In che modo le interfacce Java simulano l’ereditarietà multipla?

Sto leggendo “The Java Tutorial” (per la 2a volta). Ho appena consultato la sezione Interfacce (di nuovo), ma ancora non capisco come le interfacce Java simulino l’ereditarietà multipla. C’è una spiegazione più chiara di quella contenuta nel libro?

Supponi di avere 2 tipi di cose nel tuo dominio: Camion e Cucine

I camion hanno un metodo driveTo () e Kitchens a cook ().

Ora supponiamo che Pauli decida di vendere pizze dal retro di un camion per le consegne. Vuole qualcosa in cui possa guidare () e cucinare () con.

In C ++ userebbe l’ereditarietà multipla per fare ciò.

In Java è stato considerato troppo pericoloso, quindi puoi ereditare da una class principale, ma puoi “ereditare” i comportamenti dalle interfacce, che sono per tutti gli effetti classi astratte senza campi o implementazioni di metodi.

Quindi in Java tendiamo ad implementare l’ereditarietà multipla usando le deleghe:

Pauli sottoclass un camion e aggiunge una cucina al camion in una variabile membro chiamata cucina. Implementa l’interfaccia Kitchen chiamando kitchen.cook ().

class PizzaTruck extends Truck implements Kitchen { Kitchen kitchen; public void cook(Food foodItem) { kitchen.cook(foodItem); } } 

È un uomo felice perché ora può fare cose del genere;

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

Ok, questa stupida storia voleva dire che non si tratta di una simulazione dell’ereditarietà multipla, è una vera eredità multipla a condizione che si possa solo ereditare il contratto, ereditato solo da classi di base astratte vuote che sono chiamate interfacce.

(aggiornamento: con l’avvento dei metodi di default le interfacce ora possono anche fornire alcuni comportamenti da ereditare)

Probabilmente sei confuso perché visualizzi l’ereditarietà multipla localmente, in termini di una class che eredita i dettagli di implementazione da più genitori. Questo non è ansible in Java (e spesso porta ad abusi nelle lingue dove è ansible).

Le interfacce consentono l’ereditarietà multipla di tipi , ad esempio una class Waterfowl extends Bird implements Swimmer può essere utilizzato da altre classi come se fosse un Bird e come se fosse un Swimmer . Questo è il significato più profondo dell’ereditarietà multipla: consentire ad un object di agire come se appartenesse a più classi diverse non correlate contemporaneamente.

Ecco un modo per raggiungere l’ereditarietà multipla attraverso le interfacce in java.

Cosa ottenere?
la class A estende B, C // questo non è ansible direttamente in java ma può essere ottenuto indirettamente.

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

date le due interfacce sotto …

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

Possiamo implementare entrambi usando il codice qui sotto …

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

NON POSSIAMO estendere due oggetti, ma possiamo implementare due interfacce.

Le interfacce non simulano l’ereditarietà multipla. I creatori di Java consideravano errata l’ereditarietà multipla, quindi non c’è nulla di simile in Java.

Se si desidera combinare la funzionalità di due classi in una composizione di oggetti monouso. ie

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

E se si desidera esporre determinati metodi, definirli e consentire loro di debind la chiamata al controller corrispondente.

Qui le interfacce possono tornare utili: se Component1 implementa l’interfaccia Interface1 e Component2 implementa Interface2 , è ansible definire

 class Main implements Interface1, Interface2 

In modo che tu possa usare gli oggetti in modo intercambiabile dove il contesto lo consente.

Sai cosa, venendo dal punto di vista di un dev di JavaScript che sta cercando di capire cosa diavolo sta succedendo con questa roba, mi piacerebbe sottolineare un paio di cose e qualcuno per favore dimmi cosa mi manca qui se sono lontano dal marchio.

