初期化順序

このレッスンでは、static 初期化子・インスタンス初期化子・コンストラクタが実行される順を追えるようになります。

まず予測してください

class Item { static String tag = init("static field"); static { System.out.println("static block"); } String name = init("instance field"); { System.out.println("instance block"); } Item(String n) { System.out.println("ctor " + n); } } new Item("A"); new Item("B");

何行出力され、どんな順に並ぶでしょうか。

答えは4段階の順序

実際の出力は次のとおりです。

static field static block instance field instance block ctor A instance field instance block ctor B

読み取れることは3つあります。

  1. static のものが先 — static フィールドの初期化と static 初期化子は、最初のインスタンスが作られるより前に、クラスが読み込まれた時点で走ります
  2. static は1回だけ — インスタンスを2つ作っても static fieldstatic block は1度しか出ません
  3. インスタンス初期化子はコンストラクタの本体より先 — 毎回のインスタンス生成のたびに、フィールド初期化とインスタンス初期化子が走り、そのあとでコンストラクタの本体が動きます

書いた順もそのまま効く

もう1つ大事なのが、同じ段階の中ではソースに書いた順で実行される点です。static フィールドの初期化と static 初期化子が交互に並んでいれば、上から順に走ります。インスタンス側も同じです。試験では、初期化子をわざとフィールド宣言より上に書いて順序を入れ替えてくる問題が出ます。

親クラスがあるとさらに先に来る

継承が絡むと、順序の先頭に親クラスの初期化が入ります。全体では次の並びになります。

  1. 親クラスの static 初期化
  2. 子クラスの static 初期化
  3. 親クラスのインスタンス初期化子とコンストラクタ本体
  4. 子クラスのインスタンス初期化子とコンストラクタ本体

コンストラクタの先頭には暗黙の super() が入るので、子のコンストラクタ本体が動く前に親が完成している、と考えると自然に覚えられます。この続きは第6章で扱います。

演習で確かめます

上の Item を自分で組み立てて、出力が本当にこの順になるかを実行して確かめます。出力を予想してから提出してください。

要件

  1. static フィールド tag と static 初期化子を、この順で書くこと
  2. インスタンスフィールド name とインスタンス初期化子を、この順で書くこと
  3. trace は new Item(n) と new Item("second") をこの順で作り、文字列 done を返すこと

入出力例

trace("A") → "static field static block instance field instance block ctor A instance field instance block ctor second done" trace("B") → "static field static block instance field instance block ctor B instance field instance block ctor second done"

ヒント

生田 陸人
ゆめさくエンジニア / 現役ソフトウェアエンジニア
編集 LuaGate編集部
main.java
学習モード

メモ

初期化順序

⌘S で保存