web-dev-qa-db-fra.com

Comment les interfaces Java simulent-elles l'héritage multiple?

Je lis "Le Java Tutorial" (pour la deuxième fois). Je viens tout juste de passer à travers la section sur les interfaces, mais je ne comprends toujours pas comment Java Interfaces simule un héritage multiple. Y a-t-il une explication plus claire que ce qui est dans le livre?

74
jacknad

Supposons que vous ayez 2 types d'objets dans votre domaine: les camions et les cuisines

Les camions ont une méthode driveTo () et Kitchens une méthode cook ().

Supposons maintenant que Pauli décide de vendre des pizzas à l’arrière d’un camion de livraison. Il veut une chose où il peut conduire () et cuisiner () avec.

En C++, il utilisait plusieurs héritages pour le faire.

Dans Java qui était considéré trop dangereux, vous pouvez donc hériter d'une classe principale, mais vous pouvez "hériter" des comportements d'interfaces, qui sont à toutes fins utiles des classes abstraites sans champs ni implémentations de méthodes.

Donc dans Java nous avons tendance à implémenter l'héritage multiple en utilisant des délégations:

Pauli classe un camion et ajoute une cuisine au camion dans une variable de membre appelée cuisine. Il implémente l'interface Cuisine en appelant kitchen.cook ().

class PizzaTruck extends Truck implements Kitchen {
   Kitchen kitchen;

   public void cook(Food foodItem) {
      kitchen.cook(foodItem);
   }
}

C'est un homme heureux parce qu'il peut maintenant faire des choses comme;

pizzaTruck.driveTo(beach);
pizzaTruck.cook(pizzaWithExtraAnchovies);

Ok, cette histoire idiote voulait faire comprendre qu’il ne s’agissait pas d’une simulation d’héritage multiple, c’était un héritage multiple réel, à condition que vous ne puissiez hériter que du contrat, hériter uniquement des classes de base abstraites vides appelées interfaces.

(mise à jour: avec l'arrivée de interfaces de méthodes par défaut maintenant peut également fournir un comportement à hériter)

150
Peter Tillemans

Vous êtes probablement dérouté parce que vous visualisez plusieurs héritages localement, en termes de classe héritant des détails d'implémentation de plusieurs parents. Ceci n'est pas possible dans Java (et conduit souvent à des abus dans les langages lorsque cela est possible).

Les interfaces permettent un héritage multiple de types, par exemple. une class Waterfowl extends Bird implements Swimmer peut être utilisé par d'autres classes comme s'il s'agissait de Birdet comme s'il s'agissait de Swimmer. C’est la signification la plus profonde de l’héritage multiple: permettre à un objet d’agir comme s’il appartenait à plusieurs classes différentes non liées à la fois.

18
Michael Borgwardt

Voici un moyen de réaliser plusieurs héritages via des interfaces en Java.

Que faire?
la classe A étend B, C // ceci n'est pas possible dans Java directement mais peut être réalisé indirectement.

class B{
   public void getValueB(){}
}

class C{
   public void getValueC(){}
}


interface cInterface{
   public getValueC();
}

class cChild extends C implemets cInterface{
    public getValueC(){

      // implementation goes here, call the super class's getValueC();

    }
}


// Below code is **like** class A extends B, C 
class A extends B implements cInterface{
   cInterface child =  new cChild();
   child.getValueC();
}
16
challenger

compte tenu des deux interfaces ci-dessous ...

interface I1 {
  abstract void test(int i);
}
interface I2 {
  abstract void test(String s);
}

Nous pouvons implémenter les deux en utilisant le code ci-dessous ...

public class MultInterfaces implements I1, I2 {
  public void test(int i) {
    System.out.println("In MultInterfaces.I1.test");
  }
  public void test(String s) {
    System.out.println("In MultInterfaces.I2.test");
  }
  public static void main(String[] a) {
    MultInterfaces t = new MultInterfaces();
    t.test(42);
    t.test("Hello");
  }
}

Nous NE POUVONS PAS étendre deux objets, mais nous pouvons implémenter deux interfaces.

10
david99world

Les interfaces ne simulent pas plusieurs héritages. Java ont considéré que l'héritage multiple était erroné, il n'y a donc rien de tel en Java.).

