3

这有点难以解释,但假设我有两个类AB. A包含static由每个提供此类因素的对象注册的工厂对象列表。在这个例子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永远不会被调用,所以当我开始与A没有注册的工厂交互时,它不能做它需要做的事情。

如果我将每个的创建直接Factory移入A,当然没有问题。我的工作假设是因为B编译器没有识别出任何类中没有明确的引用,因此它们之间存在链接AB因此根本不会打扰B。我能做些什么来解决这个问题吗?我希望避免将每个新工厂添加到A直接添加每个新工厂,因为这会使维护比让新工厂简单地注册自己更加困难,但显然让它们都没有工作更糟糕;不过,如果可以的话,我想以某种方式让它按预期工作。

如果相关,我正在使用的特定 JVM 是 Android JVM,这可能是该 JVM 正在使用的一些优化的副作用吗?

4

1 回答 1

7

您可以在此博客文章中阅读有关类加载的信息。关键是一个类在被引用之前不会被加载。并且在加载类之前不会执行类的静态块。规则是

  1. 使用 new() 关键字或使用 class.forName() 的反射创建类的实例,这可能会在 Java 中引发 ClassNotFoundException。
  2. 调用 Class 的静态方法。
  3. 分配了 Class 的静态字段。
  4. 使用了一个类的静态字段,它不是一个常量变量。
  5. if Class 是顶级类,并且执行词法嵌套在 class 中的 assert 语句。

一种解决方案是实例化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 规范在此处说明了这一点。

于 2013-08-30T17:27:12.130 回答