Java 如何在Sun';什么是JVM?
默认情况下,Sun的JVM会延迟加载类并延迟初始化(即调用它们的Java 如何在Sun';什么是JVM?,java,class,classloader,static-initializer,Java,Class,Classloader,Static Initializer,默认情况下,Sun的JVM会延迟加载类并延迟初始化(即调用它们的方法)。考虑下面的类, ClinitBomb ,它在静态{}} /Cult>块中抛出异常>代码> < /p> public class ClinitBomb { static { explode(); } private static void explode() { throw new RuntimeException("boom!"); } }
方法)。考虑下面的类,<代码> ClinitBomb <代码>,它在<代码>静态{}} /Cult>块中抛出<代码>异常>代码> < /p>
public class ClinitBomb {
static {
explode();
}
private static void explode() {
throw new RuntimeException("boom!");
}
}
现在,考虑如何触发炸弹:
public class Main {
public static void main(String[] args) {
System.out.println("A");
try {
Class.forName("ClinitBomb");
} catch (Exception e) {
e.printStackTrace(System.out);
}
System.out.println("B");
ClinitBomb o2 = new ClinitBomb();
System.out.println("C");
}
}
我们保证爆炸发生在B点之前,因为forName
的文档中这样说;问题是它是否发生在Sun的JVM中的点A之前(加载Main
时),即使Main()
包含对ClinitBomb
的静态引用,它也发生在点A之后
我想要一种方法,告诉JVM在初始化Main
之后立即加载并初始化ClinitBomb
(因此炸弹会在a点之前爆炸)。一般来说,我想要一种方法说,“无论何时加载/初始化类X,也会对它引用的任何类Y这样做。”
有办法吗
Class.forName("...", true /*initialize*/, getClassLoader());
你已经走了一半了。没有办法做到这一点。JLS在(我的重点)中说: 类的初始化包括执行其静态初始值设定项和类中声明的静态字段的初始值设定项。[……] 类或接口类型T将在第一次出现以下任何一种情况之前立即初始化:
- T是一个类,并且创建了T的一个实例
- T是一个类,调用由T声明的静态方法
- 分配了一个由T声明的静态字段
- 使用T声明的静态字段,该字段不是常量变量(§4.12.4)
- T是一个顶级类,执行嵌套在T中的assert语句(§14.10)李>
尽管您可以使用JVM编写一个静态块,向每个显式初始化其引用类的类添加一个静态块(可能通过class.forName)。一旦一个类被初始化,所有可从中访问的类都将被初始化。这可能会给你你想要的结果。不过,这是相当多的工作 一个静态块指的是主站的ClinitBomb?@Thorbjørn Ravn Andersen,它不能解决一般问题。但是我想一个自定义类加载器可以在每个加载的类中注入静态块。除了添加大量的
class.forName()
之外,我不知道。OTOH,为什么它如此重要?@Bill我留下了一个项目,该项目声明静态字段初始化为每类记录器,但是获取RMI记录器需要非常繁琐的工作。当这部分代码被破坏时,让静态初始值设定项以更明显的顺序执行真的很好。我建议您将初始化移动到类中,然后在启动早期从某个地方调用它,然后稍后再引用它。您可以使用自己的急切类加载器。否。他编写的代码已经在forName
调用中初始化了ClinitBomb
;“相当于:Class.forName(className,true,currentLoader)”。他的愿望是让ClinitBomb
比那更早初始化。谢谢。(还有,bummer。在这种情况下进行调试是非常方便的。我继承了一个代码库,其中大多数类声明了一个静态最终记录器
字段,这很好,只是它们是使用一个可以访问RMI的日志基础设施创建的。因此,基本上,在执行过程中的任意点上,您突然有了远程日志记录如果失败给您一个异常初始化错误
。听起来很有趣吗?)嗯。。有趣的是,ClinitBomb的类直到forName()才被加载,这看起来很奇怪。(也就是说:删除ClinitBomb.class仍然允许主打印“A”,然后抛出NoClassDefFoundError。)根据JLS 12.1.2,它取决于实现;知道如何更改Sun JVM中的默认行为吗?我不知道。运行java-XX:+dislockDiagnosticVMOptions-XX:+PrintFlagsFinal
并查看是否有任何提示-我在我拥有的JRE中看不到任何东西。它看起来像-XX:+TraceClassResolution,除了转储正在解析的内容的日志外,还强制它立即发生。我们已经发现并修复了:)这个bug,但是下次我们的类加载器崩溃时,这会很方便。谢谢