[toc]
一. why引入
因为java对象初始化问题是比较基础的java知识点,同时,也是众多面试中百问不厌的问题,所以,我们通过阿里工程师的例子和刨析来好好理解他。
二. 引发问题
会触发Java object initialization order 问题,这种问题比较少见。
三. 举例
package com.xn.web.budget;
public class Test2 extends Test {
public int a = 100;
public Test2() {
super();
System.out.println(a);
a = 200;
}
public static void main(String[] args){
System.out.println(new Test2().a);
}
}
package com.xn.web.budget;
public class Test {
public Test() {
System.out.println(((Test2)this).a);
}
}
结果输出:
0
100
200
解析对象的初始化顺序:
- 为A类分配内存空间,初始化所有成员变量为默认值,包括primitive类型(int=0,boolean=false,…)和Reference类型。
- 调用A类构造函数。
- 调用B类构造函数。
- 调用Object空构造函数。(java编译器会默认加此构造函数,且object构造函数是个空函数,所以立即返回)
- 初始化B类成员变量,因为B类没有成员变量,跳过。
- 执行sysout输出子类A的成员变量小a。// 此时为0
- 初始化A类成员变量,将A类成员变量小a赋值100。
- 执行sysout输出当前A类的成员变量小a。// 此时为100
- 赋值当前A类的成员变量小a为200。
- main函数中执行sysout,输出A类实例的成员变量小a。// 此时为200
加粗的那两行描述是重点,结论是成员变量初始化是在父类构造函数调用完后,在此之前,成员变量的值均是默认值。
其实这类问题,熟悉原理是一方面,本质上只要不在构造函数中插入过多的业务逻辑,出问题的概率也会低很多。
最后,我们再来看看JLS中给出的Java类对象初始化顺序定义,这是一个带条件分支的流程描述:
- Assign the arguments for the constructor to newly created parameter variables for this constructor invocation.
- If this constructor begins with an explicit constructor invocation of another constructor in the same class (using this), then evaluate the arguments and process that constructor invocation recursively using these same five steps. If that constructor invocation completes abruptly, then this procedure completes abruptly for the same reason; otherwise, continue with step 5.
- This constructor does not begin with an explicit constructor invocation of another constructor in the same class (using this). If this constructor is for a class other than Object, then this constructor will begin with an explicit or implicit invocation of a superclass constructor (using super). Evaluate the arguments and process that superclass constructor invocation recursively using these same five steps. If that constructor invocation completes abruptly, then this procedure completes abruptly for the same reason. Otherwise, continue with step 4.
- Execute the instance initializers and instance variable initializers for this class, assigning the values of instance variable initializers to the corresponding instance variables, in the left-to-right order in which they appear textually in the source code for the class. If execution of any of these initializers results in an exception, then no further initializers are processed and this procedure completes abruptly with that same exception. Otherwise, continue with step 5. (In some early implementations, the compiler incorrectly omitted the code to initialize a field if the field initializer expression was a constant expression whose value was equal to the default initialization value for its type.)
- Execute the rest of the body of this constructor. If that execution completes abruptly, then this procedure completes abruptly for the same reason. Otherwise, this procedure completes normally.
引用自:传送