Le interfacce sono davvero semplici. Stupidamente, follemente semplice. Sono stupidamente, follemente semplici come le persone inizialmente pensano, motivo per cui ci sono così tante domande duplicate su questo argomento esatto perché l’unica ragione per usarle è stato reso poco chiaro dalle persone che cercano di farne di più rispetto a loro. è un uso diffuso diffuso in ogni code-base Java sul lato server a cui sono mai stato sottoposto.

Quindi, perché vorresti usarli? Il più delle volte non lo faresti. Certamente non vorrai usarli TUTTO il tempo che molti sembrano pensare. Ma prima che arrivi quando vuoi, parliamo di cosa NON sono.

Le interfacce NON sono:

  • in alcun modo una soluzione alternativa per qualsiasi tipo di meccanismo di ereditarietà che manca a Java. Non hanno nulla a che fare con l’ereditarietà, non l’hanno mai fatto e in nessun modo simulano qualcosa di simile all’eredità.
  • necessariamente qualcosa che ti aiuta con le cose che hai scritto, così come aiuta l’altro a scrivere qualcosa che deve essere interfacciato con le tue cose.

Sono davvero semplici come pensi che siano a prima vista. Le persone usano impropriamente stupidamente tutto il tempo quindi è difficile capire quale sia il punto. È solo validazione / test. Una volta che hai scritto qualcosa conforms a un’interfaccia e funziona, rimuovere quel codice “implementa” non infrange nulla.

Ma se stai usando le interfacce in modo corretto, non vorrai rimuoverlo perché averlo lì offre allo sviluppatore successivo uno strumento per scrivere un livello di accesso per un altro insieme di database o servizi web che vogliono che il resto della tua app continui usando perché sanno che la loro class fallirà fino a quando non avranno l’interfaccia completa al 100% come prevista. Tutte le interfacce fanno validare la tua class e stabilire che hai effettivamente implementato un’interfaccia come promesso. Niente di più.

Sono anche portatili. Esponendo le tue definizioni di interfaccia puoi dare alle persone che vogliono usare il tuo codice non esposto un insieme di metodi a cui conformarsi affinché i loro oggetti possano usarlo correttamente. Non devono implementare le interfacce. Potrebbero semplicemente annotarli su un pezzo di carta per appunti e ricontrollarli. Ma con l’interfaccia hai più garanzie che nulla cercherà di funzionare finché non avrà una versione corretta dell’interfaccia in questione.

Quindi, qualsiasi interfaccia non sarà mai implementata più di una volta? Completamente inutile. Multiple-eredità? Smettila di raggiungere quell’arcobaleno. Java li evita per un motivo in primo luogo e gli oggetti composti / aggregati sono comunque più flessibili in molti modi. Questo non vuol dire che le interfacce non possono aiutarti a modellare in modi che l’ereditarietà multipla consente, ma in realtà non è un’eredità in alcun modo forma o forma e non dovrebbe essere vista come tale. Sta solo garantendo che il tuo codice non funzionerà finché non avrai implementato tutti i metodi che hai stabilito.

È piuttosto semplice È ansible implementare più di un’interfaccia in un tipo. Ad esempio, potresti avere un’implementazione di List che è anche un’istanza di Deque (e Java fa … LinkedList ).

Non è ansible ereditare le implementazioni da più genitori (cioè estendere più classi). Le dichiarazioni (firme del metodo) non sono un problema.

Non è una simulazione di eredità multipla. In java non puoi ereditare da due classi, ma se implementi due interfacce “sembra che tu abbia ereditato da due classi diverse” perché puoi usare la tua class come uno qualsiasi dei tuoi due intefacenti.

Per esempio

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

Funzionerà e puoi usare mfi e msi, sembra un’ereditarietà multipla, ma non è perché non erediti nulla, semplicemente riscrivi i metodi pubblici forniti dalle interfacce.

Devi essere preciso:

Java consente l’ereditarietà multipla dell’interfaccia, ma solo l’ereditarietà dell’implementazione.

Esegui l’ereditarietà multipla dell’interfaccia in Java in questo modo:

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

