阅读this question的答案时,我想知道 Java7 bootstrap 如何在不运行静态初始化器的情况下知道 public static void main(String[] args)
方法的存在?我对这个主题有一些假设,但其中一些显然是错误的:
- Java Bootstrap 在 JVM 中运行,因此它只能使用标准 JVM 功能(无 native 功能) - 例如,被调用的类必须位于 CLASSPATH 上
- 标准 JVM 类加载是通过正常的类加载机制完成的(我知道它有几个步骤,我已经使用过类加载器好几次了)
- 类解析(链接)后,立即运行类初始化(包括初始化静态属性和运行静态初始化器)
- 无法将前两个步骤分开
我的问题是:
- 谁在什么阶段调用类初始值设定项? (之前发生了什么,之后发生了什么?)
- 为什么 Bootstrap 的行为与“正常”类加载不同?除此之外还有更多差异吗?
- 额外问题:我的哪些假设是错误的?
总结所提到的问题:如果您运行 Java 主类(从 Java7 命令行),它将检查 main()
方法是否存在,而不运行静态初始化程序。在 Java6 中,它的行为有所不同。
最佳答案
可以在不链接的情况下加载类:Java 8 中的启动器通过调用 loadClass 加载主类。类加载器上的方法,它不会链接该类或运行其任何静态方法。
参见http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/sun/launcher/LauncherHelper.java#l495和 java.c#l1221 用于在 Java 8 中加载主类的代码。
Java 6 启动器使用 FindClass JNI 方法加载主类:我猜测这就是行为差异的原因。参见jdk6/jdk6/jdk/file/814bf0775b52/src/share/bin/java.c#l1387
FindClass 会初始化类,至少在 Java 6 上:jdk6/jdk6/hotspot/file/91e5cc5d33b9/src/share/vm/prims/jni.cpp 中的实现
结果 = find_class_from_class_loader(env, sym, true, loader,
Protection_domain,true,线程);
调用,在 jdk6/jdk6/hotspot/file/91e5cc5d33b9/src/share/vm/prims/jvm_misc.hpp 中,
jclass find_class_from_class_loader(JNIEnv* env, Symbol* name, jboolean init, Handle loader, Handle Protection_domain, jboolean throwError, TRAPS);
将 init 设置为 true
关于Java7 Bootstrap : Checking class without loading?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17890723/