Re:インスタンス変数の初期化タイミングとか

j0

インスタンス変数の初期化タイミングとか
http://d.hatena.ne.jp/cocoon1982/20120515/1337049129

アンサーソングをばw

お題

クラス内に、何も修飾せず「{ 実装 }」と記述することで、コンストラクタが呼び出される前にメソッドとして呼び出される。
はずなのに、
動作としてはClassB()からClassA()、ここまではいい。その時点でa = null;されて、そこからinitialize()、overrideしてるからここではClassBのinitialize()が呼ばれて、b = "b";。その後、ClassB()のsuper()に戻ってきてb = nullされる。つまりString b = null;のb = null先にinitialize()のb = "b";が動いてるって事らしい。
スーパークラスのコンストラクタの

b = "b";

の後にサブクラスの

b = null;

が動くのが納得行かない。

確かにそっすね。

結論から言いますと、

『サブクラスの、スーパークラス初期化のエントリポイントが、コンストラクタじゃなくって、インスタンス初期化子の先頭だったら気持ち悪く無かったかもしれない。』

ということになるでしょうか。

バイトコードを見てみましょう

継承関係を絡めた、コンストラクタ、各種初期化子の実行順ってよく話題になりますね。
もちろん、OJC-Pの問題集にもありました。

今回は、こまけえこた(ryってことで、バイトコードを見てみるおw

javapじゃなくってBytecode Outline plugin for Eclipse使います。

簡単にバイトコードの説明を

くらいで後は雰囲気でおk

元のコード

ex1
サブクラスのコンストラクタの先頭super()からスーパークラスのコンストラク

サブクラスのインスタンス(変数)初期化

サブクラスのコンストラクタのコード

となっていますね。

サブクラスのコンストラクタのsuper()を省略

ex2
サブクラスのコンストラクタの先頭からスーパークラスのコンストラク

サブクラスのインスタンス(変数)初期化

サブクラスのコンストラクタのコード

実行順は同じですね。

インスタンス初期化子版

ex3
サブクラスのコンストラクタの先頭super()からスーパークラスのコンストラク

サブクラスのインスタンス(変数)初期化

サブクラスのコンストラクタのコード

これも、実行順は同じですね。
あと、「インスタンス初期化子」のブロックは、さっきまでの「インスタンス変数の宣言と同時に初期化」と全く同じになってます。


ちなみに、インスタンス初期化子は、JUnitのテストケースなんかで、データを準備する時にちょっと便利です。

HashMap<String, String> m = new HashMap<String, String>() {
	{
		put("A", "あ");
		put("B", "い");
	}
};

ClassAを継承してない場合

コンストラクタより先にインスタンス初期化(子)でブレークしますね。
これはやってみるといいと想います。

まとめ

今回は、
「インタンス初期化(子)は、コンストラクタ内の(super()以降の)コードが呼び出される前に実行される」
事をバイトコードで確認しました。

黒魔術系を触ってると重宝するBytecode Outline plugin for Eclipseですが、一家に一台いかがでしょう?

って事でw