Java にはstatic block
、クラスが最初にロードされたときに実行されるコードが含まれているという機能があることがわかりました (「ロード」の意味がわかりません。初期化を意味しますか?)。コンストラクターではなく静的ブロック内で初期化ビットを実行する理由はありますか? つまり、コンストラクターでさえ同じことを行い、クラスが最初に初期化されるときに必要なすべてのことを行います。コンストラクターができないことを静的ブロックが達成することはありますか?
11 に答える
まず、あなたの質問から 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
}
};
static ブロックは、コンストラクターとは異なることを行います。基本的に、2 つの異なる概念があります。
静的ブロックは、クラスがメモリにロードされるときに初期化されます。これは、JVM がバイトコードを読み取ったときを意味します。初期化は何でもかまいません。変数の初期化でも、そのクラスのすべてのオブジェクトで共有する必要があるものでもかまいません。
一方、コンストラクターはそのオブジェクトのみの変数を初期化します。
static ブロックは、静的フィールドを初期化する場合に役立ちます。