Programmingミドル/上級Java開発者

Javaにおけるクラス初期化順序とは何か、それはどのように機能し、静的および非静的メンバーの初期化順序を誤解するとどのような結果を招く可能性があるのか?

Hintsage AIアシスタントで面接を突破

答え。

Javaのクラス初期化順序(class initialization order)は、フィールド、ブロック、およびコンストラクタが初期化される順序を定義します。簡単に言うと:

  1. 静的フィールドと静的イニシャライザは、JVMがクラスをロードする際に、そのクラス内での出現順に実行されます(クラスごとに1回)。
  2. 非静的フィールドとイニシャライザは、インスタンスが作成されるたびに、その出現順に実行され、コンストラクタが呼び出される前に実行されます。
  3. コンストラクタは、すべてのフィールドとブロックの初期化後に実行されます。

class Parent { static { System.out.println("Parent static"); } { System.out.println("Parent init"); } Parent() { System.out.println("Parent constructor"); } } class Child extends Parent { static { System.out.println("Child static"); } { System.out.println("Child init"); } Child() { System.out.println("Child constructor"); } } // new Child() -> どの順序?

出力は:

  1. Parent static
  2. Child static
  3. Parent init
  4. Parent constructor
  5. Child init
  6. Child constructor

まず親クラスの静的ブロックが実行され、その後子クラスの静的ブロック、最後に非静的ブロックとコンストラクタが継承順に実行されます。

トリック質問。

質問: クラス内の静的イニシャライザはいつ実行されるのか?

class Ex {
    static { System.out.println("static"); }
}

— 最初のインスタンス作成時か、任意の静的メソッド/フィールドの初回アクセス時か?

答え: 静的イニシャライザは、クラスへの初回アクセス時(いかなる静的メンバーへのアクセスを含む)に実行され、インスタンス作成時だけではありません。

トピックの細部を知らないことから生じる実際のエラーの例。


物語

銀行アプリケーションでは、静的接続プールが静的ブロックで初期化されましたが、最初のインスタンス作成前に静的メソッドにアクセスしたため、接続は作成されていませんでした。これにより、負荷テスト中にNullPointerExceptionが発生しました。


物語

ログサービスは、親クラスのコンストラクタが呼ばれた後に初期化される非静的フィールドに依存していました。ログはnullロガーに書き込まれ、重要なエラーメッセージが失われました。


物語

初期値を持つ新しいフィールドを追加する際、開発者はイニシャライゼーションブロックの後に配置しました。ブロックはまだ初期化されていないフィールドを使用しようとしたため、アプリケーションの起動時にエラーが発生し、原因を見つけるのが困難でした。