Implémenter deux interfaces dans une classe avec la même méthode. Quelle méthode d'interface est overridden?

deux interfaces avec les mêmes noms et signatures de méthode. Mais mis en œuvre par une seule classe alors comment le compilateur identifiera la méthode pour quelle interface?

Ex:

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;
  }
}   
179
demandé sur Kevin Panko 2010-05-10 14:21:33

7 réponses

si un type implémente deux interfaces, et chaque interface définit une méthode qui a une signature identique, alors en fait il n'y a qu'une seule méthode, et ils ne sont pas distinguables. Si, par exemple, les deux méthodes ont des types de retour en conflit, alors ce sera une erreur de compilation. Il s'agit de la règle générale de l'héritage, de la primauté de la méthode, de la dissimulation et des déclarations, et s'applique également aux conflits possibles non seulement entre 2 méthodes héritées interface , mais aussi un interface et un Super class méthode, ou même juste des conflits en raison de l'effacement de type de génériques.


exemple de compatibilité

voici un exemple où vous avez un interface Gift , qui a une méthode present() (comme dans, présenter des cadeaux), et aussi un interface Guest , qui a également une méthode present() (comme dans, l'invité est présent et pas absent).

Presentable johnny est à la fois un Gift et un 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!!!"
    }
}

l'extrait ci-dessus compile et court.

notez que il n'y a qu'un seul @Override nécessaire!!! . C'est parce que Gift.present() et Guest.present() sont @Override - équivalent" ( JLS 8.4.2 ).

ainsi, johnny n'a qu'une mise en œuvre de present() , et il peu importe comment vous traitez johnny , que ce soit comme Gift ou comme Guest , il n'y a qu'une seule méthode à invoquer.


exemple D'incompatibilité

voici un exemple où les deux méthodes héritées ne sont pas @Override - équivalent:

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

ceci réitère une fois de plus que les membres qui héritent d'un interface doivent obéir à la règle générale des déclarations des membres. Ici nous avons Gift et Guest définir present() avec des types de retour incompatibles: un void l'autre boolean . Pour la même raison que vous ne pouvez pas un void present() et un boolean present() dans un type, cet exemple résulte en une erreur de compilation.


résumé

vous pouvez hériter des méthodes qui sont @Override - équivalent, sous réserve des exigences habituelles de la méthode de dérogation et de se cacher. Depuis ils sont @Override - équivalent, effectivement il n'y a qu'une seule méthode à mettre en œuvre, et donc il n'y a rien à distinguer/choisir.

le compilateur n'a pas à identifier quelle méthode est pour quelle interface, parce qu'une fois qu'ils sont déterminés pour être @Override - équivalent, ils sont la même méthode.

résoudre les incompatibilités potentielles peut être une tâche délicate, mais c'est une autre question tout à fait.

Références

266
répondu polygenelubricants 2010-05-14 08:03:34

en ce qui concerne le compilateur, ces deux méthodes sont identiques. Il y aura une mise en œuvre des deux.

ce n'est pas un problème si les deux méthodes sont effectivement identiques, en ce qu'elles devraient avoir la même mise en œuvre. S'ils sont contractuellement différents (selon la documentation de chaque interface), vous aurez des problèmes.

20
répondu Ash 2010-05-10 10:29:08

il s'agit d'une copie de la question https://stackoverflow.com/questions/24401064/understanding-and-solving-the-diamond-problems-in-java

vous avez besoin de Java 8 pour obtenir un problème d'héritage multiple, mais ce n'est toujours pas un problème de diamon en tant que tel.

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.

comme le commente JB Nizet, vous pouvez corriger cette erreur.

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

Cependant, vous n'avez pas de problème avec

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.
16
répondu Peter Lawrey 2017-05-23 12:18:25

Il n'y a rien à identifier. Les Interfaces ne proscrivent que le nom et la signature d'une méthode. Si les deux interfaces ont une méthode du même nom et de la même signature, la classe implementing peut implémenter les deux méthodes d'interface avec une seule méthode concrète.

cependant, si les contrats sémantique de la méthode des deux interfaces sont en contradiction, vous avez à peu près perdu; vous ne pouvez pas implémenter les deux interfaces dans une seule classe alors.

11
répondu Michael Borgwardt 2010-05-10 10:31:48

essayez d'implémenter l'interface comme anonyme.

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
répondu dcanh121 2011-10-07 00:39:12

comme dans interface,nous déclarons simplement des méthodes, classe de béton qui implémente ces deux interfaces comprend qu'il n'y a qu'une seule méthode(comme vous avez décrit les deux ont le même nom dans le type de retour). donc, il ne devrait pas être un problème avec elle.Vous pourrez définir cette méthode en classe de béton.

mais quand deux interfaces ont une méthode avec le même nom mais le type de retour différent et vous mettez en œuvre deux méthodes dans la classe de béton:

Veuillez regarder ci-dessous le code:

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

quand le compilateur obtient la méthode "public void print ()" il regarde d'abord dans InterfaceA et il l'obtient.Mais il donne quand même erreur de temps de compilation que le type de retour n'est pas compatible avec la méthode D'InterfaceB.

donc ça tourne mal pour le compilateur.

de cette façon, vous ne pourrez pas implémenter deux interfaces ayant une méthode de même nom mais un type de retour différent.

4
répondu Bhagrav Jain 2014-05-07 10:58:01

S'ils sont tous les deux pareils, ça n'a pas d'importance. Il met en œuvre les deux avec une seule méthode de béton par méthode d'interface.

3
répondu Paul Whelan 2010-05-10 10:27:34