web-dev-qa-db-ja.com

Javaサブタイプではなく、他のオブジェクトの親オーバーライドメソッドを呼び出すことはできますか?

ここで働いていますJavaコード

class Cup {
    public String sayColor() {
        return "i have a color .";
    }
}

class TCup extends Cup{
    public String sayColor(){
        System.out.println(super.getClass().getName());
        return super.sayColor()+"color is tee green.";
    }
}

class MyTCup extends TCup {
    public String sayColor(){
        System.out.println(super.getClass().getName());
        return super.sayColor()+"but brushed to red now!";
    }
}
class Test {
    public static void main(String[] args) {
        Cup c = new MyTCup();
        System.out.print(c.sayColor());
    }
}

testクラスの出力を実行します

MyTCup
MyTCup
i have a color .color is tee green.but brushed to red now!

質問1:実行時、オブジェクトCのタイプはMyTCupですが、常にスーパーメソッドを呼び出すことができます。オブジェクトを初期化した後、MyTCup内のメモリにメソッドスタックがあり、コードのように実行時に呼び出すことができますか?

質問2:他のオブジェクトのスーパーメソッドを呼び出す方法はありません。私が知っているように、c ++はいつでもキャストして親メソッドを呼び出すことができます。なぜJavaで違うのですか?

36
sting

他のオブジェクトでスーパーメソッドを呼び出すことはできません。カプセル化に違反します。全体のポイントは、オーバーライドされたメソッドの動作をオブジェクトが制御することです。たとえば、特定の状況で例外をスローするためにコレクションのaddメソッドをオーバーライドすると、「有効な」アイテムのみがコレクションに追加されるようにすることができます。呼び出し側がキャストでそれをバイパスすることができれば、それは無意味です!

オブジェクトがsuper.foo()を呼び出すのは、親実装を使用して1つの呼び出しを実装できるようにするためだけです。それが賢明な方法でのみ実行されるようにするのは、クラスのコード次第です。繰り返しになりますが、add-in-a-collectionの例を使用するには、コレクションがaddをオーバーライドする場合、検証済みアイテムをコレクションに追加するsome方法が必要です。 super.add()で行います。

カプセル化の同じ理由で、only祖父母実装ではなく親実装を呼び出すことができることに注意してください-super.foo()は有効ですが、super.super.foo()は無効ですt。

68
Jon Skeet

1:

あなたの質問は明確ではありません。 「実行時にコードのようにコールスルーする」とはどういう意味ですか?インスタンスcがそのスーパークラスをどのように認識するかを尋ねる場合、はい、クラス階層はメモリに格納され、VMからアクセスできます。

2:

Javaでは、実際にインスタンスをその親にキャストできます。インスタンスでメソッドを呼び出すと、コンパイル時のクラスではなく、常にインスタンスの実際のクラスが使用されます。つまりin JavaすべてのメソッドはC++で「仮想」と呼ばれるものです。なぜこれが決定されたのかわかりません。

編集: Jon Skeetは、サブクラスのインスタンスでスーパークラスのメソッドを呼び出せない理由を非常にうまく説明しています。

1
sleske

実際には可能ですが、方法論を使用する必要があるため、コードでのみ機能します。
スーパークラスで、次のようにメソッドにパラメーター「Class」を追加します。

public String sayColor(Class classFilter){...

現在、すべてのオーバーライドで、現在のサブクラスが次のような指定されたフィルターの1つであるかどうかを確認します。

if(TCup.class!=classFilter)return super.sayColor(classFilter);
return "some text for TCup only";

私は排他的な方法でコーディングしました。さらにパラメーターを追加するか、nullと比較して、結果をスーパークラスと結合し、創造性を発揮できます:)

0
Aquarius Power

サブクラスで新しいヘルパーメソッドを定義して、オリジナルをオーバーライドしないようにすることができます。つまり、必要に応じて、スーパーメソッドを呼び出すことができます。

0
rogerdpack