3

これは説明が少し難しいですが、 と の 2 つのクラスがあるAとしBます。そのような要素を提供する各オブジェクトによって登録されるファクトリ オブジェクト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、コンパイラーが認識していないクラスからの明確な参照がないため、その間にリンクがAありB、まったく気にしないという仮定の下で作業していBます。これを回避するためにできることはありますか? A新しいファクトリを単に登録するよりもメンテナンスが難しくなるため、新しいファクトリを直接 に追加することは避けたいと思っていましたが、まったく機能しないことは明らかです。それでも、できれば意図したとおりに動作させたいと思っています。

関連する場合、私が使用している特定の JVM は Android JVM です。これは、その JVM が使用している最適化の副作用でしょうか?

4

1 に答える 1

7

クラスのロードについては、このブログ投稿で読むことができます。ポイントは、参照されるまでクラスがロードされないことです。クラスの静的ブロックは、クラスがロードされるまで実行されません。ルールは

  1. クラスのインスタンスは、new() キーワードを使用するか、class.forName() を使用してリフレクションを使用して作成されます。これにより、Java で ClassNotFoundException がスローされる場合があります。
  2. クラスの静的メソッドが呼び出されます。
  3. クラスの静的フィールドが割り当てられます。
  4. 定数変数ではないクラスの静的フィールドが使用されています。
  5. Class が最上位クラスであり、クラス内で字句的にネストされた assert ステートメントが実行される場合。

B解決策は、no-op 静的メソッド (または上記のいずれか) をインスタンス化するか呼び出すことです。

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 に答える