先看一个网上的例子:
public class SingleTon {
private static SingleTon singleTon = new SingleTon();
public static int count1;
public static int count2 = 0;
private SingleTon() {
count1++;
count2++;
}
public static void main(String[] args) {
System.out.println(count1);
System.out.println(count2);
}
}
打印:
1
0
没有疑问,就不必往下看了,估计你已经懂了。可能很多人大意之下会认为都是1,我就是其中之一。
我们简单回顾下没有继承基类的简单类的初始化过程:
类被加载->分配内存空间->静态初始化->实例初始化
其中静态初始化和实例初始化是有序自上而下的,看到这里应该已经明白了吧。
我们还是简单说明白,类加载的时候基本类型count1和count2都被自动的初始化为0,然后执行自上而下执行静态初始化,静态初始化new SingleTon()最先执行,2个值都变为了1,然而count2又被重新赋值了,重新变为了0。
我们来看下javap编译后的汇编看看:
Constant pool://常量池
。。。省略。。。
#18 = Fieldref #1.#19 // reusing/SingleTon.count2:I
。。。省略。。。
Code:
stack=2, locals=0, args_size=0
0: new #1 // class reusing/SingleTon
3: dup
4: invokespecial #13 // Method "<init>":()V //实例化在前
7: putstatic #16 // Field singleTon:Lreusing/SingleTon;
10: iconst_0 //常量0入栈
11: putstatic #18 // Field count2:I //为静态域赋值
14: return
}
和我们分析得出的结果一模一样。
如果是实例域,有将如何初始化,我们看代码:
public class SingleTon {
public int count1;
public int count2 = 0;
public SingleTon() {
}
}
进行javap看看:
public class polymorphism.SingleTon {
public int count1;
public int count2;
public polymorphism.SingleTon();
Code:
0: aload_0
1: invokespecial #11 // Method java/lang/Object."<init>":()V
4: aload_0
5: iconst_0
6: putfield #13 // Field count2:I //实例域count2,说明实例域和构造器共同完成实例初始化
9: return
}
通过上面的分析,我们知道,实例域初始化是类实例化的一部分,那么完整的类实例化顺序应该如下: