Perché non c'è ereditarietà multipla in Java, ma è consentita l'implementazione di più interfacce?


153

Java non consente l'ereditarietà multipla, ma consente l'implementazione di più interfacce. Perché?


1
Ho modificato il titolo della domanda per renderlo più descrittivo.
Bozho,

4
È interessante notare che nel JDK 8 ci saranno metodi di estensione che consentiranno la definizione di implementazione di metodi di interfaccia. Le regole sono state definite per governare l'eredità multipla del comportamento, ma non dello stato (che capisco è più problematico .
Edwin Dalorzo,

1
Prima che voi ragazzi perdiate tempo in risposte che vi dicono solo "Come java ottiene l'eredità multipla" ... Vi consiglio di andare alla risposta di @Prabal Srivastava che logicamente vi dà ciò che deve accadere internamente, per non consentire alle classi questo diritto ... e consentire solo alle interfacce il diritto di consentire l'ereditarietà multipla.
Yo Apps,

Risposte:


228

Perché le interfacce specificano solo cosa sta facendo la classe, non come la sta facendo.

Il problema con l'ereditarietà multipla è che due classi possono definire modi diversi di fare la stessa cosa e la sottoclasse non può scegliere quale scegliere.


8
Facevo C ++ e ho riscontrato lo stesso identico problema un paio di volte. Di recente ho letto che Scala ha dei "tratti" che a me sembrano qualcosa tra il modo "C ++" e il modo "Java" di fare le cose.
Niels Basjes,

2
In questo modo, stai evitando il "problema del diamante": en.wikipedia.org/wiki/Diamond_problem#The_diamond_problem
Nick L.

6
Da Java 8 è possibile definire due metodi predefiniti identici, uno in ciascuna interfaccia. Se implementerai entrambe le interfacce nella tua classe, devi sovrascrivere questo metodo nella classe stessa, vedi: docs.oracle.com/javase/tutorial/java/IandI/…
bobbel

6
Questa risposta non è precisa Il problema non è specificare come e Java 8 è lì per dimostrare. In Java 8, due super interfacce possono dichiarare lo stesso metodo con implementazioni diverse, ma questo non è un problema perché i metodi di interfaccia sono virtuali , quindi puoi semplicemente sovrascriverli e il problema è risolto. Il vero problema riguarda l' ambiguità negli attributi , perché non è possibile risolvere questa ambiguità sovrascrivendo l'attributo (gli attributi non sono virtuali).
Alex Oliveira,

1
Cosa intendi con "attributi"?
Bozho,

96

Uno dei miei istruttori del college me lo ha spiegato in questo modo:

