静态初始化、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.
时初始化
所以这意味着,在这个例子中,初始化和执行顺序如下:
premain()
在JVM初始化后调用
main()
被称为应用程序的入口点
Constants.MAX_LENGTH
已初始化(在main中引用)
StaticClass
已初始化(由于正在创建外部 class 的实例)
- 已创建
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
假设我有以下项目结构:
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.
所以这意味着,在这个例子中,初始化和执行顺序如下:
premain()
在JVM初始化后调用main()
被称为应用程序的入口点Constants.MAX_LENGTH
已初始化(在main中引用)StaticClass
已初始化(由于正在创建外部 class 的实例)- 已创建
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