Si vous souhaitez combiner les fonctionnalités de deux classes en une composition d’objets à usage unique. C'est à dire.

public class Main {
    private Component1 component1 = new Component1();    
    private Component2 component2 = new Component2();
}

Et si vous souhaitez exposer certaines méthodes, définissez-les et laissez-les déléguer l'appel à l'automate correspondant.

Ici, les interfaces peuvent être utiles - si Component1 implémente l'interface Interface1 et Component2 met en oeuvre Interface2, vous pouvez définir

class Main implements Interface1, Interface2

Vous pouvez donc utiliser des objets de façon interchangeable lorsque le contexte le permet.

10
Bozho

Vous savez quoi, du point de vue d'un développeur JavaScript essayant de comprendre ce qui se passe avec ce genre de choses, j'aimerais souligner quelques points et quelqu'un s'il vous plaît dites-moi ce que je manque ici loin du but.

Les interfaces sont vraiment simples. Stupidement, incroyablement simple. Elles sont aussi bêtement, incroyablement simples qu'on le pensait au départ. C’est la raison pour laquelle il ya tant de questions en double sur ce sujet précis, parce que la seule raison de les utiliser a été rendue floue par des personnes qui essayaient d’en faire plus qu’elles ne le sont et est généralement utilisé de manière abusive dans chaque Java code-base côté serveur auquel j'ai été exposé).

Alors, pourquoi voudriez-vous les utiliser? La plupart du temps, vous ne le feriez pas. Vous ne voudriez certainement pas les utiliser TOUT le temps que beaucoup semblent le penser. Mais avant d’arriver à ce moment-là, parlons de ce qu’ils ne sont PAS.

Les interfaces ne sont PAS:

  • en aucune façon une solution de contournement pour tout type de mécanisme d'héritage qui manque à Java. Ils n'ont rien à voir avec l'héritage, ils ne l'ont jamais fait, et ne simulent en aucune manière un héritage similaire.
  • nécessairement quelque chose qui vous aide avec les choses que vous avez écrites, autant que cela aide l'autre gars à écrire quelque chose qui est destiné à être interfacé avec vos affaires.

Ils sont vraiment aussi simples que vous pensez qu'ils sont à première vue. Les gens en abusent bêtement tout le temps, alors il est difficile de comprendre ce qui se passe. C'est juste validation/test. Une fois que vous avez écrit quelque chose qui est conforme à une interface et qui fonctionne, la suppression de ce code "implémenté" ne casse rien.

Toutefois, si vous utilisez correctement les interfaces, vous ne voudrez plus les supprimer, car elles permettent au développeur suivant d’écrire une couche d’accès pour un autre ensemble de bases de données ou de services Web qu’ils souhaitent que le reste de votre application continue. en utilisant parce qu'ils savent que leur classe échouera jusqu'à ce qu'ils obtiennent l'interface 100% complète comme prévu. Toutes les interfaces valident votre classe et établissent que vous avez en fait implémenté une interface comme vous l’aviez promis. Rien de plus.

Ils sont également portables. En exposant vos définitions d'interface, vous pouvez donner aux personnes souhaitant utiliser votre code non exposé un ensemble de méthodes auxquelles se conformer afin que leurs objets puissent l'utiliser correctement. Ils n'ont pas à implémenter les interfaces. Ils pourraient simplement les noter sur un morceau de papier et les vérifier. Mais avec l'interface, vous avez plus de garantie que rien ne va essayer de fonctionner jusqu'à ce qu'il ait une version correcte de l'interface en question.

Donc, une interface qui ne sera probablement jamais implémentée plus d’une fois? Totalement inutile. Héritage multiple? Arrêtez de chercher cet arc-en-ciel. Java les évite pour une raison en premier lieu et les objets composites/agrégés sont beaucoup plus souples de toute façon. Cela ne veut pas dire que les interfaces ne peuvent pas vous aider à modéliser L'héritage le permet, mais il ne s'agit en aucun cas d'un héritage et ne doit pas être perçu comme tel, il garantit simplement que votre code ne fonctionnera pas tant que vous ne aurez pas implémenté toutes les méthodes que vous avez établies.