Supponiamo che io abbia una classe, che è un tostapane, e un'altra classe, che è NuclearBomb. Entrambi potrebbero avere un'ambientazione "oscura". Entrambi hanno un metodo on (). (Uno ha un off (), l'altro no.) Se voglio creare una classe che è una sottoclasse di entrambi ... come puoi vedere, questo è un problema che potrebbe davvero esplodere in faccia qui .

Quindi uno dei problemi principali è che se hai due classi genitore, potrebbero avere implementazioni diverse della stessa funzione - o forse due caratteristiche diverse con lo stesso nome, come nell'esempio del mio istruttore. Quindi devi occuparti di decidere quale verrà utilizzata dalla tua sottoclasse. Esistono modi per gestirlo, certamente - C ++ lo fa - ma i progettisti di Java ritengono che ciò renderebbe le cose troppo complicate.

Con un'interfaccia, tuttavia, stai descrivendo qualcosa che la classe è in grado di fare, piuttosto che prendere in prestito il metodo di un'altra classe per fare qualcosa. Interfacce multiple hanno molte meno probabilità di causare conflitti delicati che devono essere risolti rispetto a più classi principali.


5
Grazie, NomeN. La fonte della citazione era uno studente di dottorato di nome Brendan Burns, che all'epoca era anche il manutentore del repository open source di Quake 2. Vai a capire.
Sintattica il

4
Il problema con questa analogia è che se si crea una sottoclasse di una bomba nucleare e un tostapane, il "tostapane nucleare" esploderebbe ragionevolmente quando viene utilizzato.
101100

20
Se qualcuno decide di mescolare una bomba nucleare e un tostapane, si merita che la bomba esploda in faccia. La citazione è un ragionamento fallace
masoud

1
Lo stesso linguaggio di programmazione consente l'ereditarietà multipla "interfaccia", quindi questa "giustificazione" non si applica.
curioso

24

Poiché l'ereditarietà è abusata anche quando non si può dire "ehi, quel metodo sembra utile, estenderò anche quella classe".

public class MyGodClass extends AppDomainObject, HttpServlet, MouseAdapter, 
             AbstractTableModel, AbstractListModel, AbstractList, AbstractMap, ...

Puoi spiegare perché dici che l'eredità è abusata? Creare una classe divina è esattamente quello che voglio fare! Trovo così tante persone che lavorano attorno alla singola eredità creando classi "Strumenti" che hanno metodi statici.
Duncan Calvert,

9
@DuncanCalvert: No, non vuoi farlo, non se quel codice avrà mai bisogno di manutenzione. Molti metodi statici mancano il punto di OO, ma l'eccessiva ereditarietà multipla è molto peggio perché si perde completamente la traccia di quale codice viene utilizzato dove, così come concettualmente una classe. Entrambi stanno cercando di risolvere il problema di "come posso usare questo codice dove ne ho bisogno", ma questo è un semplice problema a breve termine. Il problema a lungo termine molto più difficile risolto dalla corretta progettazione OO è "come posso cambiare questo codice senza che il programma si interrompa in 20 posti diversi in modi imprevedibili?
Michael Borgwardt,

2
@DuncanCalvert: e lo risolvi avendo classi con alta coesione e basso accoppiamento, il che significa che contengono pezzi di dati e codice che interagiscono intensamente tra loro, ma interagiscono con il resto del programma solo attraverso una piccola e semplice API pubblica. Quindi puoi pensarci in termini di quell'API anziché dei dettagli interni, il che è importante perché le persone possono tenere a mente solo una quantità limitata di dettagli allo stesso tempo.
Michael Borgwardt,

18

La risposta a questa domanda sta nel funzionamento interno del compilatore Java (concatenamento del costruttore). Se vediamo il funzionamento interno del compilatore Java:

public class Bank {
  public void printBankBalance(){
    System.out.println("10k");
  }
}
class SBI extends Bank{
 public void printBankBalance(){
    System.out.println("20k");
  }
}

Dopo aver compilato questo aspetto come:

public class Bank {
  public Bank(){
   super();
  }
  public void printBankBalance(){
    System.out.println("10k");
  }
}
class SBI extends Bank {
 SBI(){
   super();
 }
 public void printBankBalance(){
    System.out.println("20k");
  }
}

quando estendiamo la classe e ne creiamo un oggetto, una catena di costruttori funzionerà fino alla Objectclasse.

Il codice sopra funzionerà bene. ma se abbiamo un'altra classe chiamata Carche si estende Banke una classe ibrida (eredità multipla) chiamata SBICar:

class Car extends Bank {
  Car() {
    super();
  }
  public void run(){
    System.out.println("99Km/h");
  }
}
class SBICar extends Bank, Car {
  SBICar() {
    super(); //NOTE: compile time ambiguity.
  }
  public void run() {
    System.out.println("99Km/h");
  }
  public void printBankBalance(){
    System.out.println("20k");
  }
}

In questo caso (SBICar) non riuscirà a creare la catena di costruzione ( compilazione dell'ambiguità temporale ).

Per le interfacce questo è permesso perché non possiamo crearne un oggetto.

Per i nuovi concetti defaulte staticmetodi, si prega di fare riferimento a default nell'interfaccia .

Spero che questo risolva la tua domanda. Grazie.


7

L'implementazione di più interfacce è molto utile e non causa molti problemi agli implementatori di linguaggio né ai programmatori. Quindi è permesso. L'eredità multipla, sebbene utile, può causare seri problemi agli utenti (temuto diamante della morte ). E la maggior parte delle cose che fai con l'ereditarietà multipla può essere fatta anche dalla composizione o usando le classi interne. Quindi l'eredità multipla è vietata perché porta più problemi che guadagni.


Qual è il problema con il "diamante della morte"?
curioso

2
@curiousguy Contenente più di un oggetto secondario della stessa classe base, ambiguità (sostituzione da cui viene utilizzata la classe base), regole complicate per risolvere tale ambiguità.
Tadeusz Kopec

@curiousguy: se un framework prevede che il cast di un riferimento a un oggetto a un riferimento di tipo base preservi l'identità, ogni istanza di oggetto deve avere esattamente un'implementazione di qualsiasi metodo di classe base. Se ToyotaCare HybridCarsia derivato da Care sovrascritto Car.Drive, e se PriusCarereditato da entrambi ma non sovrascrittoDrive , il sistema non avrebbe modo di identificare cosa Car.Drivedovrebbe fare il virtuale . Le interfacce evitano questo problema evitando la condizione in corsivo sopra.
supercat,

1
@supercat "il sistema non avrebbe modo di identificare cosa dovrebbe fare Car.Drive virtuale". <- Oppure potrebbe semplicemente dare un errore di compilazione e farti scegliere esplicitamente, come fa C ++.
Chris Middleton,

1
@ChrisMiddleton: un metodo void UseCar(Car &foo); non si può pretendere di includere disambiguazione tra il ToyotaCar::Drivee HybridCar::Drive(in quanto dovrebbe spesso né sapere, né la cura che anche gli altri tipi esistono ). Un linguaggio potrebbe, come fa C ++, richiedere quel codice con il ToyotaCar &myCardesiderio di passarlo a UseCardeve prima trasmettere a uno HybridCaro ToyotaCar, ma poiché ((Auto) (HybridCar) myCar). Guidare` e ((Car)(ToyotaCar)myCar).Drive farebbe cose diverse, ciò implicherebbe che gli upcasts non preservavano l'identità.
supercat

6

Puoi trovare una risposta precisa a questa domanda nella pagina della documentazione di Oracle relativa all'eredità multipla

  1. Eredità multipla di stato: possibilità di ereditare campi da più classi

    Uno dei motivi per cui il linguaggio di programmazione Java non consente di estendere più di una classe è quello di evitare i problemi di eredità multipla di stato, che è la capacità di ereditare campi da più classi

    Se l'ereditarietà multipla è consentita e quando si crea un oggetto creando un'istanza di quella classe, quell'oggetto erediterà i campi da tutte le superclassi della classe. Causerà due problemi.

    1. E se metodi o costruttori di diverse superclasse istanziano lo stesso campo?
    2. Quale metodo o costruttore avrà la precedenza?
  2. Eredità multipla dell'implementazione: possibilità di ereditare le definizioni dei metodi da più classi

    Problemi con questo approccio: denominare conflitti e ambiguità . Se una sottoclasse e una superclasse contengono lo stesso nome di metodo (e firma), il compilatore non può determinare quale versione richiamare.

    Ma Java supporta questo tipo di ereditarietà multipla con metodi predefiniti , introdotti dalla versione Java 8. Il compilatore Java fornisce alcune regole per determinare quale metodo predefinito utilizza una determinata classe.

    Fare riferimento al seguente post SE per maggiori dettagli sulla risoluzione del problema dei diamanti:

    Quali sono le differenze tra classi astratte e interfacce in Java 8?

  3. Eredità multipla di tipo: capacità di una classe di implementare più di un'interfaccia.

    Poiché l'interfaccia non contiene campi mutabili, non è necessario preoccuparsi dei problemi derivanti dall'eredità multipla dello stato qui.



4

Java supporta l'ereditarietà multipla solo attraverso le interfacce. Una classe può implementare un numero qualsiasi di interfacce ma può estendere solo una classe.

L'ereditarietà multipla non è supportata perché porta a un problema mortale con il diamante. Tuttavia, può essere risolto ma porta a un sistema complesso, quindi l'ereditarietà multipla è stata abbandonata dai fondatori Java.

In un white paper intitolato "Java: an Overview" di James Gosling nel febbraio 1995 ( link ), viene fornita un'idea del perché l'ereditarietà multipla non è supportata in Java.

Secondo Gosling:

"JAVA omette molte funzionalità poco utilizzate, poco comprese e confuse di C ++ che nella nostra esperienza portano più dolore che beneficio. Ciò consiste principalmente nel sovraccarico dell'operatore (sebbene abbia un sovraccarico del metodo), eredità multipla e ampie coercizioni automatiche".


il collegamento non è accessibile. Si prega di controllare e aggiornarlo.
MashukKhan,

3

Per lo stesso motivo C # non consente l'ereditarietà multipla ma consente di implementare più interfacce.

La lezione appresa dal C ++ con ereditarietà multipla è stata che ha portato a più problemi di quanti ne valesse la pena.

Un'interfaccia è un contratto di cose che la tua classe deve implementare. Non ottieni alcuna funzionalità dall'interfaccia. L'ereditarietà ti consente di ereditare la funzionalità di una classe genitore (e in ereditarietà multipla, che può diventare estremamente confusa).

Consentire interfacce multiple consente di utilizzare i modelli di progettazione (come l'adattatore) per risolvere gli stessi tipi di problemi che è possibile risolvere utilizzando l'ereditarietà multipla, ma in modo molto più affidabile e prevedibile.


10
C # non ha ereditarietà multiple proprio perché Java non lo consente. È stato progettato molto più tardi di Java. Il problema principale con l'ereditarietà multipla credo sia stato il modo in cui alle persone veniva insegnato a usarlo a destra ea sinistra. Il concetto secondo cui la delega nella maggior parte dei casi è un'alternativa molto migliore non esisteva all'inizio e alla metà degli anni Novanta. Quindi ricordo esempi, nei libri di testo, quando Car è una ruota, una porta e un parabrezza, mentre la macchina contiene ruote, porte e parabrezza. Quindi la singola eredità in Java fu una reazione istintiva a quella realtà.
Alexander Pogrebnyak,

2
@AlexanderPogrebnyak: scegli due dei tre seguenti: (1) Consenti cast che preservano l'identità da un riferimento di sottotipo a un riferimento di supertipo; (2) consentire a una classe di aggiungere membri pubblici virtuali senza ricompilare le classi derivate; (3) Consentire a una classe di ereditare implicitamente membri virtuali da più classi di base senza doverli specificare esplicitamente. Non credo sia possibile per nessuna lingua gestire tutte e tre le precedenti. Java ha optato per # 1 e # 2 e C # ha seguito l'esempio. Credo che il C ++ adotti solo il n. 3. Personalmente, penso che il n. 1 e il n. 2 siano più utili del n. 3, ma altri potrebbero essere diversi.
supercat,

@supercat "Non credo sia possibile per nessuna lingua gestire tutte e tre le precedenti" - se gli offset dei membri dei dati sono determinati in fase di esecuzione, piuttosto che in fase di compilazione (come sono nell'ABI non fragile dell'obiettivo-C ") eo una base per classe (ovvero ogni classe concreta ha la propria tabella di offset dei membri), quindi penso che tutti e 3 gli obiettivi possano essere raggiunti.
The Paramagnetic Croissant,

@TheParamagneticCroissant: il principale problema semantico è il n. 1. Se D1e D2entrambi ereditano da B, e ciascuno ha la precedenza su una funzione f, e if objè un'istanza di un tipo Sche eredita da entrambi D1e D2ma non ha la precedenza f, quindi il cast di un riferimento Sa D1dovrebbe produrre qualcosa di cui fusa l' D1override e il cast a Bnon dovrebbe cambiarlo. Allo stesso modo, lanciare un riferimento Sa D2dovrebbe produrre qualcosa che fusa l' D2override, e il cast a Bnon dovrebbe cambiarlo. Se una lingua non ha bisogno di consentire l'aggiunta di membri virtuali ...
supercat

1
@TheParamagneticCroissant: Potrebbe, e la mia lista di scelte è stata in qualche modo troppo semplificata per adattarsi a un commento, ma il rinvio al runtime rende impossibile all'autore di D1, D2 o S sapere quali cambiamenti possono apportare senza rompere consumatori della loro classe.
Supercat,

2

Dato che questo argomento non è vicino, pubblicherò questa risposta, spero che questo aiuti qualcuno a capire perché java non consente l'ereditarietà multipla.

Considera la seguente classe:

public class Abc{

    public void doSomething(){

    }

}

In questo caso la classe Abc non estende nulla di giusto? Non così in fretta, questa classe implicita estende la classe Object, classe base che consente a tutto di funzionare in Java. Tutto è un oggetto.

Se si tenta di utilizzare la classe di cui sopra vedrete che il vostro IDE consentono di utilizzare metodi come: equals(Object o), toString(), ecc, ma non ha dichiarato i metodi, sono venuti dalla classe baseObject

Puoi provare:

public class Abc extends String{

    public void doSomething(){

    }

}

Questo va bene, perché la tua classe non si estende implicitamente Objectma si estende Stringperché l'hai detto. Considera la seguente modifica:

public class Abc{

    public void doSomething(){

    }

    @Override
    public String toString(){
        return "hello";
    }

}

Ora la tua classe restituirà sempre "ciao" se chiami toString ().

Ora immagina la seguente classe:

public class Flyer{

    public void makeFly(){

    }

}

public class Bird extends Abc, Flyer{

    public void doAnotherThing(){

    }

}

Ancora una volta la classe Flyerimplicita estende l'oggetto che ha il metodo toString(), qualsiasi classe avrà questo metodo poiché si estende tutti Objectindirettamente, quindi, se chiami toString()da Bird, quale toString()Java dovrebbe usare? Da Abco Flyer? Questo accadrà con qualsiasi classe che tenti di estendere due o più classi, per evitare questo tipo di "collisione del metodo" hanno costruito l'idea di interfaccia , in pratica potresti pensarle come una classe astratta che non estende indirettamente l'oggetto . Poiché sono astratti , dovranno essere implementati da una classe, che è un oggetto (non è possibile installare un'interfaccia da sola, devono essere implementati da una classe), quindi tutto continuerà a funzionare correttamente.

Per differenziare le classi dalle interfacce, la parola chiave implementa era riservata solo alle interfacce.

Potresti implementare qualsiasi interfaccia che ti piace nella stessa classe poiché non estende nulla per impostazione predefinita (ma potresti creare un'interfaccia che estende un'altra interfaccia, ma di nuovo, l'interfaccia "padre" non estende l'oggetto "), quindi un'interfaccia è solo un'interfaccia e non soffriranno di " collisioni della firma dei metodi ", se lo fanno il compilatore ti lancerà un avvertimento e dovrai solo cambiare la firma del metodo per risolverlo (firma = nome metodo + parametri + tipo restituito) .

public interface Flyer{

    public void makeFly(); // <- method without implementation

}

public class Bird extends Abc implements Flyer{

    public void doAnotherThing(){

    }

    @Override
    public void makeFly(){ // <- implementation of Flyer interface

    }

    // Flyer does not have toString() method or any method from class Object, 
    // no method signature collision will happen here

}

1

Perché un'interfaccia è solo un contratto. E una classe è in realtà un contenitore per i dati.


La difficoltà fondamentale con l'ereditarietà multipla è la possibilità che una classe possa ereditare un membro tramite percorsi multipli che lo implementano in modo diverso, senza fornire la propria implementazione prioritaria. L'ereditarietà dell'interfaccia evita questo perché l'unico posto in cui i membri dell'interfaccia possono essere implementati è nelle classi, i cui discendenti saranno limitati alla singola eredità.
supercat,

1

Ad esempio due classi A, B con lo stesso metodo m1 (). E la classe C estende sia A, B.

 class C extends A, B // for explaining purpose.

Ora, la classe C cercherà la definizione di m1. In primo luogo, cercherà in classe se non ha trovato, quindi controllerà in classe genitori. Sia A, B che hanno la definizione Quindi qui si verificano ambiguità quale definizione dovrebbe scegliere. Quindi JAVA NON SUPPORTA L'EREDITÀ MULTIPLA.


che ne dite di fare il compilatore java dà compilatore se gli stessi metodi o variabili definiti in entrambe le classi genitore in modo che possiamo cambiare il codice ...
siluveru kiran kumar

1

Java non supporta l'ereditarietà multipla per due motivi:

  1. In java, ogni classe è figlia della Objectclasse. Quando eredita da più di una superclasse, la sottoclasse ottiene l'ambiguità di acquisire la proprietà della classe Oggetto.
  2. In java ogni classe ha un costruttore, se lo scriviamo esplicitamente o per niente. La prima istruzione chiama super()per invocare il costruttore della classe cena. Se la classe ha più di una super classe, viene confusa.

Pertanto, quando una classe si estende da più di una superclasse, viene visualizzato l'errore di compilazione.


0

Prendiamo ad esempio il caso in cui la classe A ha un metodo getSomething e la classe B ha un metodo getSomething e la classe C estende A e B. Cosa accadrebbe se qualcuno chiamasse C.getSomething? Non è possibile determinare quale metodo chiamare.

In sostanza, le interfacce specificano semplicemente quali metodi deve contenere una classe di implementazione. Una classe che implementa più interfacce significa solo che la classe deve implementare i metodi da tutte quelle interfacce. Che non porterebbe a problemi come sopra descritto.


2
" Cosa succederebbe se qualcuno chiamasse C.getSomething. " È un errore in C ++. Problema risolto.
curioso

Quello era il punto ... quello era un contro esempio che pensavo fosse chiaro. Stavo sottolineando che non c'è modo di determinare quale metodo ottenere qualcosa da chiamare. Inoltre, come nota a margine, la domanda riguardava java e non c ++
John Kane,

Mi dispiace di non capire quale sia il tuo punto. Ovviamente, ci sono ambiguità in alcuni casi con MI. Come è un contro esempio? Chi ha affermato che l'MI non provoca mai ambiguità? " Anche come nota a margine, la domanda riguardava java non c ++ " Quindi?
curioso

Stavo solo cercando di mostrare perché esiste quell'ambiguità e perché non funziona con le interfacce.
John Kane,

Sì, l'MI può provocare chiamate ambigue. Quindi può sovraccaricare. Quindi Java dovrebbe rimuovere il sovraccarico?
curioso

0

Considera uno scenario in cui Test1, Test2 e Test3 sono tre classi. La classe Test3 eredita le classi Test2 e Test1. Se le classi Test1 e Test2 hanno lo stesso metodo e lo chiami da oggetto di classe figlio, ci sarà ambiguità nel chiamare il metodo di classe Test1 o Test2 ma non c'è tale ambiguità per l'interfaccia come nell'interfaccia non c'è implementazione.


0

Java non supporta l'ereditarietà multipla, l'ereditarietà multipath e ibrida a causa del problema di ambiguità:

 Scenario for multiple inheritance: Let us take class A , class B , class C. class A has alphabet(); method , class B has also alphabet(); method. Now class C extends A, B and we are creating object to the subclass i.e., class C , so  C ob = new C(); Then if you want call those methods ob.alphabet(); which class method takes ? is class A method or class B method ?  So in the JVM level ambiguity problem occurred. Thus Java does not support multiple inheritance.

eredità multipla

Link di riferimento: https://plus.google.com/u/0/communities/102217496457095083679


0

in modo semplice lo sappiamo tutti, possiamo ereditare (estendere) una classe ma possiamo implementare così tante interfacce .. questo perché nelle interfacce non diamo un'implementazione, diciamo solo la funzionalità. supponiamo che java possa estendere così tante classi e che abbiano gli stessi metodi .. in questo punto se proviamo a invocare il metodo superclasse nella sottoclasse quale metodo supponiamo di eseguire ??, il compilatore ottiene un esempio confuso : - prova a estendere più ma in interfacce quei metodi non hanno corpi che dovremmo implementare quelli nella sottoclasse .. provare a più strumenti quindi nessuna preoccupazione


1
Puoi semplicemente pubblicare qui quegli esempi. Senza questo sembra un blocco di testo a una domanda di 9 anni che ha risposto centinaia di volte.
Pochmurnik,

-1

* Questa è una risposta semplice poiché sono un principiante in Java *

Considerare ci sono tre classi X, Ye Z.

Quindi stiamo ereditando come X extends Y, Z E entrambi Ye stiamo Zavendo un metodo alphabet()con lo stesso tipo di ritorno e argomenti. Questo metodo alphabet()in Ydice di visualizzare il primo alfabeto e l'alfabeto del metodo in Zdice visualizzare l'ultimo alfabeto . Quindi ecco che arriva l'ambiguità quando alphabet()viene chiamato da X. Indica se visualizzare il primo o l' ultimo alfabeto ??? Quindi java non supporta l'ereditarietà multipla. In caso di interfacce, considerare Ye Zcome interfacce. Quindi entrambi conterranno la dichiarazione di metodo alphabet()ma non la definizione. Non dirà se visualizzare il primo alfabeto o l'ultimo alfabeto o altro, ma dichiarerà semplicemente un metodoalphabet(). Quindi non c'è motivo di aumentare l'ambiguità. Possiamo definire il metodo con tutto ciò che vogliamo all'interno della classe X.

Quindi, in una parola, la definizione delle interfacce viene eseguita dopo l'implementazione, quindi nessuna confusione.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.