2

次の関数を持つ抽象クラスがある場合-

abstract class A{
    void foo(String s) throws Exception{
        throw new Exception("exception!");
    }
}

そして、抽象クラスを拡張し、独自のバージョンの foo を実装する別のクラス -

class B extends A{
    void foo(String s){
        //do stuff that does *not* throw an exception
    }
}

これは問題を引き起こしますか? 具体的には、次のテスト ケースで -

Collection<A> col = new Collection<A>();
B b = new B();
col.add(b);
for(A a : col){
    a.foo();
}

私はいくつかのテストを行いましたが、何も壊れていないようですが、A ではなく B の foo が呼び出された理由がわかりません

4

4 に答える 4

11

のためPolymorphism

実行時に実際のオブジェクトの型CollectionがそうであるBため、B.foo()呼び出されました。

基本的に、サブタイプオブジェクトがスーパークラス参照に割り当てられている場合、ランタイム ポリモーフィズムは、インスタンス メソッドのサブタイプのバージョンが呼び出されるようにします。つまり、もちろんオーバーライドされている場合です。そうでない場合、呼び出しはスーパークラス バージョンにフォールバックします。

有効なメソッド オーバーライドと見なされるものは何ですか?

オーバーライドされたメソッドには

  • 同じメソッド シグネチャ
  • 共変の戻り型(サブタイプを返すことができます)
  • より広範なチェック例外をスローしてはなりません (あなたの質問と@ Dgrin91のコメントに適用されます。つまり、オーバーライドされたメソッドがいくつかのリスクを冒した(例外をスローした)からといって、オーバーライドするメソッドが同じことを行う必要があるという意味ではありません;したがって、例外をスローしない場合があります全て)
  • より制限の少ないアクセス修飾子を使用してはなりません(保護をパブリックにすることはできますが、プライベートにすることはできません)
于 2013-06-11T20:24:10.963 に答える
0

スローを宣言せずにメソッドをオーバーライドできます。これは、具体的なクラスを使用している呼び出し元に役立ちます。たとえば、B クラスを使用している人は、メソッドのこの実装が何もスローしないため、try-catch を使用する必要はありません。

より詳細な説明は、Jon Skeet によって提供されています: Inheritance 、 method signature 、 method overriding 、 throws 句

于 2013-06-11T20:48:19.450 に答える
0

別のポスターで指摘されているように、この動作はポリモーフィズムが原因で発生します。

コレクションは A の要素であると宣言されました。A を拡張すると宣言された B は A です。これは、型 B の要素をコレクションに追加できるという事実によって裏付けられます (A のインスタンスが必要です)。

A.foo の実装は例外をスローし、それが呼び出された場合は実際に例外をスローします。一方、B はメソッド foo をオーバーライドし、例外をスローしません。コレクションに追加したインスタンスは B の 1 つであったため、呼び出されるのは B.foo です。forループがインスタンスをタイプAとして宣言することは何も変更しません(これはBがAであるため有効です)。

あなたが観察した動作は予期されたものです。

理解を深めるために、次のものを作成するとよいでしょう。

class C extends A {}

コレクションに C インスタンスを 1 つ追加します。C の foo を反復すると、親クラス (A) に委任され、期待どおりに例外がスローされます。

于 2013-06-11T20:31:12.733 に答える