初期化順序
このレッスンでは、static 初期化子・インスタンス初期化子・コンストラクタが実行される順を追えるようになります。
まず予測してください
Java
class Item {
static String tag = init("static field");
static { record("static block"); }
String name = init("instance field");
{ record("instance block"); }
Item(String n) { record("ctor " + n); }
}
new Item("A");
new Item("B");record は渡された文字列を1行ずつ記録するだけのメソッドです。
画面に出すのではなく記録にしておくと、並んだ順をあとから文字列として
取り出して確かめられます。
何行記録され、どんな順に並ぶでしょうか。
答えは4段階の順序
実際に記録されるのは次のとおりです。
プレーンテキスト
static field
static block
instance field
instance block
ctor A
instance field
instance block
ctor B読み取れることは3つあります。
- static のものが先 — static フィールドの初期化と static 初期化子は、最初のインスタンスが作られるより前に、クラスが読み込まれた時点で走ります
- static は1回だけ — インスタンスを2つ作っても
static fieldとstatic blockは1度しか記録されません - インスタンス初期化子はコンストラクタの本体より先 — 毎回のインスタンス生成のたびに、フィールド初期化とインスタンス初期化子が走り、そのあとでコンストラクタの本体が動きます
書いた順もそのまま効く
もう1つ大事なのが、同じ段階の中ではソースに書いた順で実行される点です。static フィールドの初期化と static 初期化子が交互に並んでいれば、上から順に走ります。インスタンス側も同じです。試験では、初期化子をわざとフィールド宣言より上に書いて順序を入れ替えてくる問題が出ます。
親クラスがあるとさらに先に来る
継承が絡むと、順序の先頭に親クラスの初期化が入ります。全体では次の並びになります。
- 親クラスの static 初期化
- 子クラスの static 初期化
- 親クラスのインスタンス初期化子とコンストラクタ本体
- 子クラスのインスタンス初期化子とコンストラクタ本体
コンストラクタの先頭には暗黙の super() が入るので、子のコンストラクタ本体が動く前に親が完成している、と考えると自然に覚えられます。この続きは第6章で扱います。
演習で確かめます
上の Item を自分で組み立てて、記録が本当にこの順になるかを実行して確かめます。並びを予想してから提出してください。
要件
- static フィールド tag と static 初期化子を、この順で書くこと
- インスタンスフィールド name とインスタンス初期化子を、この順で書くこと
- trace は new Item(n) と new Item("second") をこの順で作り、log の中身を返すこと
ヒント
編集 ゆめさく編集部