首先看下面的一段代码:
//Java源码:
public class Singleton {
private static Singleton sgt = new Singleton();
public static int instance1;
public static int instance2 = 2;
private Singleton()
{
instance1++;
instance2++;
}
public static Singleton getInstance()
{
return sgt;
}
public static void main(String[] args) {
Singleton.getInstance();
System.out.println("sgt.instance1="+instance1);
System.out.println("sgt.instance2="+instance2);
}
}
//end Singleton
输出结果为:sgt.instance1=1
sgt.instance1=2
背景知识:类加载分为三个过程:装载、链接、初始化。
1) 装载的过程就是将class文件读入内存的过程,并且提取其中的类关键信息,比如:方法、变量等等。
2) 而在链接中存在三个步骤:
a、进行字节码的检查,看是否符合class文件规范;
b、对类中的类变量进行分配空间,附初始值(系统默认),此处专指基本类型。
c、对类中的引用变量进行分配空间。
3) 随后才进行初始化,现在的初始化才是真正的,将按照语句一句一句执行。
也就是说,在初始化执行以前所有的类变量以及引用变量都是分配了存储空间的,只是他们的数值是不可信任的,也就是系统默认的数据。
好了,现在针对以上代码分析:
1)类变量的分配内存(声明)顺序:instance1,instance2,sgt ,系统赋予它们默认值,分别为0,0,null。
2)初始化:按它们声明的顺序进行初始化,即先初始化sgt ,new操作后使instance1和instance2分别为1,3;然后再初始化instance1和instance2,instance1没有指定值所以不执行保留值1,而instance2将被赋值为2,故最终结果输出为1,2。
若将语句private static Singleton sgt = new Singleton(); 置于public static int instance2 = 2;语句后,则sgt比instance1和instance2后初始化,最终结果则为1,3。
现在我们再修改一下源代码, 将instance1和instance2修改为实例变量(去掉各自的static),则结果又将如何呢?
结果为1,3。可能大多数人都能说出这个结果,但是我估计很少人能说清楚这个结果是怎么来的,我个人理解为(仅供参考):因为实例变量在类加载的时候只会被声明并不会被初始化,在类被实例化之前他们是透明的。当创建的对象使用它们时,他们才会被初始化,所以很多人想当然得出那样的“正确”结果,可是并没有真正明白其中的机制。