web-dev-qa-db-ja.com

コンストラクターからオーバーライドされたメソッドへのダウンキャストを防ぐために複雑さが必要ですか?

コンストラクターでfinal以外のインスタンスメソッドを呼び出すと、コンストラクターからオーバーライドされたメソッドにダウンキャストされるリスクがあります。

_public class Start {
    public static void main(String[] args) {
        try {
            ClassB obj = new ClassB();

        } catch(Exception e) { }
    }

        static class ClassA {
            ClassA() { initSomething(); }

            void initSomething() {
                System.out.println("ClassA:: initSomething()...");
            }
        }


        static class ClassB extends ClassA {
            @Override
            void initSomething() {
                System.out.println("ClassB:: initSomething()...");
            }
        }
}
_

これで、すべてのサブクラスに依存してsuper.initSomething()を呼び出すことができます。

私が見てきた多くのコンストラクターでは、オーバーライド可能なインスタンスメソッドareが呼び出されます。また、finalとマークされたメソッドを見たことがありません。

コンストラクターで非最終インスタンスメソッドを呼び出さないというポリシーを持っていることで、私は愚かな衒学者ですか?実際には、そのようなダウンキャスティングは実際には例外的なケースです。経験豊富なプログラマは何をしますか?

7
konishiki

コンストラクターでfinal以外のインスタンスメソッドを呼び出さないというポリシーを持っていることで、私は愚かなことに頭を悩ませていますか?

いいえ。ただし、構造をより詳しく理解することが重要です。

実際には、そのようなダウンキャストは実際にはコーナーケースです。経験豊富なプログラマは何をしますか?

ここで「ダウンキャスト」が行われているのは見られません。オーバーライド可能なメソッドを呼び出すだけです。

心に留めておくべき中心的な信条はコンストラクタはオブジェクトを使用可能な状態で構築することで終了する必要があります。これはオブジェクトの各「レベル」まで拡張されます。スーパークラスコンストラクタは完全かつ正しく終了する必要があります。次に、サブクラスコンストラクターが実行され、その状態が適切に初期化されます。

コンストラクタisは初期化メソッドです(たとえコンストラクタが技術的にJavaのメソッドではない場合でも)、「初期化」メソッドのまさにそのアイデアは、オブジェクト指向プログラミングの敵です。別のメソッドに依存しても意味がありませんすでに初期化メソッドがある場合

コンストラクターがメソッドを使用する場合は、finalメソッドのみを呼び出す必要があります。そうしないと、サブクラスでメソッドがオーバーライドされる可能性があります。そのオーバーライドされたメソッドは、super()を呼び出す以外にサブクラスコンストラクターが実行されていないため、まだ初期化されていない状態にアクセスしようとする可能性があります。メソッドが初期化されていない状態にアクセスする場合、上記のルールに違反しますコンストラクターが実際にはまだ実行されていないため。これは、スーパークラスから各サブクラスへの構築の順序を壊します。

もちろん、オブジェクト指向の方法論におけるほとんどの「ルール」のように、それらはあなたが呼ぶよりももっと...ガイドラインです。ほとんどの場合それらに従ってください、しかし1つを飛び越えるのを避けるために10のフープを飛び越えないでください。 「ルール」を破るのが理にかなっている場合は、それを破ってください。ただし、注意してテストしてください。

6
user22815