请给出下面代码的输出:
public class Test1 {
/**
* @param args
*/
public static int k=0;
public static Test1 t1=new Test1("t1");
public static Test1 t2=new Test1("t2");
public static int i=print("i");
public static int n=99;
public int j=print("j");
{
print("构造块");
}
static {
print("静态块");
}
public Test1(String str) {
System.out.println((++k)+":"+str+"\t i="+i+"\t n="+n);
++i;++n;
}
public static int print(String str) {
System.out.println((++k)+":"+str+"\t i="+i+"\t n="+n);
++n;
return ++i;
}
public static void main(String[] args) {
Test1 t=new Test1("init");
}
}
初看时,感觉略显棘手,主要卡在
public static Test1 t1=new Test1("t1");
public static Test1 t2=new Test1("t2");
调用main方法,首先会加载Test1类。类加载过程分为:加载、连接、初始化三部分,其中连接又分为:验证、准备、解析。关于虚拟机类加载机制 Java虚拟机会在准备阶段为类Field赋默认初始值,在初始化阶段才会执行初始化语句和静态初始化块。因此在初始化阶段开始之前,各类Field值为:
public static int k=0;
public static Test1 t1=null;
public static Test1 t2=null;
public static int i=0;
public static int n=0;
问题是,在类初始化阶段,执行到
public static Test1 t1=new Test1("t1");
怎么办?当时搞不懂的地方是:实例化对象之前,如果类还没加载完怎么办?运行的结果是:如果在类加载过程中遇到实例化对象的语句,则去实例化对象。(至于原理,还待解,期待高手的解答!)即在执行这条语句的时候会转而去执行类Test1的构造器,在执行构造器时发现还有一个实例Field j 和一个普通初始化没有初始化,于是再转而去初始化实例Field j和普通初始化块。j的初始化由print("j")的返回值来完成,因此此时将输出:
1:j i=0 n=0
在执行完实例Field j的初始化工作之后,接着要执行普通初始化块
{
print("构造块");
}
的初始化,此时输出:
2:构造块 i=1 n=1
同时 k=2, n=2, i=2;
执行完实例Field和普通初始化块之后就可以开始执行构造器了,此时输出:
3:t1 i=2 n=2
同时 k=3, n=3, i=3;
到此为止,Test1的实例 t1的创建完成。类似的,t2的创建如t1。依次输出:
4:j i=3 n=3
5:构造块 i=4 n=4
6:t2 i=5 n=5
接着初始化类Field i,执行print("i");此时输出:
7:i i=6 n=6
此时,k=7, n=7, i=7;
然后将n初始化为99。
此时所有的类Field都已初始化完毕。最后执行静态初始化块
static {
print("静态块");
}
此时输出:
8:静态块 i=7 n=99
最后执行main方法中Test1的实例 t 的创建,此过程与t1、t2类似。输出:
9:j i=8 n=100
10:构造块 i=9 n=101
11:init i=10 n=102
因此,程序最终输出结果:
2:构造块 i=1 n=1
3:t1 i=2 n=2
4:j i=3 n=3
5:构造块 i=4 n=4
6:t2 i=5 n=5
7:i i=6 n=6
8:静态块 i=7 n=99
9:j i=8 n=100
10:构造块 i=9 n=101
11:init i=10 n=102