web-dev-qa-db-ja.com

同じメソッドを持つクラスに2つのインターフェイスを実装します。どのインターフェイスメソッドがオーバーライドされますか?

同じメソッド名とシグネチャを持つ2つのインターフェイス。しかし、単一のクラスによって実装されている場合、コンパイラはどのメソッドがどのインターフェイス用であるかをどのように識別するのでしょうか?

例:

interface A{
  int f();
}

interface B{
  int f();
}

class Test implements A, B{   
  public static void main(String... args) throws Exception{   

  }

  @Override
  public int f() {  // from which interface A or B
    return 0;
  }
}   
203
Jothi

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


互換性の例

以下に、interface Giftpresent()メソッド(ギフトの提示など)があり、interface Guestにもpresent()メソッド(例:ゲストが存在し、不在ではない)がある例を示します。

Presentable johnnyは、GiftGuestの両方です。

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!!!"
    }
}

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

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

したがって、johnnyにはpresent()の実装が1つだけあります。ま​​た、johnnyとしてもGiftとしても、Guestの処理方法は関係ありません。呼び出すメソッドは1つだけです。


非互換性の例

次に、継承された2つのメソッドが@Override- equivalentではない例を示します。

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"
}

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


概要

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

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

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

参照資料

293

コンパイラに関する限り、これらの2つの方法は同じです。両方の実装が1つあります。

2つのメソッドが同じ実装である必要があるという点で、2つのメソッドが実質的に同一である場合、これは問題ではありません。それらが契約上異なる場合(各インターフェイスのドキュメントに従って)、問題が発生します。

20
Ash

これはこの質問の重複としてマークされました https://stackoverflow.com/questions/24401064/understanding-and-solving-the-diamond-problems-in-Java

多重継承の問題を取得するにはJava 8が必要ですが、それでもまだダイアモン問題ではありません。

interface A {
    default void hi() { System.out.println("A"); }
}

interface B {
    default void hi() { System.out.println("B"); }
}

class AB implements A, B { // won't compile
}

new AB().hi(); // won't compile.

JB Nizetがコメントしているように、これは私のオーバーライドを修正できます。

class AB implements A, B {
    public void hi() { A.super.hi(); }
}

ただし、問題はありません

interface D extends A { }

interface E extends A { }

interface F extends A {
    default void hi() { System.out.println("F"); }
}

class DE implement D, E { }

new DE().hi(); // prints A

class DEF implement D, E, F { }

new DEF().hi(); // prints F as it is closer in the heirarchy than A.
19
Peter Lawrey

特定するものは何もありません。インターフェイスは、メソッド名と署名のみを禁止します。両方のインターフェイスにまったく同じ名前とシグネチャのメソッドがある場合、実装クラスは単一の具象メソッドで両方のインターフェイスメソッドを実装できます。

ただし、2つのインターフェイスメソッドのsemanticコントラクトが矛盾する場合は、ほとんど失われています。その場合、単一のクラスに両方のインターフェースを実装することはできません。

12

インターフェイスと同様に、メソッドを宣言しているだけです。これら両方のインターフェイスを実装する具体的なクラスは、メソッドが1つしかないことを理解しています(両方のメソッドで、戻り値の型が同じであると説明しました)。したがって、問題はないはずです。具体的なクラスでそのメソッドを定義できます。

ただし、2つのインターフェイスに同じ名前で異なる戻り型のメソッドがあり、具象クラスに2つのメソッドを実装する場合:

以下のコードを見てください:

public interface InterfaceA {
  public void print();
}


public interface InterfaceB {
  public int print();
}

public class ClassAB implements InterfaceA, InterfaceB {
  public void print()
  {
    System.out.println("Inside InterfaceA");
  }
  public int print()
  {
    System.out.println("Inside InterfaceB");
    return 5;
  }
}

コンパイラがメソッド「public void print()」を取得すると、最初にInterfaceAを検索して取得しますが、戻り値の型がInterfaceBのメソッドと互換性がないというコンパイル時エラーが発生します。

そのため、コンパイラにとっては困ります。

この方法では、同じ名前のメソッドで戻り型が異なる2つのインターフェイスを実装することはできません。

4
Bhagrav Jain

インターフェースを匿名として実装してみてください。

public class MyClass extends MySuperClass implements MyInterface{

MyInterface myInterface = new MyInterface(){

/* Overrided method from interface */
@override
public void method1(){

}

};

/* Overrided method from superclass*/
@override
public void method1(){

}

}
4
dcanh121

両方が同じであれば、それは問題ではありません。インターフェイスメソッドごとに単一の具象メソッドを使用して、これらの両方を実装します。

3
Paul Whelan