写出上面程序的输出结果
class SingleTon {
private static SingleTon singleTon = new SingleTon(); //A
public static int count1; //B
public static int count2 = 0; //C
static {
System.out.println("static code");
}
private SingleTon() {
System.out.println("SingleTon init");
System.out.println("singleTon==null" + (singleTon == null));
count1++;
count2++;
System.out.println("SingleTon init count1=" + count1);
System.out.println("SingleTon init count2=" + count2);
}
public static SingleTon getInstance() {
System.out.println("getInstance singleTon==null" + (singleTon == null));
return singleTon;
}
}
public class Test {
static {
System.out.println("TEST init");
}
public static void main(String[] args) {
SingleTon singleTon = SingleTon.getInstance();
System.out.println(singleTon.count1);
System.out.println(singleTon.count2);
}
}
大家可以大胆假设
然后放到 ide 中执行一下看看是否跟你想的一样.
从第几条开始跟你想的不一样了呢.
TEST init (1)
SingleTon init (2)
singleTon==null true (3)
SingleTon init count1=1 (4)
SingleTon init count2=1 (5)
static code (6)
getInstance singleTon==nullfalse (7)
1 (8)
0 (9)
解释一下
1. 这个跟类的初始化有关,在调用类的静态方法,静态变量的时候(final 修饰的静态常量除外)会触发类的初始化.SingleTon.getInstance(); 是调用了静态方法,会触发类的初始化.
2. 静态代码块是在类初始化后执行的,main 方法所在的类内的静态代码块又是最先执行的
3. 在类初始化之前有一个准备阶段,按照成员变量的顺序,进行顺序赋予默认值.对象类型的变量会先付成 null,然后在初始化的时候才在堆上 new 一个对象的内存空间.静态变量也是这样,先初始化成 0,然后在初始化阶段对给定的值付给变量.
4. 也就是初始化之前的准备阶段,singleTon =null ,count1=0,count2=0,然后执行类初始化.这个时候先执行 singleTon=new SingleTon(); 这个时候会执行构造方法,在执行过程中,虽然为 singleTon 开辟了内存空间,但是还有赋值给 singleTon,所以这个时候 singleTon==null;然后执行 count1++,count2++
这个时候,count1,count2 都是 1.此时 singleTon 赋值结束.
5. 然后顺序执行,count1 不需要处理,count2 需要赋值成 0.
6. 目前为止,类初始化执行完成.这个时候 singleTon.count1 肯定是 1,singleTon.count2 的结果是 0.
思考一下?把 C 行的代码和 A 行的代码换下位置,会发生什么,输出结果有什么变化.
来源: http://www.jianshu.com/p/8713d449bfcf