精华内容
下载资源
问答
  • 本篇文章主要介绍了Spring 中如何控制2个bean中的初始化顺序,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • Java类初始化顺序

    2020-12-22 23:54:19
    所有代码块是从上往下顺序执行的,所以代码块里面使用到的变量如果在块下面初始化会有问题 执行构造方法中内容。 所以看见的空构造方法,只能说第三部没有需要执行的内容。 下面举例子 public class TestClass { ...
  • 在Java中,类装载器把一个类装入Java虚拟机中,要经过三个步骤来完成:装载、链接和初始化,网上关于Java中对象初始化顺序的文章很多,这篇文章我们将详细介绍Java中对象初始化顺序。有需要的可以参考学习。
  • 详细介绍了Java的静态成员变量、静态数据块、非静态成员变量和非静态成员变量等初始化顺序
  • JAVA面试题解惑系列(一)——类的初始化顺序-JAVA程序员JAVA工程师面试必看
  • 类继承的初始化顺序类继承的初始化顺序类继承的初始化顺序类继承的初始化顺序
  • Kotlin实例初始化时,构造函数、成员变量、init块等的初始化顺序必须弄清楚,否则容易出bug: Example: open class Parent { private val a = println("Parent.a") constructor(arg: Unit=println("Parent ...

    Kotlin实例初始化时,构造函数、成员变量、init块等的初始化顺序必须弄清楚,否则容易出bug:

    Example:


    open class Parent {
        private val a = println("Parent.a")
    
        constructor(arg: Unit=println("Parent primary constructor default argument")) {
            println("Parent primary constructor")
        }
    
        init {
            println("Parent.init")
        }
    
        private val b = println("Parent.b")
    }
    
    class Child : Parent {
        val a = println("Child.a")
    
        init {
            println("Child.init 1")
        }
    
        constructor(arg: Unit=println("Child primary constructor default argument")) : super() {
            println("Child primary constructor")
        }
    
        val b = println("Child.b")
    
        constructor(arg: Int, arg2:Unit= println("Child secondary constructor default argument")): this() {
            println("Child secondary constructor")
        }
    
        init {
            println("Child.init 2")
        }
    }
    

    Output:


    Child primary constructor default argument
    Parent primary constructor default argument
    Parent.a
    Parent.init
    Parent.b
    Parent primary constructor
    Child.a
    Child.init 1
    Child.b
    Child.init 2
    Child primary constructor
    

    Conclusion:


    1. 按照父类->子类的顺序执行初始化(同Java)
    2. 构造函数在成员变量初始化之后执行(同Java)
    3. init与成员变量初始化按照代码位置顺序执行 (重点!)

    因此,下面的代码会出现NPE

     class Foo {
            init {
                initList()
            }
            
            val list : MutableList<String> = mutableListOf()
            
            fun initList() {
                list.clear()
            }
        }
    
    展开全文
  • 本篇文章是对java父类和子类初始化顺序进行了详细的分析介绍,需要的朋友参考下
  • 这里直接给出C#类成员一般初始化顺序: 子类静态字段 子类静态构造 子类实例字段 父类静态字段 父类静态构造 父类实例字段 父类实例构造 子类实例构造 为什么说是“一般”初始化顺序呢?因为根据类结构的...
  • JAVA类初始化顺序总结

    万次阅读 多人点赞 2018-09-27 23:16:24
    初始化顺序 首先来看下,当一个类从main入口方法,对于静态变量、静态初始化块、变量、初始化块、构造器,它们的初始化顺序: public class ClassLoadTest { private static User user = new User(); static { ...

    类的初始化

    初始化顺序

    首先来看下,当一个类从main入口方法,对于静态变量、静态初始化块、变量、初始化块、构造器,它们的初始化顺序:

    public class ClassLoadTest {
        private static User user = new User();
        static {
            System.err.println("static code block");
        }
    
    
        {
            System.err.println("code block");
        }
        private Student student = new Student();
        public ClassLoadTest(){
            System.err.println("Constructor");
        }
        public static void main(String[] args) {
            System.err.println("mian ==>");
            new ClassLoadTest();
        }
    }
    
    class Student{
        public Student(){
            System.err.println("student initint===>");
        }
    }
    
    class User {
        public User() {
            System.err.println("user initing===>");
        }
    }
    

    结论:

    正常类的加载顺序:静态变量/静态代码块 -> main方法 -> 非静态变量/代码块 -> 构造方法

    说明:静态代码块与静态变量的执行顺序同代码定义的顺序;非静态变量与代码块的执行顺序同代码执行顺序

    继承的情况

    class Parent {
    	/* 静态变量 */
    	public static String p_StaticField = "父类--静态变量";
    	/* 变量 */
    	public String p_Field = "父类--变量";
    	protected int i = 9;
    	protected int j = 0;
    	/* 静态初始化块 */
    	static {
    		System.out.println( p_StaticField );
    		System.out.println( "父类--静态初始化块" );
    	}
    	/* 初始化块 */
    	{
    		System.out.println( p_Field );
    		System.out.println( "父类--初始化块" );
    	}
    	/* 构造器 */
    	public Parent()
    	{
    		System.out.println( "父类--构造器" );
    		System.out.println( "i=" + i + ", j=" + j );
    		j = 20;
    	}
    }
    
    public class SubClass extends Parent {
    	/* 静态变量 */
    	public static String s_StaticField = "子类--静态变量";
    	/* 变量 */
    	public String s_Field = "子类--变量";
    	/* 静态初始化块 */
    	static {
    		System.out.println( s_StaticField );
    		System.out.println( "子类--静态初始化块" );
    	}
    	/* 初始化块 */
    	{
    		System.out.println( s_Field );
    		System.out.println( "子类--初始化块" );
    	}
    	/* 构造器 */
    	public SubClass()
    	{
    		System.out.println( "子类--构造器" );
    		System.out.println( "i=" + i + ",j=" + j );
    	}
    
    
    	/* 程序入口 */
    	public static void main( String[] args )
    	{
    		System.out.println( "子类main方法" );
    		new SubClass();
    	}
    }
    

    初始化顺序:

    父类–静态变量/父类–静态初始化块
    子类–静态变量/子类–静态初始化块
    父类–变量/父类–初始化块
    父类–构造器
    子类–变量/子类–初始化块
    子类–构造器

    结论:

    • 子类的静态变量和静态初始化块的初始化是在父类的变量、初始化块和构造器初始化之前就完成了;
    • 静态变量、静态初始化块顺序取决于它们在类中出现的先后顺序
    • 变量、初始化块初始化顺序取决于它们在类中出现的先后顺序

    分析

    • (1)访问SubClass.main()(这是一个static方法),于是装载器就会为你寻找已经编译的SubClass类的代码(也就是SubClass.class文件)。在装载的过程中,装载器注意到它有一个基类,于是再装载基类。不管你创不创建基类对象,这个过程总会发生。如果基类还有基类,那么第二个基类也会被装载,依此类推;

    • (2)执行基类的static初始化,然后是下一个派生类的static初始化,依此类推。这个顺序非常重要,因为派生类的“static初始化”有可能要依赖基类成员的正确初始化;

    • (3)当所有必要的类都已经装载结束,开始执行main()方法体,并用new SubClass()创建对象;

    • (4)类SubClass存在父类,则调用父类的构造函数,你可以使用super来指定调用哪个构造函数。基类的构造过程以及构造顺序,同派生类的相同。首先基类中各个变量按照字面顺序进行初始化,然后执行基类的构造函数的其余部分;

    • (5)对子类成员数据按照它们声明的顺序初始化,执行子类构造函数的其余部分;

    static变量

    public class Test {
    
    	static {
    		i = 0; // 给变量复制可以正常编译通过
    		// System.out.print(i); // 这句编译器会提示“非法向前引用”
    	}
    	static int i = 1;
    	
    	static int j = 1;
    	
    	static{
    		j = 2;
    	}
    
    	public static void main(String[] args){
    		System.out.println(Test.i); //1
    		System.out.println(Test.j); //2
    	}
    }
    

    不触发初始化实例

    /**
    * 被动使用类字段演示一:
    * 通过子类引用父类的静态字段,不会导致子类初始化
    **/
    class SuperClass {
    
    	static {
    		System.out.println("SuperClass init!");
    	}
    	
    	public static int value = 123;
    	}
    
    class SubClass extends SuperClass {
    
    	static {
    		System.out.println("SubClass init!");
    	}
    }
    
    /**
    * 非主动使用类字段演示
    **/
    public class NotInitialization {
    
    	public static void main(String[] args) {
    		// System.out.println(SubClass.value);
    		//SuperClass init!
    		//123
    	
    		/**
    		* 被动使用类字段演示二:
    		* 通过数组定义来引用类,不会触发此类的初始化
    		**/
    		SuperClass[] sca = new SuperClass[10];
    	}
    }
    

    被动使用类字段

    /**
    * 被动使用类字段演示三:
    *
    * 常量在编译阶段会存入调用类的常量池中,本质上没有直接引用到定义常量的类,
    * 因此不会触发定义常量的类的初始化。
    
    **/
    public class ConstClass {
    
    	static {
    		System.out.println("ConstClass init!");
    	}
    	
    	public static final String HELLOWORLD = "hello world";
    }
    
    public class Test {
    	public static void main(String[] args){
    		System.out.println(ConstClass.HELLOWORLD);
    	}
    }
    

    输出

    hello world
    

    这里没有初始化ConstClass类,是因为在编译的时候,常量(static final 修饰的)会存入调用类的常量池【这里说的是main函数所在的类的常量池】,调用的时候本质上没有引用到定义常量的类,而是直接访问了自己的常量池

    静态方法调用

    当调用目标类的静态变量或静态方法时,不会触发该类的代码块或构造方法的执行,示例如下:

    public class ClassLoadTest {
    	public static void main(String[] args) {
    		// System.err.println(Handler.user);
    		Handler.print();
    	}
    }
    
    class Handler {
    	public static User user = new User();
    	static {
    		System.err.println("static code block");
    	}
    	{
    		System.err.println("code block");
    	}
    	public Handler(){
    		System.err.println("Constructor");
    	}
    	public static void print(){
    		System.err.println("static method");
    	}
    }
    
    class User {
    	public User() {
    		System.err.println("user initing===>");
    	}
    }
    

    参考 {#articleHeader13}

    java类的初始化顺序–http://blog.sina.com.cn/s/blog_4cc16fc50100bjjp.html

    Java类加载的时机 ——https://blog.csdn.net/imzoer/article/details/8038249

    展开全文
  • Java类继承初始化顺序

    2016-09-02 12:27:26
    具体内容见博客
  • 彻底搞懂java程序的初始化顺序

    千次阅读 2019-08-09 08:00:00
    使用场景 在java程序中,当实例化对象时,对象的所在类的所有成员变量首先要进行初始化,只有当所有类成员完成初始化后,才会调用对象所在类的构造函数创建对象。 原则 ...初始化顺序 父类...

     

    使用场景

    在java程序中,当实例化对象时,对象的所在类的所有成员变量首先要进行初始化,只有当所有类成员完成初始化后,才会调用对象所在类的构造函数创建对象。

    原则

    1. 变量优先于块、静态优先于非静态。

    2. 父类优先于派生类初始化。

    3. 按照成员变量定义的顺序来进行初始化,即使变量定义散布于方法定义之中,它们仍然在任何方法(包括构造器)被调用前初始化。

    初始化顺序

    父类静态变量
    父类静态代码块
    子类静态变量
    子类静态代码块
    父类非静态变量
    父类非静态代码块
    父类构造函数
    子类非静态变量
    子类非静态代码块
    子类构造函数

    初始化示例代码

     
    class Base {	
    	
        public Base() {	
            System.out.println("父类构造方法");	
        }	
    	
        String b = "父类非静态变量";	
        {	
            System.out.println(b);	
            System.out.println("父类非静态代码块");	
        }	
    	
        static String a = "父类静态变量";	
    	
        static {	
            System.out.println(a);	
            System.out.println("父类静态代码块");	
        }	
    	
        public static void A() {	
            System.out.println("父类普通静态方法");	
        }	
    	
    }	
    	
    class Derived extends Base {	
    	
        public Derived() {	
            System.out.println("子类构造器");	
        }	
    	
        String b = "子类非静态变量";	
        {	
            System.out.println(b);	
            System.out.println("子类非静态代码块");	
        }	
    	
        static String a = "子类静态变量";	
    	
        static {	
            System.out.println(a);	
            System.out.println("子类静态块");	
        }	
    	
        public static void A() {	
            System.out.println("子类普通静态方法");	
        }	
    	
        public static void main(String[] args) {	
            Base.A();	
            Derived.A();	
            new Derived();	
        }	
    }

    分别执行主函数里的三条指令,执行结果如下。

    Base.A()

    父类静态变量
    父类静态代码块
    子类静态变量
    子类静态块
    父类普通静态方法

    Derived.A()

    父类静态变量
    父类静态代码块
    子类静态变量
    子类静态块
    子类普通静态方法

    new Derived()

    父类静态变量
    父类静态代码块
    子类静态变量
    子类静态代码块
    父类非静态变量
    父类非静态代码块
    父类构造函数
    子类非静态变量
    子类非静态代码块
    子类构造函数

    更多内容,欢迎关注微信公众号:全菜工程师小辉~

    640?wx_fmt=png

     

     

    展开全文
  • Spring bean 初始化顺序

    千次阅读 2019-05-06 10:58:13
    从接口的名字上不难发现,InitializingBean 的作用就是在 bean 初始化后执行定制化的操作。 Spring 容器中的 Bean 是有生命周期的,Spring 允许在 Bean 在初始化完成后以及 Bean 销毁前执行特定的操作,常用的设定...

    InitializingBean, init-method 和 PostConstruct

    1、概述

    从接口的名字上不难发现,InitializingBean 的作用就是在 bean 初始化后执行定制化的操作。

    Spring 容器中的 Bean 是有生命周期的,Spring 允许在 Bean 在初始化完成后以及 Bean 销毁前执行特定的操作,常用的设定方式有以下三种:

    1. 通过实现 InitializingBean/DisposableBean 接口来定制初始化之后/销毁之前的操作方法;
    2. 通过 <bean> 元素的 init-method/destroy-method 属性指定初始化之后 /销毁之前调用的操作方法;
    3. 在指定方法上加上@PostConstruct 或@PreDestroy注解来制定该方法是在初始化之后还是销毁之前调用。

    2、InitializingBean vs init-method

    接口定义如下:

    public interface InitializingBean {
        void afterPropertiesSet() throws Exception;
    }
    

    接口只有一个方法afterPropertiesSet,
    此方法的调用入口是负责加载 spring bean 的AbstractAutowireCapableBeanFactory,源码如下:

    protected void invokeInitMethods(String beanName, Object bean,
    			RootBeanDefinition mbd) throws Throwable {
    		boolean isInitializingBean = bean instanceof InitializingBean;
    		if ((isInitializingBean)
    				&& (((mbd == null) || (!(mbd
    						.isExternallyManagedInitMethod("afterPropertiesSet")))))) {
    			if (this.logger.isDebugEnabled()) {
    				this.logger
    						.debug("Invoking afterPropertiesSet() on bean with name '"
    								+ beanName + "'");
    			}
    			//先调用afterPropertiesSet()进行初始化
    			if (System.getSecurityManager() != null) {
    				try {
    					AccessController.doPrivileged(
    							new PrivilegedExceptionAction(bean) {
    								public Object run() throws Exception {
    									((InitializingBean) this.val$bean)
    											.afterPropertiesSet();
    									return null;
    								}
    							}, getAccessControlContext());
    				} catch (PrivilegedActionException pae) {
    					throw pae.getException();
    				}
    			} else {
    				((InitializingBean) bean).afterPropertiesSet();
    			}
    		}
    		
    		//然后调用InitMethod()进行初始化
    		if (mbd != null) {
    			String initMethodName = mbd.getInitMethodName();
    			if ((initMethodName == null)
    					|| ((isInitializingBean) && ("afterPropertiesSet"
    							.equals(initMethodName)))
    					|| (mbd.isExternallyManagedInitMethod(initMethodName)))
    				return;
    			invokeCustomInitMethod(beanName, bean, mbd);
    		}
    	}
    

    从这段源码可以得出以下结论:

    1. spring为bean提供了两种初始化bean的方式,实现InitializingBean接口,实现afterPropertiesSet方法,或者在配置文件中通过init-method指定,两种方式可以同时使用
    2. 实现InitializingBean接口是直接调用afterPropertiesSet方法,比通过反射调用init-method指定的方法效率相对来说要高点。但是init-method方式消除了对spring的依赖
    3. 先调用afterPropertiesSet,再执行 init-method 方法,如果调用afterPropertiesSet方法时出错,则不调用init-method指定的方法

    3、@PostConstruct

    通过 debug 和调用栈找到类InitDestroyAnnotationBeanPostProcessor, 其中的核心方法,即 @PostConstruct 方法调用的入口:

        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
            try {
                metadata.invokeInitMethods(bean, beanName);
            }
            catch (InvocationTargetException ex) {
                throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException());
            }
            catch (Throwable ex) {
                throw new BeanCreationException(beanName, "Failed to invoke init method", ex);
            }
            return bean;
        }
    

    从命名上,我们就可以得到某些信息——这是一个BeanPostProcessor。BeanPostProcessor的postProcessBeforeInitialization是在Bean生命周期中afterPropertiesSet和init-method之前被调用的。另外通过跟踪,@PostConstruct方法的调用方式也是通过反射机制。

    4、总结

    1. spring bean的初始化执行顺序:构造方法 --> @PostConstruct注解的方法 --> afterPropertiesSet方法 --> init-method指定的方法。具体可以参考例子
    2. afterPropertiesSet通过接口实现方式调用(效率上高一点),@PostConstruct和init-method都是通过反射机制调用

    同理,bean销毁过程的顺序为:@PreDestroy > DisposableBean > destroy-method
    不再展开,看源码就好

    测试代码如下:

    @Slf4j
    public class InitSequenceBean implements InitializingBean {
    
        public InitSequenceBean() {
            log.info("InitSequenceBean: construct");
        }
    
        @Override
        public void afterPropertiesSet() throws Exception {
            log.info("InitSequenceBean: afterPropertiesSet");
        }
    
        @PostConstruct
        public void postConstruct() {
            log.info("InitSequenceBean: postConstruct");
        }
    
        public void initMethod() {
            log.info("InitSequenceBean: initMethod");
        }
    }
    
    @Configuration
    public class SystemConfig {
    
        @Bean(initMethod = "initMethod", name = "initSequenceBean")
        public InitSequenceBean initSequenceBean() {
            return new InitSequenceBean();
        }
    }
    
    @Slf4j
    public class InitSequenceBeanTest extends ApplicationTests {
    
        @Autowired
        private InitSequenceBean initSequenceBean;
    
        @Test
        public void initSequenceBeanTest() {
            log.info("Finish: {}", initSequenceBean.toString());
        }
    }
    
    展开全文
  • Java成员变量初始化顺序

    千次阅读 2018-11-24 22:28:49
    Java中成员变量分为两类:1、类变量 2、实例变量 1、类变量初始化 ...1.2 初始化顺序 上述两种方式在程序中的排列顺序即为执行顺序 class ClassVarInit{ static int value=10; static{ value=10...
  • 类的初始化顺序详解

    千次阅读 2018-08-23 13:14:15
    前言 先声明一个常识,类域和局部变量初始化的差异如下, 局部变量不初始化会报错: 类中属性(也称域)不赋初值,默认为0,如果是引用...结论:就算类中属性散乱定义在不同地方,初始化也会严格按照先后顺序执行...
  • C++类成员初始化顺序问题

    万次阅读 多人点赞 2017-11-22 21:08:20
    说应聘C++岗位的不知道成员变量初始化顺序!大冬天的背后竟冒出了一丝冷汗,因为我也不知道,所以就上网查了一下,将学到的知识记录如下。 主要参考博客: C++类成员初始化顺序问题1 C++类成员初始化顺序问题2 ...
  • 主要介绍了c#对象初始化顺序,实例分析了C#对象初始化的相关使用技巧与调用顺序,需要的朋友可以参考下
  • java类变量初始化顺序

    2014-04-08 11:38:28
    详细讲解java类中静态变量,普通标量,对象、基本类型的初始化顺序
  • Java类的初始化顺序

    万次阅读 多人点赞 2018-07-05 10:03:23
    对于静态变量、静态初始化块、变量、初始化块、构造器,它们的初始化顺序依次是(静态变量、静态初始化块)&gt;(变量、初始化块)&gt;构造器。初始化顺序图示:我们也可以通过下面的测试代码来验证这一点:...
  • 网上有很多关于Java中class的初始化顺序文章,但是本文通过图文更加详细的介绍了Java中class的初始化顺序,并对class的装载顺序进行了讲解,下面一起来看看。
  • 本篇文章介绍了,Java对象初始化顺序的使用。需要的朋友参考下
  • 以下这段小程序对调用对象构造函数时,父类构造函数、成员变量初始化函数,以及非静态初始化块调用顺序进行验证,不考虑静态成员及静态初始化
  • 【深入理解JVM】:Java类继承关系中的初始化顺序

    万次阅读 多人点赞 2016-05-06 11:19:38
    Java类初始化的顺序经常让人犯迷糊,现在本文尝试着从JVM的角度,对Java非继承和继承关系中类的初始化顺序进行试验,尝试给出JVM角度的解释。非继承关系中的初始化顺序对于非继承关系,主类...
  • 本篇文章介绍了,Java对象初始化顺序的使用。需要的朋友参考下
  • JAVA类加载与初始化顺序

    千次阅读 2018-08-20 15:03:05
    类的生命周期 7个阶段依次为:Loading Verification Preparation Resolution Initialization Using...于是java默认的类查找加载顺序是自顶向下的,树状结构 双亲委托的意图是保证java类型体系中最基础的行为一...
  • 主要介绍了Java类继承关系中的初始化顺序,结合实例形式详细对比分析了Java非继承关系中的初始化与继承关系中的初始化相关原理与操作技巧,需要的朋友可以参考下
  • java对象初始化顺序

    千次阅读 2018-08-10 10:18:34
    Java初始化顺序 类变量(静态变量)、实例变量(非静态变量)、静态代码块、非静态代码块 的初始化时机 由 static 关键字修饰的(如:类变量[静态变量]、静态代码块)将在类被初始化创建实例对象之前被初始化,...
  • C++类成员的初始化顺序

    千次阅读 2019-08-10 14:46:48
    C++中变量的初始化顺序应该是: 1 基类的静态变量或全局变量 2 派生类的静态变量或全局变量 3 基类的成员变量 4 派生类的成员变量 注意,对于一个类中的变量,初始化的顺序并不是按照初始化成员列表的顺序进行...
  • 主要介绍了C++ 成员变量的初始化顺序问题详解的相关资料,需要的朋友可以参考下

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 907,146
精华内容 362,858
关键字:

初始化顺序