[JVM] 类的加载二:类加载应用示例分析

示例一

代码清单

如下所示代码和对应的输出结果

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

结果分析

我们结合类的加载、链接、初始化和使用四个阶段对这段程序进行分析。

  1. 首先,MyTest6这个类是启动类,JVM会调用该类的main方法,即会主动使用该类,MyTest6经历加载、链接和初始化。
  2. 执行main方法过程中发现需要调用类Singleton的静态方法getInstance,是对Singleton类的主动使用,因此JVM首先会将Singleton对应的class文件加载到内存中来。
  3. 接着执行链接过程,在链接过程中先根据JVM规范对Singleton的class文件进行校验。然后按照定义的顺序为Singleton类中的静态变量赋予默认的值,即为Singleton.counter1赋默认值0,为Singleton.counter2赋默认值0,为Singleton.singleton赋默认值null。链接的最后一步将Singleton类中的符号引用转换为直接引用。
  4. 紧接着按照Singleton中静态变量和静态代码块的定义顺序执行初始化过程,在这里Singleton.counter1还是默认值0,Singleton.counter2被初始化为1,然后执行Singleton的构造方法构造Singleton对象,在构造方法中对counter1counter2执行++操作,然后用生成的Singleton对象来初始化singleton静态变量。
  5. 接下来就可以正常使用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

结果分析

  1. MyTest6的加载、链接和初始化过程同示例一。
  2. Singleton类的加载过程同示例一。
  3. Singleton的链接过程同示例一。只不过static成员的赋默认值的顺序稍有不同,示例一中先给counter2赋默认值0,再给singleton赋默认值null,示例二中先给singleton赋默认值null,再给counter2赋默认值0,结果都一样,只不过按照static成员的定义顺序赋默认值。
  4. Singleton的初始化过程同样按照static成员的定义顺序进行初始化。counter1保持默认值0,接着执行Singleton的构造方法构造Singleton对象,构造方法执行之前counter1counter2的值都为默认值0,执行完构造方法后counter1couner2的值都变为1,对象构造完后将singleton初始化为构造好的Singleton对象,最后执行counter2的初始化过程,将counter2的值重新赋值为0。

猜你喜欢

转载自blog.csdn.net/zkp_java/article/details/80035155