初期化の順番とか内部クラスとか
ちょっとハマった。
public class Outer { class Inner { public Inner() { list.add(xxx); // NullPointerException } } private List list = new ArrayList(); public void method() { new Inner(); } }
確かこんなコードだったか。
最初はなんでかさっぱりわからなかった。
new Inner()のところでブレークポイントで止めるとlistは確かにnullじゃないのに、Innerのコンストラクタに入るとnullになる。
はて?
Innerコンストラクタの「list」というのは「Outer.this.list」の省略形だ。
もちろん省略せずに書いても結果は同じなのだが、Outer.thisがすでにnullになっている。
内部クラスのインスタンスは親インスタンスの参照を暗黙的に持つはずで、それがnullというのは・・・
はて?
ふと気になって初期化処理の順番を調べてみた。
案の定フィールドの初期化はコンストラクタの後に行われるとのこと。
Innerを例にとると、
・Outer.thisメンバを宣言しnullで初期化
・コンストラクタ
・Outer.thisメンバに親インスタンスを設定
となる。
思うに、Innerクラスで使うところのOuter.thisというのは一つのインスタンスフィールドであり、コンストラクタ内では初期化されていないため使えないということかな?