6
Erik Reppen

C'est assez simple. Vous pouvez implémenter plusieurs interfaces dans un type. Ainsi, par exemple, vous pourriez avoir une implémentation de List qui est aussi une instance de Deque (et Java fait ...LinkedList ).

Vous ne pouvez pas hériter de implémentations de plusieurs parents (c'est-à-dire étendre plusieurs classes). Déclarations (signatures de méthode) ne posent aucun problème.

5
Mark Peters

Ce n'est pas une simulation d'héritage multiple. Dans Java, vous ne pouvez pas hériter de deux classes, mais si vous implémentez deux interfaces, "il semble que vous ayez hérité de deux classes différentes", car vous pouvez utiliser votre classe comme n'importe laquelle de vos deux interfaces.

Par exemple

interface MyFirstInteface{
    void method1();
}
interface MySecondInteface{
    void method2();
}
class MyClass implements MyFirstInteface, MySecondInteface{
    public void method1(){
        //Method 1
    }
    public void method2(){
        //Method 2
    }

    public static void main(String... args){
        MyFirstInterface mfi = new MyClass();
        MySecondInterface msi = new MyClass();
    }
}

Cela fonctionnera et vous pourrez utiliser mfi et msi, cela ressemble à un héritage multiple, mais ce n’est pas parce que vous n’héritez rien, vous réécrivez simplement les méthodes publiques fournies par les interfaces.

3
Colin Hebert

Vous devez être précis:

Java permet un héritage multiple d'interface, mais un seul héritage d'implémentation.

Vous faites plusieurs héritages d'interface dans Java comme ceci:

public interface Foo
{
    String getX(); 
}

public interface Bar
{
    String getY();
}

public class MultipleInterfaces implements Foo, Bar
{
    private Foo foo;
    private Bar bar;

    public MultipleInterfaces(Foo foo, Bar bar)
    {
        this.foo = foo;
        this.bar = bar;
    }

    public String getX() { return this.foo.getX(); }
    public String getY() { return this.bar.getY(); }
}
3
duffymo

En passant, la raison pour laquelle Java n'implémente pas l'héritage multiple complet, c'est parce qu'il crée des ambiguïtés. Supposons que vous puissiez dire "A étend B, C", puis les deux, B et C, ont fonction "void f (int)". De quelle implémentation hérite-t-elle? Avec l'approche de Java, vous pouvez implémenter un nombre illimité d'interfaces, mais les interfaces ne déclarent qu'une signature. Ainsi, si deux interfaces incluent des fonctions avec la même signature, très bien, votre classe doit implémenter une fonction avec cette signature Si les interfaces dont vous héritez ont des fonctions avec des signatures différentes, celles-ci n'ont alors rien à voir les unes avec les autres, il n'y a donc aucun problème de conflit.

Je ne dis pas que c'est le seul moyen. C++ implémente le véritable héritage multiple en établissant des règles de priorité dont l'implémentation est gagnante. Mais les auteurs de Java ont décidé d'éliminer l'ambiguïté. Que ce soit pour une conviction philosophique voulant un code plus propre, ou parce qu'ils ne voulaient pas faire tout le travail supplémentaire, je ne le fais pas. t sais.

3
Jay

Je voudrais signaler quelque chose qui m’a mordu dans le dos, venant du C++ où vous pouvez facilement hériter de nombreuses implémentations.

Avoir une interface "large" avec de nombreuses méthodes signifie que vous devrez implémenter beaucoup de méthodes dans vos classes concrètes et vous ne pouvez pas les partager facilement à travers les implémentations.

Par exemple:

interface Herbivore {
    void munch(Vegetable v);
};

interface Carnivore {
    void devour(Prey p);
}

interface AllEater : public Herbivore, Carnivore { };

class Fox implements AllEater {
   ... 
};

class Bear implements AllEater {
   ...
};

Dans cet exemple, Fox et Bear ne peuvent pas partager une implémentation de base commune pour ses méthodes d'interface munch et devour.

Si les implémentations de base ressemblent à ceci, nous voudrions peut-être les utiliser pour Fox et Bear:

class ForestHerbivore implements Herbivore
    void munch(Vegetable v) { ... }
};

