Javaにおける初期化ブロックは、クラスのオブジェクトインスタンスが作成される際に実行される特別なコードブロックで、コンストラクタが呼び出される前に実行されます。以下の2つのタイプがあります:
public class Example { static { System.out.println("静的ブロック"); } { System.out.println("インスタンスブロック"); } public Example() { System.out.println("コンストラクタ"); } }
新しいオブジェクトを作成すると、次のように出力されます:
静的ブロック
インスタンスブロック
コンストラクタ
初期化ブロックを使用する意義は、すべてのコンストラクタに共通のロジックが必要な場合や、変数の宣言には収まりきらない複雑な初期化が必要な場合です。しかし、ほとんどの場合はコンストラクタが好まれます。
質問: オブジェクトを作成する際のフィールド、staticブロック、インスタンスブロック、コンストラクタの初期化順序は?
回答:
ストーリー
大規模プロジェクトで初期化の問題が発生しました:開発者の一人が共通のロジックをコンストラクタから初期化ブロックに移動しましたが、呼び出し順序を考慮しませんでした。その結果、いくつかのフィールドがロジックを実行する前に正しく初期化されず、オブジェクトの作成時にNullPointerExceptionが発生しました。
ストーリー
抽象クラスにおける大きな初期化ブロックの再利用により、他のクラスがそのクラスを継承した際に、サブクラスが初期化順序を適切にオーバーライドできませんでした。これにより、継承時の予期しない動作や、初期化ブロックおよびコンストラクタの呼び出し順序に関連するバグが発生しました。
ストーリー
開発者は、静的フィールドが新しいオブジェクトが作成されるたびに再初期化されると仮定し、staticブロックにリソースクリーニングのロジックを追加しました。その結果、リソースはクラスがロードされる際に一度だけクリーニングされ、その後のメモリ管理は「ダウンしました」。静的ブロックは一度だけ呼び出されるため、リソースのリークや不適切なリソース管理を引き起こしました。