クラスを継承したときの初期化(コンストラクタ等)と対になる終了処理(デストラクタ等)の話。
初期化の順番ってどれほど気にしているでしょうか?例として、
と
だったら、どっちが良いと思いますか?どっちでも良いと思いますか?
前者はコンパイルエラーになります(コンストラクタなので、たぶん)。
なぜか。
親を継承した子クラスは親クラスが存在して初めて成立するので、
親クラスが準備出来ていない時に子クラスが何かする(この場合は初期化する)と、
親クラスの初期化されていないメンバにアクセスしたりして、予期しない動作を起こす可能性がでてきてしまうからです。
→だから順番が強制されているのです。(終了処理は必然的に順番が逆になります)
ちなみに親が子のことを予め知ることはできないので、親→子の順番で初期化するのは何も問題おきません・・・。
(こういう理由でprivateなコンストラクタを持つクラスは継承できないのです。つまり、コンストラクタにつく「private」は継承を禁止にするキーワードでは全くなく、コンストラクタがprivateだと呼べないから結果的に継承できなくなってるだけなのです)
この例はコンストラクタなので、当たり前なところがありますが、最近流行り?のAndroid界隈では結構こんなコードを見かけます。
でも上で言った話があるので、本当は逆にしたほうがいいです。
最後に関連して一つ追加すると、
初期化と終了は対になっているはずなので、A->B->Cの順番で初期化したら
C->B->Aの順番で終了されているのが正しいです。
(もちろん互いに関係なければ順番は関係ないですが、お作法的な配置の話です)
まとめると、初期化は親→子、終了処理は子→親の順番でやるのが正しくて、順番が逆なのはなにも気にしていないか、よほどの理由があるときしかありえない。
ぜひ気をつけましょう。
初期化の順番ってどれほど気にしているでしょうか?例として、
public class InitializePattern1 extends Parent { public InitializePattern1() { initializePattern1Class(); super(); } }
と
public class InitializePattern1 extends Parent { public InitializePattern1() { super(); initializePattern1Class(); } }
だったら、どっちが良いと思いますか?どっちでも良いと思いますか?
前者はコンパイルエラーになります(コンストラクタなので、たぶん)。
なぜか。
親を継承した子クラスは親クラスが存在して初めて成立するので、
親クラスが準備出来ていない時に子クラスが何かする(この場合は初期化する)と、
親クラスの初期化されていないメンバにアクセスしたりして、予期しない動作を起こす可能性がでてきてしまうからです。
→だから順番が強制されているのです。(終了処理は必然的に順番が逆になります)
ちなみに親が子のことを予め知ることはできないので、親→子の順番で初期化するのは何も問題おきません・・・。
(こういう理由でprivateなコンストラクタを持つクラスは継承できないのです。つまり、コンストラクタにつく「private」は継承を禁止にするキーワードでは全くなく、コンストラクタがprivateだと呼べないから結果的に継承できなくなってるだけなのです)
この例はコンストラクタなので、当たり前なところがありますが、最近流行り?のAndroid界隈では結構こんなコードを見かけます。
public class SampleActivity extends Activity {
@Override
public onCreate() {
doInitialization(); // 先に初期化しちゃってる
super.onCreate();
}
public onDestroy() {
super.onDestroy();
doClosing();// 後で終了処理しちゃってる
}
}
これは、コンストラクタやデストラクタ(C++)以外は、特に順番関係なく呼べちゃうからできちゃうんですね。でも上で言った話があるので、本当は逆にしたほうがいいです。
最後に関連して一つ追加すると、
初期化と終了は対になっているはずなので、A->B->Cの順番で初期化したら
C->B->Aの順番で終了されているのが正しいです。
(もちろん互いに関係なければ順番は関係ないですが、お作法的な配置の話です)
public class SampleActivity extends Activity { @Override public onCreate() { super.onCreate(); doInitializationA(); // Aを初期化 doInitializationB(); // Bを初期化 doInitializationC(); // Cを初期化 } public onDestroy() { doClosingC(); // Cを終了 doClosingB(); // Bを終了 doClosingA(); // Aを終了 super.onDestroy(); } }
まとめると、初期化は親→子、終了処理は子→親の順番でやるのが正しくて、順番が逆なのはなにも気にしていないか、よほどの理由があるときしかありえない。
ぜひ気をつけましょう。
コメント