A proposito, il motivo per cui Java non implementa l’ereditarietà multipla completa è perché crea ambiguità. Supponiamo di poter dire “A extends B, C”, e quindi sia B che C hanno una funzione “void f (int)”. Quale implementazione eredita? Con l’approccio di Java, è ansible implementare qualsiasi numero di interfacce, ma le interfacce dichiarano solo una firma. Quindi se due interfacce includono funzioni con la stessa firma, bene, la tua class deve implementare una funzione con quella firma. Se le interfacce che si ereditano hanno funzioni con diverse firme, le funzioni non hanno nulla a che fare l’una con l’altra, quindi non si tratta di un conflitto.

Non sto dicendo che questo è l’unico modo. C ++ implementa la vera ereditarietà multipla stabilendo le regole di precedenza di cui l’implementazione vince. Ma gli autori di Java hanno deciso di eliminare l’ambiguità. Non so se a causa di una convinzione filosofica che ciò sia stato fatto per un codice più pulito, o perché non volessero fare tutto il lavoro extra.

Non è corretto dire che le interfacce “simulano” l’ereditarietà multipla.

Certo, il tuo tipo può implementare più interfacce e agire in modo polimorfico con tanti tipi diversi. Tuttavia, ovviamente non erediterai comportamenti o implementazioni in base a questa disposizione.

In generale, guarda la composizione dove pensi di aver bisogno di più eredità.

OPPURE Una soluzione potenziale per ottenere qualcosa di ereditario multiplo è l’interfaccia Mixin: http://csis.pace.edu/~bergin/patterns/multipleinheritance.html . Usare con cura!

Non lo fanno.

Penso che la confusione derivi da persone che credono che l’implementazione di un’interfaccia costituisca una qualche forma di ereditarietà. Non lo fa; l’implementazione può essere semplicemente vuota, nessun comportamento è forzato dall’atto o garantito attraverso qualsiasi contratto. Un tipico esempio è l’interfaccia Clonable, che allude a molte grandi funzionalità, che definisce così poco che è essenzialmente inutile e potenzialmente pericoloso.

Cosa erediti implementando un’interfaccia? Bubkes! Quindi, secondo me, smetti di usare l’interfaccia e l’ereditarietà delle parole nella stessa frase. Come diceva Michael Borgwardt, un’interfaccia non è una definizione ma un aspetto.

Si può effettivamente “ereditare” da più classi concrete se implementano le interfacce stesse. innerclasss ti aiutano a farlo:

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

Non penso che lo facciano.

L’ereditarietà è specificamente una relazione orientata all’implementazione tra le implementazioni. Le interfacce non forniscono alcuna informazione di implementazione, ma invece definiscono un tipo. Per avere ereditarietà, è necessario ereditare in modo specifico alcuni comportamenti o attributi da una class genitore.

Credo che qui ci sia una domanda specifica sul ruolo delle interfacce e dell’eredità multipla, ma non riesco a trovarlo ora …

Non c’è davvero alcuna simulazione dell’ereditarietà multipla in Java.

Le persone a volte dicono che è ansible simulare l’ereditarietà multipla utilizzando le interfacce perché è ansible implementare più di un’interfaccia per class e quindi utilizzare la composizione (anziché l’ereditarietà) nella class per ottenere i comportamenti delle classi multiple che si tentava di ereditare da iniziare con.

Se ha senso nel modello a oggetti, puoi ovviamente ereditare da una class e implementare anche 1 o più interfacce.

Ci sono casi in cui l’ereditarietà multipla diventa molto utile e difficile da sostituire con le interfacce senza scrivere altro codice. Ad esempio, ci sono app Android che utilizzano classi derivate da Activity e altre da FragmentActivity nella stessa app. Se si dispone di una caratteristica particolare che si desidera condividere in una class comune, in Java sarà necessario duplicare il codice anziché consentire alle classi child di Activity e FragmentsActivity di derivare dalla stessa class SharedFeature. E la scarsa implementazione dei generici in Java non aiuta neanche perché scrivere quanto segue è illegale:

 public class SharedFeature extends  ... ... 

