静态初始化、main 和 premain 的执行顺序

Static initialization, main and premain order of execution

假设我有以下项目结构:

Inst.java

import java.lang.instrument.Instrumentation;

final public class Inst {
    private static Instrumentation instrumentation;

    public static void premain(String args, Instrumentation inst) {
        instrumentation = inst;
    }

    public static long sizeof(Object o) {
        return instrumentation.getObjectSize(o);
    }
}

Constants.java

public class Constants {
    public static final int MAX_LENGTH = 10;
}

SomeClass.java

public class SomeClass {
    private int myVar;

    public SomeClass(final int myVar) {
        this.myVar = myVar;
    }

    public static class StaticClass {
        private static final int SOME_VAR = 1;
    }
}

Main.java

public class Main {
    public static void main(String [] args) {
        int init = Constants.MAX_LENGTH;
        SomeClass clazz = new SomeClass(init);           
    }
}

Oracle 文档声明如下:

After the Java Virtual Machine (JVM) has initialized, each premain method will be called in the order the agents were specified, then the real application main method will be called.

在我看来,这意味着 premain 方法在 JVM 初始化后 立即被调用 ,因此 Inst 首先被初始化(在这个例子)。

此外,static 在 class 加载时初始化(据我所知),或者更一般地在第一次引用 class.

时初始化

所以这意味着,在这个例子中,初始化和执行顺序如下:

  1. premain()在JVM初始化后调用
  2. main() 被称为应用程序的入口点
  3. Constants.MAX_LENGTH已初始化(在main中引用)
  4. StaticClass 已初始化(由于正在创建外部 class 的实例)
  5. 已创建 SomeClass 的实例

我上面的顺序正确吗?

如您所述,加载 class 后会立即调用静态初始值设定项。但是 classes 是在需要这些之前加载的。因此,在调用 main() 之前,会加载 Constants 并加载 SomeClass

如果您的代理 Inst 需要 Constants,那么 Constants 应该在 Main 之前加载。

有趣的是,如果你在依赖项中有一个循环,那么当它被检测到时循环就会被打破,结果将取决于class加载顺序。

编辑: 您可以将上面的代码放在文件中,然后 运行 它与 java -verbose:class Main 一起,您会看到很多 classes 被加载,包括您的 classes 被加载的顺序:

C:\temp\java>\opt\jdk-11\bin\java.exe -verbose:class Main
[0.009s][info][class,load] opened: C:\opt\jdk-11\lib\modules
.
.
.
[0.326s][info][class,load] Main source: file:/C:/temp/java/
[0.326s][info][class,load] java.lang.NamedPackage source: jrt:/java.base
[0.327s][info][class,load] java.lang.PublicMethods$MethodList source: jrt:/java.base
[0.327s][info][class,load] java.lang.PublicMethods$Key source: jrt:/java.base
[0.328s][info][class,load] java.lang.Void source: jrt:/java.base
[0.329s][info][class,load] Constants source: file:/C:/temp/java/
[0.330s][info][class,load] SomeClass source: file:/C:/temp/java/
[0.331s][info][class,load] jdk.internal.misc.TerminatingThreadLocal source: jrt:/java.base
[0.331s][info][class,load] java.lang.Shutdown source: jrt:/java.base
[0.332s][info][class,load] java.lang.Shutdown$Lock source: jrt:/java.base