类 什么时候加载?

When classes are loaded?

嗯,我有这样一段代码:

public class Main {
    public static void main(String[] args) {
        Test t; //1
        Integer i = new Integer(1); //2
        t = new Test(); //3
        System.out.println(Test4.a); //4
    }
}

class Test {
    private int a = 10;
    private Test2 t2; //5

    List<Test2> list = new ArrayList<Test2>() {
        {
            for (int i = 0; i < a; i++) {
                add(new Test2()); //6
            }
        }
    };
}

class Test2 extends Test3{
}

class Test3 {
}

class Test4 {
    public static final int a = 4;
}

我不知道如何(全部或部分)以及何时加载 classes。所以:

  1. Test t; - 它不是一个活跃的用法,但引用 t 必须是一个明确的类型。测试 class 是否已加载(可能是部分加载,然后是多少个阶段 - loading\linking\initializing - 它通过了)还是什么都没发生?
  2. Integer i = new Integer(1); - 是在 JVM 启动时加载 Integer 还是在这一行?
  3. t = new Test(); - 一个活跃的用法。它是从一开始就完全加载还是从某个点开始加载(见 1)
  4. System.out.println(Test4.a); - Test4 是否已加载?
  5. 是否加载了 Test2Test3?如果是那么什么时候?

当 classes 被加载时被 JLS, Section 12.4.1 覆盖。

A class or interface type T will be initialized immediately before the first occurrence of any one of the following:

  • T is a class and an instance of T is created.

  • T is a class and a static method declared by T is invoked.

  • A static field declared by T is assigned.

  • A static field declared by T is used and the field is not a constant variable (§4.12.4).

  • T is a top level class (§7.6), and an assert statement (§14.10) lexically nested within T (§8.1.3) is executed.

(剪断)

A class or interface will not be initialized under any other circumstance.

Chapter 5 谈论加载、链接和初始化 classes.

The Java Virtual Machine dynamically loads, links and initializes classes and interfaces. Loading is the process of finding the binary representation of a class or interface type with a particular name and creating a class or interface from that binary representation. Linking is the process of taking a class or interface and combining it into the run-time state of the Java Virtual Machine so that it can be executed. Initialization of a class or interface consists of executing the class or interface initialization method (§2.9).

您的问题:

  1. 声明变量不会加载 class。但是加载发生在链接之前,而链接发生在初始化之前。因此,当加载 class 时,它也会被链接和初始化。
  2. 在您的代码运行之前,Integer class 由 JVM 加载(连同许多其他语言基础 classes)。
  3. 现在 Test class 已加载,因为创建了一个新实例。
  4. Test4没有加载,因为只用了一个常量变量,与上面第4条规则冲突
  5. Test3Test2是在Test加载之后加载的,因为Test2对象是在Test的实例初始化器中创建的,这也导致Test3(超class)待加载。

这在running your code with the JVM option -verbose:class时得到证实。