56

Java にはstatic block、クラスが最初にロードされたときに実行されるコードが含まれているという機能があることがわかりました (「ロード」の意味がわかりません。初期化を意味しますか?)。コンストラクターではなく静的ブロック内で初期化ビットを実行する理由はありますか? つまり、コンストラクターでさえ同じことを行い、クラスが最初に初期化されるときに必要なすべてのことを行います。コンストラクターができないことを静的ブロックが達成することはありますか?

4

11 に答える 11

49

まず、あなたの質問から 1 つのことを強調したいと思います。

コンストラクターは同じことを行い、クラスが最初に初期化されるときに必要なすべてのことを行います

これは正しくありません。コンストラクターは、クラスのインスタンスが作成されるときに必要なすべての初期化を行います。クラス自体が最初にメモリにロードされて初期化されるとき、コンストラクターは実行されません (クラスのインスタンスがクラスの初期化の一部としてたまたま作成された場合を除く)。この混乱 (クラスの初期化とクラスのインスタンスの初期化の間) が、おそらくstaticブロックの有用性に疑問を投げかけている理由です。

クラスに複雑な初期化を必要とする静的メンバーがある場合、staticブロックが使用するツールになります。何らかの静的マップが必要だとします (ここでは目的は関係ありません)。次のようにインラインで宣言できます。

public static final Map<String, String> initials = new HashMap<String, String>();

ただし、一度入力したい場合は、インライン宣言ではできません。staticそのためには、ブロックが必要です。

public static final Map<String, String> initials = new HashMap<String, String>();
static {
    initials.put("AEN", "Alfred E. Newman");
    // etc.
}

さらに保護したい場合は、次のようにすることができます。

public static final Map<String, String> initials;
static {
    Map<String, String> map = new HashMap<String, String>()
    map.put("AEN", "Alfred E. Newman");
    // etc.
    initials = Collections.unmodifiableMap(map);
}

initialsインラインを変更不可能なマップとして初期化できないことに注意してください。putまた、変更メソッド (など)の 1 つを呼び出すだけで例外が生成されるため、コンストラクターでこれを行うこともできません。

公平を期すために、これはあなたの質問に対する完全な答えではありません。ブロックはstatic、プライベートな静的関数を使用して削除できます。

public static final Map<String, String> initials = makeInitials();

private static Map<String, String> makeInitials() {
    Map<String, String> map = new HashMap<String, String>()
    map.put("AEN", "Alfred E. Newman");
    // etc.
    return Collections.unmodifiableMap(map);
}

ただし、これは、static提案したようにコンストラクター内のブロックをコードに置き換えるものではないことに注意してください! staticまた、相互に関連する方法で複数のフィールドを初期化する必要がある場合、これは機能しません。

ブロックを置き換えるのが厄介なケースは、static他のいくつかのクラスを一度だけ初期化する必要がある「マスター」クラスです。

public class Master {
    static {
        SlaveClass1.init();
        SlaveClass2.init(SlaveClass1.someInitializedValue);
        // etc.
    }
}

SlaveClass2特に、依存関係をonに固定したくない場合はSlaveClass1、このようなある種のマスター コードが必要です。この種のものは、間違いなくコンストラクターには属しません。

インスタンス初期化ブロックと呼ばれるものもあります。これは、各インスタンスの作成時に実行されるコードの匿名ブロックです。(構文はstaticブロックに似ていますが、staticキーワードはありません。) 名前付きコンストラクターを持つことができないため、匿名クラスには特に便利です。これが実際の例です。(計り知れGZIPOutputStreamないことに) には、圧縮レベルを指定できるコンストラクターまたは API 呼び出しがなく、デフォルトの圧縮レベルが none であるGZIPOutputStreamため、圧縮を取得するにはサブクラス化する必要があります。いつでも明示的なサブクラスを作成できますが、匿名クラスを作成する方が便利な場合があります。

OutputStream os = . . .;
OutputStream gzos = new GZIPOutputStream(os) {
    {
        // def is an inherited, protected field that does the actual compression
        def = new Deflator(9, true); // maximum compression, no ZLIB header
    }
};
于 2012-12-21T18:05:36.067 に答える
3

static ブロックは、コンストラクターとは異なることを行います。基本的に、2 つの異なる概念があります。

静的ブロックは、クラスがメモリにロードされるときに初期化されます。これは、JVM がバイトコードを読み取ったときを意味します。初期化は何でもかまいません。変数の初期化でも、そのクラスのすべてのオブジェクトで共有する必要があるものでもかまいません。

一方、コンストラクターはそのオブジェクトのみの変数を初期化します。

于 2012-12-21T18:03:00.990 に答える
2

static ブロックは、静的フィールドを初期化する場合に役立ちます。

于 2012-12-21T18:39:01.677 に答える