web-dev-qa-db-ja.com

クラスを強制的に初期化するにはどうすればよいですか?

これを行うための最善かつ最もクリーンな方法は何ですか?具体的には、そのクラスで実行するには静的初期化ブロックにいくつかのコードが必要ですが、これを可能な限りきれいに見せたいです。

41
Artem

読み込み中!=初期化。

クラスを初期化する必要があります(これは、とりわけ静的ブロックが実行されるときです)。

Java言語仕様 からの抜粋は、次のように述べています。

クラスまたはインターフェースタイプTは、次のいずれかが最初に発生する直前に初期化されます。

  • Tはクラスであり、Tのインスタンスが作成されます。
  • Tはクラスであり、Tによって宣言された静的メソッドが呼び出されます。
  • Tによって宣言された静的フィールドが割り当てられます。
  • Tによって宣言された静的フィールドが使用され、そのフィールドは定数変数ではありません(§4.12.4)。
  • Tはトップレベルのクラスであり、T内で字句的にネストされたassertステートメント(§14.10)が実行されます。

クラスClassとパッケージJava.lang.reflectで特定のリフレクトメソッドを呼び出すと、クラスまたはインターフェースの初期化も行われます。他の状況では、クラスまたはインターフェースは初期化されません。

AnovstrupのDohはすでにそれを言っています:initという空の静的関数を作成するだけです。十分に文書化してください...整形式のコードのコンテキストでは、私は個人的にこれのユースケースを見ることができません。

次のコードを使用して、クラスを強制的に初期化できます。

//... Foo.class ...          //OLD CODE
... forceInit(Foo.class) ... //NEW CODE

/**
 * Forces the initialization of the class pertaining to 
 * the specified <tt>Class</tt> object. 
 * This method does nothing if the class is already
 * initialized prior to invocation.
 *
 * @param klass the class for which to force initialization
 * @return <tt>klass</tt>

 */
public static <T> Class<T> forceInit(Class<T> klass) {
    try {
        Class.forName(klass.getName(), true, klass.getClassLoader());
    } catch (ClassNotFoundException e) {
        throw new AssertionError(e);  // Can't happen
    }
    return klass;
} 
17
Iulian
try
{
  Class.forName(class name as string)
}
catch(ClassNotFoundException e)
{
  whatever
}

それでうまくいくはずです。

@Longpoke

その時私は何かを誤解しているのかもしれません。クラスがロードされているが静的初期化子がnot実行される例を作成できますか?以下は、ロードしたことを出力するだけの例です。

package test;

public class TestStatic 
{
    public static void main(String[] args) 
    {
        try 
        {
            Class.forName("test.Static");
        }
        catch (ClassNotFoundException e) 
        {
            e.printStackTrace();
        }
    }
}

次の静的クラスがロードされています:

package test;

public class Static 
{
    static
    {
        System.out.println("Static Initializer ran...");
    }
}

リストした条件が満たされるまで静的初期化子が実行されない場合、テストを実行するとなぜこのprintlnが実行されるのですか?リストにある条件のうち、私が満たすものはどれですか。

8
BigMac66

クラス間の目に見えない依存関係は良い考えではありません。静的初期化ブロックのコードを静的メソッドに移動し、依存クラスで直接呼び出すことをお勧めします。静的初期化ブロックは、新しく作成された静的メソッドを呼び出すように書き換えることができます。

4
Abhinav Sarkar

1つの解決策は、静的メソッドを呼び出すことです。

_public class A {
   static { DebugUtils.FLAG_TEST_USER = true; }

   static void init() {}
}
_

次にA.init()を呼び出して初期化を強制します。

ただし、これを行うことはコードのにおいです。シングルトンオブジェクトの静的コードを標準コンストラクタに置き換えることを検討してください。

1
Aaron Novstrup

クラス内の何かを静的に初期化する必要がある場合は、それに依存するクライアントクラスが存在する必要があることを意味します。

クライアントが1つある場合、または初期化ブロックの通常のホームと呼ぶ場合、そこで初期化するのが最もクリーンだと思います。

多くの同等のクライアントの場合、これらのクラスから、他のクラスの静的初期化が成功したことを確認することをお勧めします。次に、カップリングが文書化され、最初のクライアントがそれを必要とする前に、クラスが常に初期化されることが確実になります。

0
Peter Tillemans