class ForestCarnivore implements Carnivore
    void devour(Prey p) { ... }
};

Mais nous ne pouvons pas hériter des deux. Les implémentations de base doivent être des variables membres de la classe et les méthodes définies peuvent les transmettre. C'est à dire:

class Fox implements AllEater {
    private ForestHerbivore m_herbivore;
    private ForestCarnivore m_carnivore;

    void munch(Vegetable v) { m_herbivore.munch(v); }
    void devour(Prey p) { m_carnivore.devour(p); }
}

Cela devient difficile si les interfaces se développent (c'est-à-dire plus de 5 à 10 méthodes ...)

Une meilleure approche consiste à définir une interface comme une agrégation d’interfaces:

interface AllEater {
    Herbivore asHerbivore();
    Carnivore asCarnivore();
}

Cela signifie que Fox et Bear ne doivent implémenter que ces deux méthodes, et que les interfaces et les classes de base peuvent se développer indépendamment de l'interface d'agrégat AllEater qui concerne les classes implémentées.

Moins de couplage de cette façon, si cela fonctionne pour votre application.

2
Macke

Vous pouvez réellement "hériter" de plusieurs classes concrètes si elles implémentent des interfaces elles-mêmes. innerclasses vous aider à atteindre cet objectif:

interface IBird {
    public void layEgg();
}

interface IMammal {
    public void giveMilk();
}

class Bird implements IBird{
    public void layEgg() {
        System.out.println("Laying eggs...");
    }
}

class Mammal implements IMammal {
    public void giveMilk() {
        System.out.println("Giving milk...");
    }
}

class Platypus implements IMammal, IBird {

    private class LayingEggAnimal extends Bird {}
    private class GivingMilkAnimal extends Mammal {}

    private LayingEggAnimal layingEggAnimal = new LayingEggAnimal();

    private GivingMilkAnimal givingMilkAnimal = new GivingMilkAnimal();

    @Override
    public void layEgg() {
        layingEggAnimal.layEgg();
    }

    @Override
    public void giveMilk() {
        givingMilkAnimal.giveMilk();
    }

}
</ code>
2
SHOJAEI BAGHINI

Il n'est pas juste de dire que les interfaces "simulent" l'héritage multiple.

Bien sûr, votre type peut implémenter plusieurs interfaces et agir comme autant de types différents polymorphiquement. Cependant, vous n'hériterez évidemment pas du comportement ou des implémentations dans cet arrangement.

Regardez généralement la composition où vous pensez avoir besoin d'un héritage multiple.

OU Une solution potentielle pour obtenir quelque chose comme l'héritage multiple est l'interface Mixin - http://csis.pace.edu/~bergin/patterns/multipleinheritance.html . A utiliser avec précaution!

2
Benjamin Wootton

Ils ne le font pas.

Je pense que la confusion vient de personnes qui croient que la mise en place d'une interface constitue une forme d'héritage. Ce n'est pas; la mise en œuvre peut simplement être vide, aucun comportement n'est forcé par l'acte ni garanti par aucun contrat. Un exemple typique est l'interface Clonable, qui, tout en faisant allusion à de nombreuses fonctionnalités exceptionnelles, définit si peu que c'est essentiellement inutile et potentiellement dangereux.

De quoi héritez-vous en mettant en place une interface? Bubkes! Donc, à mon avis, arrêtez d'utiliser les mots interface et héritage dans la même phrase. Comme Michael Borgwardt l’a dit, une interface n’est pas une définition mais un aspect.

2
mikek

Non, Java ne prend pas en charge l'héritage multiple. N'utilise ni la classe ni l'interface. Reportez-vous à ce lien pour plus d'informations https://devsuyed.wordpress.com/2016/07/ 21/ne-Java-support-multiple-héritage

1
Suyed Dalvi

Je ne pense pas qu'ils font.

L'héritage est spécifiquement une relation d'implémentation entre implémentations. Les interfaces ne fournissent aucune information d'implémentation, mais définissent plutôt un type. Pour avoir un héritage, vous devez hériter spécifiquement de certains comportements ou attributs d'une classe parent.

Je crois qu'il y a une question ici quelque part spécifiquement sur le rôle des interfaces et de l'héritage multiple, mais je ne le trouve pas maintenant ...

1
Thomas Owens

Il n'y a pas de support pour l'héritage multiple en Java.

Cette histoire de prise en charge de plusieurs héritages à l'aide d'une interface est ce que nous avons concocté. L'interface offre plus de flexibilité que les classes concrètes et nous avons la possibilité d'implémenter plusieurs interfaces en utilisant une seule classe. C’est par accord que nous adhérons à deux plans pour créer une classe.

C'est essayer de se rapprocher de l'héritage multiple. Ce que nous faisons est d’implémenter une interface multiple, ici nous n’allons rien étendre (hériter). La classe d'implémentation est celle qui va ajouter les propriétés et le comportement. Il ne s'agit pas de libérer l'implémentation des classes parentes. Je dirais simplement qu'il n'y a pas de support pour l'héritage multiple en Java.

1
Vivek Sadh

Il n'y a vraiment pas de simulation d'héritage multiple en Java.

Les gens diront parfois que vous pouvez simuler plusieurs héritages à l'aide d'interfaces, car vous pouvez implémenter plus d'une interface par classe, puis utiliser la composition (plutôt que l'héritage) dans votre classe pour obtenir les comportements des multiples classes dont vous vouliez hériter. pour commencer.

