解释起来有点棘手,但假设我有两个类 A
和 B
。 A
包含工厂对象的静态
列表,这些工厂对象由提供此类因子的每个对象注册。在此示例中,B
就是这样一个类,并提供了一个虚构的 Factory
实现。
A类:
public class A {
protected static Map<String, Factory> registered = new HashMap<String, Factory>();
protected static register(String name, Factory factory) {
registered.put(name, factory);
}
public A() {
// Do something with the factories we've registered
}
}
B类:
public class B {
static {
A.register("Foo", new Factory() {
public Object create() {
return new B();
}
});
}
public B() {
// Create a new instance of class B
}
}
在我的程序中,由于某种奇怪的原因,B
中的静态 block 从未被调用,因此当我开始与 A
交互时,没有注册任何工厂,因此它无法做它需要做的事情。
如果我将每个Factory
的创建直接移到A
中,当然没有问题。我的工作假设是,由于编译器无法识别的任何类都没有对 B
的明确引用,因此 A
和 B 之间存在链接
所以根本不用担心 B
。我能做些什么来解决这个问题吗?我希望避免直接将每个新工厂添加到 A
中,因为这使得维护比让新工厂简单地注册自己更困难,但显然让它们根本不起作用更糟糕;尽管如此,如果可以的话,我还是想以某种方式让它按预期工作。
如果相关的话,我正在使用的特定 JVM 是 Android JVM,这可能是该 JVM 正在使用的某些优化的副作用吗?
最佳答案
您可以在this blog post中阅读有关类加载的信息。 。要点是类在被引用之前不会被加载。并且类的静态 block 在类被加载之前不会被执行。规则是
- 类的实例是使用 new() 关键字或使用 class.forName() 进行反射创建的,这可能会在 Java 中抛出 ClassNotFoundException。
- 调用类的静态方法。
- 分配了 Class 的静态字段。
- 使用类的静态字段,它不是常量变量。
- if Class 是顶级类,并且执行按词法嵌套在类中的断言语句。
解决方案是实例化 B
或调用无操作静态方法(或上述任何方法)。
public class B {
static {
A.register("Foo", new Factory() {
public Object create() {
return new B();
}
});
}
public void static noOp() {}
public B() {
// Create a new instance of class B
}
}
...
B.noOp();
Oracle JVM 规范指出了这一点 here .
关于java - Java中自注册对象的静态 block 无法执行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18538342/