先看一个例子:
public class Test {
public static Test test=new Test("static test");
public static int a=5;
public int b=2;
{
System.out.println("非静态初始化块,此时a的值是:"+a+",b的值是:"+b);
}
public Test(String str){
System.out.println("from "+str);
System.out.println("a:"+a+" "+"b:"+b);
a++;
b++;
System.out.println("in the constructor,此时a的值是:"+a+",b的值是:"+b);
}
public static void main(String[] args) {
Test test=new Test("instance test");
}
}
执行结果是:
非静态初始化块,此时a的值是:0,b的值是:2
from static test
a:0 b:2
in the constructor,此时a的值是:1,b的值是:3
非静态初始化块,此时a的值是:5,b的值是:2
from instance test
a:5 b:2
in the constructor,此时a的值是:6,b的值是:3
初次使用一个类创建对象时,JVM实际上做了三歩工作:加载、链接、初始化。在程序中能看到的是第二步“链接”中的“准备阶段”和第三步“初始化”。
首先只对静态成员变量a进行分析。在准备阶段会将静态成员变量的值设为默认,也就是test=null,a=0。
然后,在初始化阶段对静态成员变量赋初值。首先是test=new Test("static test")。从执行结果可以看出此时a==0,这正是准备阶段所赋的默认值。之后a++,即a==1。再初始化a:a有初始值5,此时a==5(如果a没有初始值,那么a不会被强制赋值,也就是保持a==1)。之后a++,此时a==2。
最后,执行test=new Test("instance test")时,由结果可知,此时a==5,a++,a==6。最后输出a为6。
关于非静态成员变量b,在这里只说一下b在整个执行过程中的变化,因为在某些地方我也没有弄的很透彻。初始化从test开始,这里new了一个对象,此时在构造器执行之前执行了非静态代码块,此时a==0而b已经直接初始化为2。在构造器内部b++,输出结果可知b==3。到此,Test的初始化过程结束。
初始化顺序:
父类的静态代码——>子类的静态代码——>父类的非静态代码——>父类构造函数——>子类非静态代码——>子类构造函数