1
Justin Niessner

Il existe des cas où l'héritage multiple s'avère très pratique et difficile à remplacer par des interfaces sans écrire plus de code. Par exemple, il existe Android des applications qui utilisent des classes dérivées de Activity et d’autres de FragmentActivity dans la même application. Si vous souhaitez partager une fonctionnalité particulière dans une classe commune, dans Java vous devrez dupliquer le code au lieu de laisser les classes enfant d’Activity et FragmentsActivity dériver de la même classe SharedFeature. Et la mauvaise implémentation des génériques dans Java n’aide pas soit parce qu'écrire ce qui suit est illégal:

public class SharedFeature<T> extends <T extends Activity>

...
...
1
Sergiob

Je dois aussi dire que Java ne supporte pas l'héritage multiple.

Vous devez différencier la signification entre les mots-clés extends et implements en Java. Si nous utilisons extends, nous hériterons de la classe après ce mot clé. Mais, pour simplifier les choses, nous ne pouvons pas utiliser extends plus d'une fois. Mais vous pouvez implémenter autant d'interfaces que vous le souhaitez.

Si vous implémentez une interface, vous n'aurez aucune chance de manquer l'implémentation de toutes les méthodes de chaque interface (Exception: implémentations par défaut des méthodes d'interface introduites dans Java 8). Vous êtes maintenant pleinement conscient de ce qui se passe avec les choses que vous avez intégrées à votre nouvelle classe.

Pourquoi Java n'autorise pas l'héritage multiple, c’est en fait un héritage multiple qui rend le code assez complexe. Parfois, deux méthodes de classes parents peuvent entrer en conflit car elles ont les mêmes signatures. Mais si vous êtes obligé de Si vous implémentez toutes les méthodes manuellement, vous comprendrez parfaitement ce qui se passe, comme je l’ai mentionné plus haut, ce qui rend votre code plus compréhensible.

Si vous avez besoin de plus d’informations sur les interfaces Java, consultez cet article, http://www.geek-programmer.com/introduction-to-Java-interfaces/

1
user7338196

Si cela se justifie dans votre modèle objet, vous pouvez bien entendu hériter d'une classe et implémenter une ou plusieurs interfaces.

1
Benjamin Wootton