Non c’è supporto per l’ereditarietà multipla in java.

Questa storia di supporto dell’ereditarietà multipla tramite l’interfaccia è ciò che abbiamo sviluppato dagli sviluppatori. L’interfaccia offre flessibilità rispetto alle classi concrete e abbiamo la possibilità di implementare più interfacce utilizzando una singola class. Questo è un accordo che stiamo aderendo a due progetti per creare una class.

Questo sta cercando di avvicinarsi all’ereditarietà multipla. Quello che facciamo è implementare un’interfaccia multipla, qui non stiamo estendendo (ereditando) nulla. La class di implementazione è quella che aggiungerà proprietà e comportamento. Non sta ottenendo l’implementazione libera dalle classi genitore. Vorrei semplicemente dire che non c’è supporto per l’ereditarietà multipla in java.

Mi piacerebbe sottolineare qualcosa che mi ha un po ‘preso da dietro, proveniente dal C ++, dove puoi facilmente ereditare anche molte implementazioni.

Avere un’interfaccia “ampia” con molti metodi significa che dovrai implementare molti metodi nelle tue lezioni concrete e non puoi condividerli facilmente attraverso le implementazioni.

Per esempio:

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

In questo esempio, Fox e Bear non possono condividere un’implementazione di base comune per entrambi i suoi metodi di interfaccia munch e devour .

Se le implementazioni di base sono simili, vorremmo forse usarle per Fox e Bear :

 class ForestHerbivore implements Herbivore void munch(Vegetable v) { ... } }; class ForestCarnivore implements Carnivore void devour(Prey p) { ... } }; 

Ma non possiamo ereditarli entrambi. Le implementazioni di base devono essere variabili membro nella class e i metodi definiti possono inoltrarle. Vale a 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); } } 

Questo diventa ingombrante se le interfacce crescono (ovvero più di 5-10 metodi …)

Un approccio migliore consiste nel definire un’interfaccia come un’aggregazione di interfacce:

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

Ciò significa che Fox e Bear devono solo implementare questi due metodi e che le interfacce e le classi di base possono crescere indipendentemente AllEater interfaccia di AllEater che riguarda le classi di implementazione.

Meno accoppiamento in questo modo, se funziona per la tua app.

No, Java non supporta l’ereditarietà multipla. Né utilizzando la class né utilizzando l’interfaccia. Fare riferimento a questo link per maggiori informazioni https://devsuyed.wordpress.com/2016/07/21/does-java-support-multiple-inheritance

Devo anche dire che Java non supporta l’ereditarietà multipla.

Devi differenziare il significato tra extends e implements parole chiave in Java. Se usiamo extends , stiamo effettivamente ereditando la class dopo quella parola chiave. Ma, per rendere tutto semplice, non possiamo usare extends più di una volta. Ma puoi implementare tutte le interfacce che desideri.

Se si implementa un’interfaccia, c’è una probabilità zero che manchi l’implementazione di tutti i metodi in ogni interfaccia (Eccezione: implementazioni predefinite dei metodi di interfaccia introdotte in Java 8) Quindi, ora sei pienamente consapevole di ciò che sta accadendo con le cose che hai incorporato nella tua nuova class.

Perché Java non consente l’ereditarietà multipla, l’ereditarietà multipla rende il codice piuttosto complesso. A volte, due metodi di classi parent potrebbero essere in conflitto a causa della presenza delle stesse firme. Ma se sei costretto ad implementare tutti i metodi manualmente, avrai la piena comprensione di quello che sta succedendo, come ho detto sopra. Rende il tuo codice più comprensibile a te.

Se hai bisogno di maggiori informazioni sulle interfacce Java, consulta questo articolo, http://www.geek-programmer.com/introduction-to-java-interfaces/