8

Java では、ダイヤモンドの問題を保護するために多重継承を許可していません。インターフェイスを使用してこの問題を処理します。

次に、インターフェースを使用する場合、たとえば

interface A{
run();
}

interface B{
run();
}

class C implements A, B{
run() {}   //Which interface we are using?
}

run()classでメソッドを呼び出すとき、C使用しているインターフェイスをどのように判断できますか?

4

7 に答える 7

3

型が 2 つのインターフェイスを実装し、各インターフェイスが同一のシグネチャを持つメソッドを定義する場合、実際にはメソッドは 1 つしかなく、それらを区別することはできません。たとえば、2 つのメソッドの戻り値の型が競合している場合、コンパイル エラーになります。これは、継承、メソッドのオーバーライド、隠蔽、および宣言の一般的なルールであり、継承された 2 つのインターフェイス メソッド間だけでなく、インターフェイスとスーパー クラス メソッド間の競合、またはジェネリックの型消去による競合にも適用されます。 .

対応例

次の例では、present() メソッドを持つ (贈り物を贈る) インターフェイス Gift と、同じく present() メソッドを持つインターフェイス Guest (ゲストは出席し、不在ではない) を使用しています。 )。

見栄えのするジョニーは、ギフトとゲストの両方です。

public class InterfaceTest {
    interface Gift  { void present(); }
    interface Guest { void present(); }

    interface Presentable extends Gift, Guest { }

    public static void main(String[] args) {
        Presentable johnny = new Presentable() {
            @Override public void present() {
                System.out.println("Heeeereee's Johnny!!!");
            }
        };
        johnny.present();                     // "Heeeereee's Johnny!!!"

        ((Gift) johnny).present();            // "Heeeereee's Johnny!!!"
        ((Guest) johnny).present();           // "Heeeereee's Johnny!!!"

        Gift johnnyAsGift = (Gift) johnny;
        johnnyAsGift.present();               // "Heeeereee's Johnny!!!"

        Guest johnnyAsGuest = (Guest) johnny;
        johnnyAsGuest.present();              // "Heeeereee's Johnny!!!"
    }
}

上記のスニペットはコンパイルおよび実行されます。

必要な @Override は 1 つだけであることに注意してください!!!. これは、Gift.present() と Guest.present() が「@Override 相当」であるためです (JLS 8.4.2)。

したがって、johnny には present() の実装が 1 つしかなく、johnny を Gift として扱うか Guest として扱うかに関係なく、呼び出すメソッドは 1 つだけです。

非互換例

以下は、継承された 2 つのメソッドが @Override と同等ではない例です。

public class InterfaceTest {
    interface Gift  { void present(); }
    interface Guest { boolean present(); }

    interface Presentable extends Gift, Guest { } // DOES NOT COMPILE!!!
    // "types InterfaceTest.Guest and InterfaceTest.Gift are incompatible;
    //  both define present(), but with unrelated return types"
}

これは、インターフェイスからメンバーを継承する場合、メンバー宣言の一般的な規則に従わなければならないことをさらに繰り返します。ここでは、Gift と Guest が、互換性のない戻り値の型 (1 つは void、もう 1 つはブール値) で present() を定義しています。1 つの型で void present() と boolean present() を使用できないのと同じ理由で、この例ではコンパイル エラーが発生します。

概要

メソッドのオーバーライドと非表示の通常の要件に従って、@Override と同等のメソッドを継承できます。それらは @Override と同等であるため、事実上、実装するメソッドは 1 つしかないため、区別/選択するものは何もありません。

@Override と同等であると判断されると、それらは同じメソッドになるため、コンパイラはどのメソッドがどのインターフェイス用であるかを識別する必要はありません。

潜在的な非互換性を解決するのは難しい作業かもしれませんが、それはまったく別の問題です。

参考文献

http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.4.8.4

于 2013-11-13T16:42:40.800 に答える
1

あなたにはわかりません。ただし、インターフェイスには機能がないため、どちらも問題ではありません。

これは、Java 8 が登場すると、インターフェイスが関数のデフォルトの実装を持つことができるため、わずかに変更されます。複数のデフォルト実装がある場合、あいまいさが生じる可能性があります。これがどのように解決されるかは、JDK 8 のデフォルトは Java での多重継承の形式ですか?という質問で説明されています。.

于 2013-11-13T16:42:44.283 に答える
0

あなたの質問はあまり意味がありません。現実的な例を挙げてみましょう。AHumanは泣くことができます。アンAnimalBabyは泣くことができます。これで、Human と AnimalBaby の両方であるインスタンスJohnができ、それを泣かせます。何が起こるのですか?John叫びます。両方のインターフェースのメソッドを実装しているという事実は、cry()泣くことが John にとって何を意味し、何をするかを変えるものではありません。

于 2013-11-13T16:42:15.173 に答える
0

両方。C は 2 つのインターフェースから 2 つのメソッドを継承しました (これはたまたまオーバーライドと同等(8.4.8.4)です)。C には、署名が両方に一致するため、両方をオーバーライドする 1 つのメソッドがあります。(8.4.2)

ただし、2 つのメソッドが同じ名前とパラメーターの型を持っているからといって、それらが同じセマンティクスを持っているとは限りません。名前は、2 つの異なることを意味する 1 つの英語の単語である可能性が非常に高いです。同じように見えるが実際にはセマンティクスが異なる 2 つのスーパー インターフェイスから 2 つのメソッドを継承した場合、サブクラスに 2 つの実装があるはずです。例えば

interface java.lang.Runnable
    void run()

interface com.animal.Runnable
    void run()

class Dog implements com.animal.Runnable,
                     java.lang.Runnable // a dog as a task
    ???

そのような場合を処理できる言語を想像できます。しかし、Java はそれをしません。2 つのメソッドが十分に類似している場合、それらは同じセマンティクスを持つと見なされます。幸いなことに、実際には、これはとにかく問題になるようです。

于 2013-11-13T16:43:19.607 に答える