示例一
代码清单
如下所示代码和对应的输出结果
public class MyTest6 {
public static void main(String[] args) {
Singleton instance = Singleton.getInstance();
System.out.println("counter1: " + Singleton.counter1);
System.out.println("counter2:" + Singleton.counter2);
}
}
class Singleton{
public static int counter1;
public static int counter2 = 1;
private static Singleton singleton = new Singleton();
public Singleton() {
counter1++;
counter2++;
}
public static Singleton getInstance(){
return singleton;
}
}
输出结果:
counter1: 1
counter2:2
结果分析
我们结合类的加载、链接、初始化和使用四个阶段对这段程序进行分析。
- 首先,
MyTest6这个类是启动类,JVM会调用该类的main方法,即会主动使用该类,MyTest6经历加载、链接和初始化。 - 执行
main方法过程中发现需要调用类Singleton的静态方法getInstance,是对Singleton类的主动使用,因此JVM首先会将Singleton对应的class文件加载到内存中来。 - 接着执行链接过程,在链接过程中先根据JVM规范对
Singleton的class文件进行校验。然后按照定义的顺序为Singleton类中的静态变量赋予默认的值,即为Singleton.counter1赋默认值0,为Singleton.counter2赋默认值0,为Singleton.singleton赋默认值null。链接的最后一步将Singleton类中的符号引用转换为直接引用。 - 紧接着按照
Singleton中静态变量和静态代码块的定义顺序执行初始化过程,在这里Singleton.counter1还是默认值0,Singleton.counter2被初始化为1,然后执行Singleton的构造方法构造Singleton对象,在构造方法中对counter1和counter2执行++操作,然后用生成的Singleton对象来初始化singleton静态变量。 - 接下来就可以正常使用
Singleton类了。
示例二
代码清单
如下所示的代码和输出结果,代码只是移动了示例一种一行代码的位置,最后输出的结果就不一样了:
public class MyTest6 {
public static void main(String[] args) {
Singleton instance = Singleton.getInstance();
System.out.println("counter1: " + Singleton.counter1);
System.out.println("counter2:" + Singleton.counter2);
}
}
class Singleton{
public static int counter1;
private static Singleton singleton = new Singleton();
public Singleton() {
counter1++;
counter2++;
}
public static int counter2 = 0;
public static Singleton getInstance(){
return singleton;
}
}
输出结果:
counter1: 1
counter2:0
结果分析
MyTest6的加载、链接和初始化过程同示例一。Singleton类的加载过程同示例一。Singleton的链接过程同示例一。只不过static成员的赋默认值的顺序稍有不同,示例一中先给counter2赋默认值0,再给singleton赋默认值null,示例二中先给singleton赋默认值null,再给counter2赋默认值0,结果都一样,只不过按照static成员的定义顺序赋默认值。Singleton的初始化过程同样按照static成员的定义顺序进行初始化。counter1保持默认值0,接着执行Singleton的构造方法构造Singleton对象,构造方法执行之前counter1和counter2的值都为默认值0,执行完构造方法后counter1和couner2的值都变为1,对象构造完后将singleton初始化为构造好的Singleton对象,最后执行counter2的初始化过程,将counter2的值重新赋值为0。
本文通过两个示例详细解析了Java单例模式的实现过程,包括类加载、链接及初始化等阶段,展示了不同代码顺序对最终结果的影响。
1039

被折叠的 条评论
为什么被折叠?



