Come avrei dovuto spiegare la differenza tra un'interfaccia e una classe astratta?


469

In una delle mie interviste, mi è stato chiesto di spiegare la differenza tra un interfaccia ed una classe astratta .

Ecco la mia risposta:

I metodi di un'interfaccia Java sono implicitamente astratti e non possono avere implementazioni. Una classe astratta Java può avere metodi di istanza che implementano un comportamento predefinito.

Le variabili dichiarate in un'interfaccia Java sono di default final. Una classe astratta può contenere variabili non finali.

I membri di un'interfaccia Java sono pubblici per impostazione predefinita. Una classe astratta Java può avere i soliti gusti dei membri della classe come privati, protetti, ecc.

Un'interfaccia Java dovrebbe essere implementata usando la parola chiave "implementa"; Una classe astratta Java dovrebbe essere estesa usando la parola chiave "extends".

Un'interfaccia può estendere solo un'altra interfaccia Java, una classe astratta può estendere un'altra classe Java e implementare più interfacce Java.

Una classe Java può implementare più interfacce ma può estendere solo una classe astratta.

Tuttavia, l'intervistatore non era soddisfatto e mi disse che questa descrizione rappresentava " conoscenza libresca ".

Mi ha chiesto una risposta più pratica, spiegando quando avrei scelto una classe astratta su un'interfaccia, usando esempi pratici .

Dove ho sbagliato?


32
Forse la tua risposta sembrava che stai dicendo qualcosa che non capisci? Può essere che devi semplicemente cambiare lo stile di dire a quello che più assomiglia alle tue stesse parole.
Kirill Kobelev,

19
Hai risposto con un elenco di differenze tecniche (abbastanza corrette). Molto probabilmente l'intervistatore era alla ricerca di una risposta più concettuale (ad esempio, su quale base si sceglierebbe se usare un'interfaccia e una classe astratta).
Ted Hopp,

15
Hai dimenticato di dire che le classi astratte hanno costruttori, anche se non puoi istanziare una classe astratta, la const. viene utilizzato dalle classi secondarie. Le interfacce indicano "cosa" ma non "come" perché definiscono un contratto (elenco di metodi) mentre un abst. la classe può anche indicare "come" (implementare una meth.). Utilizzando int. puoi emulare l'ereditarietà multipla (una classe può implementare più int. ma estendere solo una classe). Utilizzando int. puoi avere un tipo base per dif. famiglie: Flyer f = new Plane (); Flyer f2 = new Bird (); Bird and Plane non corrispondono alla stessa famiglia ma entrambi possono volare (sono volantini).
Francisco Goldenstein,

7
A partire dalle interfacce java8 possono contenere metodi .. quindi al di là del concetto di OO queste cosiddette "differenze" possono cambiare ogni giorno.
portatore dell'anello

15
Non ho alcun problema con la tua risposta, e non credo che l'intervistatore abbia affari da deridere alla "conoscenza del libro". Gli intervistatori non conoscono sempre le risposte corrette alle domande che fanno, e alcune interviste servono solo per avvisarti di non lavorare lì.
Marchese di Lorne,

Risposte:


513

Prima ti faccio un esempio:

public interface LoginAuth{
   public String encryptPassword(String pass);
   public void checkDBforUser();
}

Supponiamo di avere 3 database nella tua applicazione. Quindi ogni singola implementazione per quel database deve definire i 2 metodi precedenti:

public class DBMySQL implements LoginAuth{
          // Needs to implement both methods
}
public class DBOracle implements LoginAuth{
          // Needs to implement both methods
}
public class DBAbc implements LoginAuth{
          // Needs to implement both methods
}

Ma cosa succede se encryptPassword()non dipende dal database, ed è lo stesso per ogni classe? Quindi quanto sopra non sarebbe un buon approccio.

Invece, considera questo approccio:

public abstract class LoginAuth{
   public String encryptPassword(String pass){
            // Implement the same default behavior here 
            // that is shared by all subclasses.
   }

   // Each subclass needs to provide their own implementation of this only:
   public abstract void checkDBforUser();
}

Ora in ogni classe figlio, abbiamo solo bisogno di implementare un metodo - il metodo che dipende dal database.


97
Non sono sicuro che questo spieghi davvero la differenza ... certo che è una bella tecnica. Suppongo che valga anche la pena sottolineare che Java 8 ha finalmente ammesso che C ++ aveva ragione e che l'ereditarietà multipla può essere fatta e può essere utile e quindi le interfacce possono ora definire non solo le firme delle funzioni ma anche fornire implementazioni predefinite. Pertanto, sarebbe preferibile utilizzare un'interfaccia.
thecoshman,

1
@thecoshman Che differenza farebbe se affrontassi il problema come nella risposta (classe astratta con un metodo implementato e l'altro astratto) o definissi un'interfaccia con un'implementazione del metodo predefinita? Fondamentalmente, quello che sto cercando di dire è che hai scritto che "sarebbe preferibile usare un'interfaccia" e la mia domanda è: perché?
Neutrino

1
Quindi, suppongo sia giusto dire che con le interfacce, l'implementazione di ciò che è stato definito dipende dalla classe che implementa effettivamente l'interfaccia, mentre le cose in una classe astratta sono "core" per le classi che estendono la classe; cioè, non cambia.
Orrymr,

4
@Neutrino Nonostante Java ti permetta di implementare più interfacce ognuna delle quali offre implementazioni predefinite per funzioni, puoi comunque estendere solo una singola classe. Pertanto, l'utilizzo di un'interfaccia può offrire maggiore flessibilità a coloro che desiderano utilizzarla, insieme ad altre interfacce.
thecoshman,

3
@HiradNikoo Ci scusiamo per il commento tardivo, ma mi sono appena imbattuto in questa discussione. Puoi anche considerare l'eredità di classe come relazione IS-A, mentre le interfacce indicano "ha una certa funzionalità".
Alexander Jank,

206

Niente è perfetto in questo mondo. Forse si aspettavano un approccio più pratico.

Ma dopo la tua spiegazione potresti aggiungere queste righe con un approccio leggermente diverso.

  1. Le interfacce sono regole (regole perché è necessario dare loro un'implementazione che non si può ignorare o evitare, in modo che siano imposte come regole) che funziona come un documento di comprensione comune tra i vari team nello sviluppo del software.

  2. Le interfacce danno l'idea di cosa si deve fare ma non come verrà fatto. Quindi l'implementazione dipende completamente dallo sviluppatore seguendo le regole date (significa data firma dei metodi).

  3. Le classi astratte possono contenere dichiarazioni astratte, implementazioni concrete o entrambe.

  4. Le dichiarazioni astratte sono come regole da seguire e le implementazioni concrete sono come linee guida (puoi usarlo così com'è o puoi ignorarlo sostituendo e dando la tua implementazione ad esso).

  5. Inoltre, quali metodi con la stessa firma possono modificare il comportamento in contesti diversi sono forniti come dichiarazioni di interfaccia come regole da implementare di conseguenza in contesti diversi.

Modifica: Java 8 facilita la definizione di metodi predefiniti e statici nell'interfaccia.

public interface SomeInterfaceOne {

    void usualAbstractMethod(String inputString);

    default void defaultMethod(String inputString){
        System.out.println("Inside SomeInterfaceOne defaultMethod::"+inputString);
    }
}

Ora, quando una classe implementerà SomeInterface, non è obbligatorio fornire l'implementazione per i metodi di interfaccia predefiniti.

Se abbiamo un'altra interfaccia con i seguenti metodi:

public interface SomeInterfaceTwo {

    void usualAbstractMethod(String inputString);

    default void defaultMethod(String inputString){
        System.out.println("Inside SomeInterfaceTwo defaultMethod::"+inputString);
    }

}

Java non consente l'estensione di più classi perché determina il "Problema del diamante" in cui il compilatore non è in grado di decidere quale metodo di superclasse utilizzare. Con i metodi predefiniti, il problema del diamante sorgerà anche per le interfacce. Perché se una classe sta implementando entrambi

SomeInterfaceOne and SomeInterfaceTwo

e non implementa il metodo predefinito comune, il compilatore non può decidere quale scegliere. Per evitare questo problema, in java 8 è obbligatorio implementare metodi predefiniti comuni di diverse interfacce. Se una classe sta implementando entrambe le interfacce di cui sopra, deve fornire l'implementazione per il metodo defaultMethod (), altrimenti il ​​compilatore genererà un errore di tempo di compilazione.


11
+1, questa è davvero una buona risposta per evitare confusione. Ma non ho visto alcun link e non ho idea del perché tu abbia citato quelle linee preziose. Rendili come punti se possibile :).
Suresh Atta,

Leggi il mio commento sopra sull'emulazione dell'ereditarietà multipla usando le interfacce e usando le interfacce per avere un tipo base per classi di famiglie diverse. Penso che l'intervistatore voglia sentire quel tipo di risposte dagli intervistati.
Francisco Goldenstein,

Il tuo commento indica anche un buon esempio di utilizzo dell'interfaccia. Ho scritto quello che provo mentre lavoro giorno per giorno. Queste parole potrebbero non essere professionali o accurate. Ma è quello che ho imparato a conoscere dopo aver lavorato a stretto contatto con classi e interfacce astratte nella mia programmazione quotidiana.
Shailesh Saxena,

4. Le implementazioni concrete sono anche le regole, con l'implementazione predefinita.
Luten,

@Luten: Per quanto ne so, se puoi evitare / ignorare una regola senza alcun problema, questa deve essere una linea guida non una regola. Perfavore, correggimi se sbaglio.
Shailesh Saxena,

168

Hai fatto un buon riassunto delle differenze pratiche nell'uso e nell'implementazione ma non hai detto nulla sulla differenza di significato.

Un'interfaccia è una descrizione del comportamento di una classe di implementazione avrà. La classe di implementazione garantisce che disporrà di questi metodi che possono essere utilizzati su di essa. Fondamentalmente è un contratto o una promessa che la classe deve fare.

Una classe astratta è una base per diverse sottoclassi che condividono comportamenti che non devono essere creati ripetutamente. Le sottoclassi devono completare il comportamento e avere l'opzione di sovrascrivere il comportamento predefinito (purché non sia definito come finalo private).

Troverai buoni esempi nel java.utilpacchetto che include interfacce simili Liste classi astratte come quelle AbstractListche implementano già l'interfaccia. La documentazione ufficiale descrive AbstractListquanto segue:

Questa classe fornisce un'implementazione scheletrica dell'interfaccia Elenco per ridurre al minimo lo sforzo richiesto per implementare questa interfaccia supportata da un archivio dati "ad accesso casuale" (come un array).


16
Questa dovrebbe essere la risposta. Non un elenco di dettagli, ma il concetto sottostante che fa la differenza tra un'interfaccia e una classe astratta, non solo in Java ma in generale.
edc65,

1
Questo è veramente buono. Naturalmente anche le altre risposte sono buone. Ma questo ti dice un importante avvertimento sulla abstractparola chiave, cioè quando un compilatore lo vede, lo sanno, le seguenti informazioni sono incomplete e devono essere implementate . Le interfacce sono sempre incomplete, ma le classi astratte sono astratte perché dovevano avere dei incomplete (abstract)metodi.
Rakib,

85

Un'interfaccia è costituita da variabili singleton (public static final) e metodi abstract pubblici. Normalmente preferiamo usare un'interfaccia in tempo reale quando sappiamo cosa fare ma non sappiamo come farlo .

Questo concetto può essere meglio compreso con l'esempio:

Prendi in considerazione una classe di pagamento. Il pagamento può essere effettuato in molti modi, come PayPal, carta di credito, ecc. Quindi normalmente prendiamo il pagamento come interfaccia che contiene un makePayment()metodo e CreditCard e PayPal sono le due classi di implementazione.

public interface Payment
{
    void makePayment();//by default it is a abstract method
}
public class PayPal implements Payment
{
    public void makePayment()
    {
        //some logic for PayPal payment
        //e.g. Paypal uses username and password for payment
    }
}
public class CreditCard implements Payment
{
    public void makePayment()
    {
        //some logic for CreditCard payment
        //e.g. CreditCard uses card number, date of expiry etc...
    }
}

Nell'esempio sopra, CreditCard e PayPal sono due classi / strategie di implementazione. Un'interfaccia ci consente anche il concetto di ereditarietà multipla in Java che non può essere realizzato da una classe astratta.

Scegliamo una classe astratta quando ci sono alcune funzionalità per le quali sappiamo cosa fare e altre funzionalità che sappiamo come eseguire .

Considera il seguente esempio:

public abstract class Burger
{
    public void packing()
    {
        //some logic for packing a burger
    }
    public abstract void price(); //price is different for different categories of burgers
}
public class VegBerger extends Burger
{
    public void price()
    {
        //set price for a veg burger.
    }
}
public class NonVegBerger extends Burger
{
    public void price()
    {
        //set price for a non-veg burger.
    }
}

Se in futuro aggiungiamo metodi (concreti / astratti) a una determinata classe astratta, la classe di implementazione non avrà bisogno di cambiare il suo codice. Tuttavia, se in futuro aggiungiamo metodi in un'interfaccia, dobbiamo aggiungere implementazioni a tutte le classi che implementano tale interfaccia, altrimenti si verificano errori di compilazione.

Ci sono altre differenze, ma queste sono quelle principali che potrebbero essere state quelle che il tuo intervistatore si aspettava. Spero che questo sia stato utile.


1
Bene, questa risposta ha molto senso, ed è abbastanza chiara con l'esempio, quando arriviamo a scegliere tra interfacee abstract class.
MAC

"cosa fare ma non so come farlo" mentre definiamo un metodo senza fare alcuna implementazione in esso "void makePayment ();", mentre definiamo le implementazioni del metodo nella classe che implementerà l'interfaccia.
Abdel-Raouf

45

Differenza tra classe Abstact e interfaccia

  1. Classi astratte contro interfacce in Java 8
  2. Differenza concettuale:

Metodi predefiniti dell'interfaccia in Java 8

  1. Cos'è il metodo predefinito?
  2. Ogni errore di compilazione del metodo è stato risolto utilizzando il metodo predefinito
  3. Metodo predefinito e problemi di ambiguità dell'ereditarietà multipla
  4. Punti importanti sui metodi predefiniti dell'interfaccia java:

Metodo statico dell'interfaccia Java

  1. Metodo statico dell'interfaccia Java, esempio di codice, metodo statico vs metodo predefinito
  2. Punti importanti sul metodo statico dell'interfaccia java:

Interfacce funzionali Java



Classi astratte contro interfacce in Java 8

Le modifiche all'interfaccia di Java 8 includono metodi statici e metodi predefiniti nelle interfacce. Prima di Java 8, potevamo avere solo dichiarazioni di metodo nelle interfacce. Ma da Java 8, possiamo avere metodi predefiniti e metodi statici nelle interfacce.

Dopo aver introdotto il metodo predefinito, sembra che le interfacce e le classi astratte siano uguali. Tuttavia, sono ancora concetto diverso in Java 8.

La classe astratta può definire il costruttore. Sono più strutturati e possono avere uno stato ad essi associato. Al contrario, il metodo predefinito può essere implementato solo in termini di invocazione di altri metodi di interfaccia, senza alcun riferimento allo stato di una particolare implementazione. Quindi, entrambi usano per scopi diversi e la scelta tra due dipende davvero dal contesto dello scenario.

Differenza concettuale:

Le classi astratte sono valide per implementazioni scheletriche (cioè parziali) di interfacce ma non dovrebbero esistere senza un'interfaccia corrispondente.

Quindi, quando le classi astratte vengono effettivamente ridotte in implementazioni scheletriche di interfacce a bassa visibilità, anche i metodi predefiniti possono portarlo via? Decisamente: no! L'implementazione delle interfacce richiede quasi sempre alcuni o tutti quegli strumenti per la creazione di classi di cui mancano i metodi predefiniti. E se un'interfaccia non lo fa, è chiaramente un caso speciale, che non dovrebbe farti smarrire.

Metodi predefiniti dell'interfaccia in Java 8

Java 8 introduce la nuova funzione " Metodo predefinito " o (Metodi Defender), che consente allo sviluppatore di aggiungere nuovi metodi alle interfacce senza interrompere l'implementazione esistente di queste interfacce. Fornisce flessibilità per consentire a Interface di definire l'implementazione che utilizzerà come impostazione predefinita nella situazione in cui una Classe concreta non riesce a fornire un'implementazione per quel metodo.

Consideriamo un piccolo esempio per capire come funziona:

public interface OldInterface {
    public void existingMethod();
 
    default public void newDefaultMethod() {
        System.out.println("New default method"
               + " is added in interface");
    }
}

La seguente classe verrà compilata correttamente in Java JDK 8,

public class OldInterfaceImpl implements OldInterface {
    public void existingMethod() {
     // existing implementation is here…
    }
}

Se si crea un'istanza di OldInterfaceImpl:

OldInterfaceImpl obj = new OldInterfaceImpl ();
// print “New default method add in interface”
obj.newDefaultMethod(); 

Metodo predefinito:

I metodi predefiniti non sono mai definitivi, non possono essere sincronizzati e non possono ignorare i metodi di Object. Sono sempre pubblici, il che limita fortemente la capacità di scrivere metodi brevi e riutilizzabili.

I metodi predefiniti possono essere forniti a un'interfaccia senza influire sulle classi di implementazione in quanto include un'implementazione. Se ogni metodo aggiunto in un'interfaccia definito con l'implementazione non viene influenzata alcuna classe di implementazione. Una classe di implementazione può sovrascrivere l'implementazione predefinita fornita dall'interfaccia.

I metodi predefiniti consentono di aggiungere nuove funzionalità alle interfacce esistenti senza interrompere l'implementazione precedente di queste interfacce.

Quando estendiamo un'interfaccia che contiene un metodo predefinito, possiamo eseguire le seguenti operazioni,

  1. Non sovrascrivere il metodo predefinito ed erediterà il metodo predefinito.
  2. Sostituisci il metodo predefinito simile ad altri metodi che sostituiamo nella sottoclasse.
  3. Ridichiarare il metodo predefinito come astratto, che forza la sottoclasse a sovrascriverlo.

Ogni errore di compilazione del metodo è stato risolto utilizzando il metodo predefinito

Per Java 8, le raccolte JDK sono state estese e ogni metodo è stato aggiunto all'intera raccolta (che funziona in combinazione con lambdas). Con il modo convenzionale, il codice appare come di seguito,

public interface Iterable<T> {
    public void forEach(Consumer<? super T> consumer);
}

Dal momento che questo risultato ogni classe di implementazione con errori di compilazione, quindi, è stato aggiunto un metodo predefinito con un'implementazione richiesta in modo che l'implementazione esistente non debba essere modificata.

L'interfaccia Iterable con il metodo predefinito è di seguito,

public interface Iterable<T> {
    public default void forEach(Consumer
                   <? super T> consumer) {
        for (T t : this) {
            consumer.accept(t);
        }
    }
}

Lo stesso meccanismo è stato utilizzato per aggiungere Stream nell'interfaccia JDK senza interrompere le Classi di implementazione.


Metodo predefinito e problemi di ambiguità dell'ereditarietà multipla

Poiché la classe java può implementare più interfacce e ciascuna interfaccia può definire il metodo predefinito con la stessa firma del metodo, pertanto i metodi ereditati possono entrare in conflitto tra loro.

Considera l'esempio seguente,

public interface InterfaceA {  
       default void defaultMethod(){  
           System.out.println("Interface A default method");  
    }  
}
 
public interface InterfaceB {
   default void defaultMethod(){
       System.out.println("Interface B default method");
   }
}
 
public class Impl implements InterfaceA, InterfaceB  {
}

Il codice sopra riportato non verrà compilato con il seguente errore,

java: classe Impl eredita impostazioni predefinite non correlate per defaultMethod () dai tipi InterfaceA e InterfaceB

Per correggere questa classe, dobbiamo fornire l'implementazione del metodo predefinito:

public class Impl implements InterfaceA, InterfaceB {
    public void defaultMethod(){
    }
}

Inoltre, se vogliamo invocare l'implementazione predefinita fornita da qualsiasi super interfaccia piuttosto che dalla nostra stessa implementazione, possiamo farlo come segue,

public class Impl implements InterfaceA, InterfaceB {
    public void defaultMethod(){
        // existing code here..
        InterfaceA.super.defaultMethod();
    }
}

Possiamo scegliere qualsiasi implementazione predefinita o entrambe come parte del nostro nuovo metodo.

Punti importanti sui metodi predefiniti dell'interfaccia java:

  1. I metodi predefiniti dell'interfaccia Java ci aiuteranno a estendere le interfacce senza temere di interrompere le classi di implementazione.
  2. I metodi predefiniti dell'interfaccia Java hanno colmato le differenze tra interfacce e classi astratte.
  3. I metodi predefiniti dell'interfaccia Java 8 ci aiuteranno a evitare le classi di utilità, come tutto il metodo della classe Collections può essere fornito nelle interfacce stesse.
  4. I metodi predefiniti dell'interfaccia Java ci aiuteranno a rimuovere le classi di implementazione di base, possiamo fornire l'implementazione di default e le classi di implementazione possono scegliere quale sovrascrivere.
  5. Uno dei motivi principali per l'introduzione di metodi predefiniti nelle interfacce è quello di migliorare l'API Collections in Java 8 per supportare le espressioni lambda.
  6. Se una classe nella gerarchia ha un metodo con la stessa firma, i metodi predefiniti diventano irrilevanti. Un metodo predefinito non può sovrascrivere un metodo da java.lang.Object. Il ragionamento è molto semplice, è perché Object è la classe base per tutte le classi java. Quindi, anche se abbiamo metodi della classe Object definiti come metodi predefiniti nelle interfacce, sarà inutile perché verrà sempre usato il metodo della classe Object. Ecco perché per evitare confusione, non possiamo avere metodi predefiniti che sovrascrivono i metodi della classe Object.
  7. I metodi predefiniti dell'interfaccia Java sono anche definiti Metodi Defender o Metodi di estensione virtuale.

Collegamento alle risorse:

  1. Interfaccia con metodi predefiniti vs classe astratta in Java 8
  2. Classe astratta contro interfaccia nell'era JDK 8
  3. Evoluzione dell'interfaccia tramite metodi di estensione virtuale

Metodo statico dell'interfaccia Java

Metodo statico dell'interfaccia Java, esempio di codice, metodo statico vs metodo predefinito

Il metodo statico dell'interfaccia Java è simile al metodo predefinito, tranne per il fatto che non possiamo sostituirli nelle classi di implementazione. Questa funzionalità ci aiuta a evitare risultati indesiderati in caso di scarsa implementazione nelle classi di implementazione. Diamo un'occhiata a questo con un semplice esempio.

public interface MyData {

    default void print(String str) {
        if (!isNull(str))
            System.out.println("MyData Print::" + str);
    }

    static boolean isNull(String str) {
        System.out.println("Interface Null Check");

        return str == null ? true : "".equals(str) ? true : false;
    }
}

Vediamo ora una classe di implementazione che ha il metodo isNull () con un'implementazione scadente.

public class MyDataImpl implements MyData {

    public boolean isNull(String str) {
        System.out.println("Impl Null Check");

        return str == null ? true : false;
    }

    public static void main(String args[]){
        MyDataImpl obj = new MyDataImpl();
        obj.print("");
        obj.isNull("abc");
    }
}

Nota che isNull (String str) è un metodo di classe semplice, non ha la precedenza sul metodo di interfaccia. Ad esempio, se aggiungeremo l'annotazione @Override al metodo isNull (), si verificherà un errore del compilatore.

Ora quando eseguiremo l'applicazione, otteniamo il seguente output.

Controllo null interfaccia

Controllo null impl

Se rendiamo il metodo dell'interfaccia da statico a predefinito, otterremo il seguente output.

Controllo null impl

MyData Print ::

Controllo null impl

Il metodo statico dell'interfaccia Java è visibile solo per i metodi di interfaccia, se rimuoviamo il metodo isNull () dalla classe MyDataImpl, non saremo in grado di usarlo per l'oggetto MyDataImpl. Tuttavia, come altri metodi statici, possiamo usare i metodi statici dell'interfaccia usando il nome della classe. Ad esempio, un'istruzione valida sarà:

boolean result = MyData.isNull("abc");

Punti importanti sul metodo statico dell'interfaccia java:

  1. Il metodo statico dell'interfaccia Java fa parte dell'interfaccia, non possiamo usarlo per gli oggetti della classe di implementazione.
  2. I metodi statici dell'interfaccia Java sono utili per fornire metodi di utilità, ad esempio controllo null, ordinamento delle raccolte ecc.
  3. Il metodo statico dell'interfaccia Java ci aiuta a fornire sicurezza impedendo alle classi di implementazione di sovrascriverle.
  4. Non possiamo definire il metodo statico dell'interfaccia per i metodi della classe Object, otterremo un errore del compilatore come "Questo metodo statico non può nascondere il metodo dell'istanza da Object". Questo perché non è consentito in Java, poiché Object è la classe di base per tutte le classi e non possiamo avere un metodo statico a livello di classe e un altro metodo di istanza con la stessa firma.
  5. Possiamo usare i metodi statici dell'interfaccia java per rimuovere le classi di utilità come Collezioni e spostare tutti i suoi metodi statici sull'interfaccia corrispondente, che sarebbe facile da trovare e utilizzare.

Interfacce funzionali Java

Prima di concludere il post, vorrei fornire una breve introduzione alle interfacce funzionali. Un'interfaccia con esattamente un metodo astratto è nota come interfaccia funzionale.

È @FunctionalInterfacestata introdotta una nuova annotazione per contrassegnare un'interfaccia come interfaccia funzionale.@FunctionalInterfacel'annotazione è una funzione per evitare l'aggiunta accidentale di metodi astratti nelle interfacce funzionali. È facoltativo ma buona pratica usarlo.

Le interfacce funzionali sono attese da tempo e sono molto ricercate funzionalità di Java 8 perché ci consente di usare espressioni lambda per istanziarle. Un nuovo pacchetto java.util.function con un sacco di interfacce funzionali viene aggiunto per fornire tipi di destinazione per espressioni lambda e riferimenti a metodi. Esamineremo le interfacce funzionali e le espressioni lambda nei post futuri.

Ubicazione delle risorse:

  1. Modifiche all'interfaccia Java 8: metodo statico, metodo predefinito

8
Sto cercando esattamente questi tipi di risposte aggiornate. Grazie per la rapida risposta.
Ravindra babu,

41

Tutte le tue dichiarazioni sono valide tranne la tua prima dichiarazione (dopo la versione di Java 8):

I metodi di un'interfaccia Java sono implicitamente astratti e non possono avere implementazioni

Dalla pagina della documentazione :

Un'interfaccia è un tipo di riferimento, simile a una classe, che può contenere solo costanti, firme dei metodi, metodi predefiniti, metodi statici e tipi nidificati

I corpi dei metodi esistono solo per metodi predefiniti e metodi statici.

Metodi predefiniti:

Un'interfaccia può avere metodi predefiniti , ma sono diversi dai metodi astratti nelle classi astratte.

I metodi predefiniti consentono di aggiungere nuove funzionalità alle interfacce delle librerie e garantire la compatibilità binaria con il codice scritto per le versioni precedenti di tali interfacce.

Quando si estende un'interfaccia che contiene un metodo predefinito, è possibile effettuare le seguenti operazioni:

  1. Non menzionare affatto il metodo predefinito, che consente all'interfaccia estesa di ereditare il metodo predefinito.
  2. Ridichiarare il metodo predefinito, che lo rende abstract.
  3. Ridefinire il metodo predefinito, che lo sovrascrive.

Metodi statici:

Oltre ai metodi predefiniti, è possibile definire metodi statici nelle interfacce. (Un metodo statico è un metodo associato alla classe in cui è definito anziché a qualsiasi oggetto. Ogni istanza della classe condivide i suoi metodi statici.)

Ciò semplifica l'organizzazione dei metodi di supporto nelle librerie;

Codice di esempio dalla pagina di documentazione su interfaceavere statice defaultmetodi.

import java.time.*;

public interface TimeClient {
    void setTime(int hour, int minute, int second);
    void setDate(int day, int month, int year);
    void setDateAndTime(int day, int month, int year,
                               int hour, int minute, int second);
    LocalDateTime getLocalDateTime();

    static ZoneId getZoneId (String zoneString) {
        try {
            return ZoneId.of(zoneString);
        } catch (DateTimeException e) {
            System.err.println("Invalid time zone: " + zoneString +
                "; using default time zone instead.");
            return ZoneId.systemDefault();
        }
    }

    default ZonedDateTime getZonedDateTime(String zoneString) {
        return ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString));
    }
}

Utilizzare le linee guida seguenti per scegliere se utilizzare un'interfaccia o una classe astratta.

Interfaccia:

  1. Per definire un contratto (preferibilmente apolide - non intendo nessuna variabile)
  2. Collegare le classi non correlate con ha una capacità.
  3. Per dichiarare variabili costanti pubbliche ( stato immutabile )

Classe astratta:

  1. Condividi il codice tra diverse classi strettamente correlate. Stabilisce è una relazione.

  2. Condividi lo stato comune tra le classi correlate (lo stato può essere modificato in classi concrete)

Articoli correlati:

Interface vs Abstract Class (OO generale)

Implements vs extends: quando utilizzare? Qual è la differenza?

Attraverso questi esempi, puoi capirlo

Le classi non correlate possono avere funzionalità tramite l'interfaccia ma le classi correlate cambiano il comportamento attraverso l'estensione delle classi di base.


Cosa intendi dire "contratto senza stato"? È l'articolo 1 sulle interfacce
Maksim Dmitriev,

1
Assenza di stato mutabile. Poiché l'interfaccia può avere costanti, i dati possono essere mutati a differenza delle classi astratte
Ravindra babu,

1
Correzione nella precedente dichiarazione. Nell'interfaccia, i dati non possono essere mutati a differenza della classe astratta
Ravindra babu,

2
questa è la risposta migliore Non solo si rivolge a Java8, ma spiega anche in quali situazioni particolari useresti una delle due.
Shuklaswag,

Il concetto di statelessin interface è un bel successo. L'interfaccia non può avere alcuno stato (l'interfaccia potrebbe avere costanti ma sono definitive / statiche quindi immutabili).
Kaihua,

22

La tua spiegazione sembra decente, ma può sembrare che tu stia leggendo tutto da un libro di testo? : - /

Ciò di cui mi preoccupo di più è quanto solido è stato il tuo esempio? Ti sei preoccupato di includere quasi tutte le differenze tra abstract e interfacce?

Personalmente, suggerirei questo link: http://mindprod.com/jgloss/interfacevsabstract.html#TABLE

per un elenco esaustivo di differenze ..

Spero che aiuti te e tutti gli altri lettori nelle loro future interviste


1
il link è condiviso è davvero fantastico
Premraj il

È possibile fornire un'implementazione predefinita nelle interfacce Java utilizzando la parola chiave predefinita
Ogen

21

Molti sviluppatori junior commettono l'errore di pensare a interfacce, classi astratte e concrete come lievi variazioni della stessa cosa e scelgono una di esse puramente per motivi tecnici: ho bisogno dell'eredità multipla? Ho bisogno di un posto per mettere metodi comuni? Devo preoccuparmi di qualcosa di diverso da una lezione concreta? Questo è sbagliato e nascosto in queste domande c'è il problema principale: "I" . Quando scrivi il codice per te stesso, raramente pensi ad altri sviluppatori presenti o futuri che lavorano su o con il tuo codice.

Le interfacce e le classi astratte, sebbene apparentemente simili dal punto di vista tecnico, hanno significati e scopi completamente diversi.

Sommario

  1. Un'interfaccia definisce un contratto che alcune implementazioni realizzeranno per te .

  2. Una classe astratta fornisce un comportamento predefinito che la tua implementazione può riutilizzare.

Questi due punti sopra sono quello che sto cercando durante l'intervista ed è un riassunto abbastanza compatto. Continua a leggere per maggiori dettagli.

Riepilogo alternativo

  1. Un'interfaccia serve a definire le API pubbliche
  2. Una classe astratta è per uso interno e per la definizione di SPI

Per esempio

Per dirla diversamente: una classe concreta fa il lavoro reale, in un modo molto specifico. Ad esempio, unArrayList utilizza un'area contigua di memoria per memorizzare un elenco di oggetti in modo compatto che offre un accesso casuale rapido, iterazione e modifiche sul posto, ma è terribile per inserimenti, eliminazioni e occasionalmente anche aggiunte; nel frattempo, aLinkedListutilizza nodi a doppio collegamento per memorizzare un elenco di oggetti, che offre invece iterazione rapida, modifiche sul posto e inserimento / eliminazione / aggiunta, ma è terribile in caso di accesso casuale. Questi due tipi di elenchi sono ottimizzati per diversi casi d'uso e conta molto come li utilizzerai. Quando stai cercando di spremere le prestazioni da un elenco con cui interagisci pesantemente e quando scegli il tipo di elenco dipende da te, dovresti scegliere con cura quale stai istanziando.

D'altra parte, gli utenti di alto livello di un elenco non si preoccupano davvero di come sia effettivamente implementato e dovrebbero essere isolati da questi dettagli. Immaginiamo che Java non esponga l' Listinterfaccia, ma abbia solo una Listclasse concreta che è in realtà ciò che LinkedListè in questo momento. Tutti gli sviluppatori Java avrebbero adattato il proprio codice per adattarlo ai dettagli dell'implementazione: evitare l'accesso casuale, aggiungere una cache per accelerare l'accesso o semplicemente reimplementare ArrayListda soli, anche se sarebbe incompatibile con tutto l'altro codice che funziona effettivamente conList solo . Sarebbe terribile ... Ma ora immagina che i maestri Java si rendano davvero conto che un elenco collegato è terribile per la maggior parte dei casi d'uso reali, e hanno deciso di passare a un elenco di array solo per loroListclasse disponibile. Ciò influenzerebbe le prestazioni di ogni programma Java nel mondo e le persone non ne sarebbero contente. E il principale colpevole è che i dettagli di implementazione erano disponibili e gli sviluppatori hanno ipotizzato che quei dettagli fossero un contratto permanente su cui poter contare. Ecco perché è importante nascondere i dettagli dell'implementazione e definire solo un contratto astratto. Questo è lo scopo di un'interfaccia: definire quale tipo di input accetta un metodo e quale tipo di output è previsto, senza esporre tutte le viscere che inducono i programmatori a modificare il loro codice per adattarlo ai dettagli interni che potrebbero cambiare con qualsiasi aggiornamento futuro .

Una classe astratta è nel mezzo tra interfacce e classi concrete. Dovrebbe aiutare le implementazioni a condividere codice comune o noioso. Ad esempio, AbstractCollectionfornisce implementazioni di isEmptybase in base alla dimensione è 0, containscome iterare e confrontare, addAllcome ripetuto adde così via. Ciò consente alle implementazioni di concentrarsi sulle parti cruciali che le differenziano: come archiviare e recuperare i dati.

Un'altra prospettiva: API contro SPI

Le interfacce sono gateway a bassa coesione tra diverse parti del codice. Consentono alle biblioteche di esistere e di evolversi senza interrompere tutti gli utenti delle biblioteche quando qualcosa cambia internamente. Si chiama Application Programming Interface , non Application Programming Classes. Su scala ridotta, consentono inoltre a più sviluppatori di collaborare con successo a progetti su larga scala, separando i diversi moduli attraverso interfacce ben documentate.

Le classi astratte sono aiutanti di coesione elevata da utilizzare durante l'implementazione di un'interfaccia, assumendo un certo livello di dettagli di implementazione. In alternativa, le classi astratte vengono utilizzate per la definizione di SPI, interfacce fornitore di servizi.

La differenza tra un'API e una SPI è sottile, ma importante: per un'API, l'attenzione è rivolta a chi la usa e per una SPI l'attenzione è su chi la implementa .

L'aggiunta di metodi a un'API è semplice, tutti gli utenti esistenti dell'API verranno comunque compilati. L'aggiunta di metodi a una SPI è difficile, poiché ogni fornitore di servizi (implementazione concreta) dovrà implementare i nuovi metodi. Se le interfacce vengono utilizzate per definire un SPI, un provider dovrà rilasciare una nuova versione ogni volta che il contratto SPI cambia. Se si utilizzano invece classi astratte, è possibile definire nuovi metodi in termini di metodi astratti esistenti o come throw not implemented exceptionstub vuoti , che consentiranno almeno una versione precedente di un'implementazione del servizio da compilare ed eseguire.

Una nota su Java 8 e metodi predefiniti

Sebbene Java 8 abbia introdotto metodi predefiniti per le interfacce, il che rende la linea tra le interfacce e le classi astratte ancora più sfocate, ciò non è stato così che le implementazioni possono riutilizzare il codice, ma per rendere più semplice cambiare le interfacce che servono sia come API che come SPI (o vengono erroneamente utilizzati per la definizione di SPI anziché per le classi astratte).

"Conoscenza del libro"

I dettagli tecnici forniti nella risposta del PO sono considerati "conoscenza del libro" perché questo è di solito l'approccio usato a scuola e nella maggior parte dei libri di tecnologia su una lingua: che cosa è, non come usarlo nella pratica, specialmente nelle applicazioni su larga scala .

Ecco un'analogia: supponiamo che la domanda fosse:

Cosa è meglio noleggiare per una serata da ballo, un'auto o una stanza d'albergo?

La risposta tecnica suona come:

Bene, in un'auto puoi farlo prima, ma in una stanza d'albergo puoi farlo più comodamente. D'altra parte, la camera d'albergo si trova in un solo posto, mentre in macchina puoi farlo in più posti, diciamo che puoi andare al punto di vista per una bella vista o in un teatro drive-in, o in molti altri posti, o anche in più di un posto. Inoltre, la camera d'albergo ha una doccia.

Questo è tutto vero, ma manca completamente i punti che sono due cose completamente diverse, ed entrambe possono essere utilizzate contemporaneamente per scopi diversi, e l'aspetto "farlo" non è la cosa più importante in nessuna delle due opzioni . La risposta manca di prospettiva, mostra un modo di pensare immaturo, pur presentando correttamente "fatti" reali.


Intendevi "accoppiamento basso"?
user2418306

@ user2418306 No, coesione è un termine più generico che include l'accoppiamento, sebbene siano sinonimi vicini, e entrambi i termini avrebbero funzionato.
Sergiu Dumitriu,

9

Che ne dici di pensare nel modo seguente:

  • Una relazione tra una classe e una classe astratta è di tipo "is-a"
  • Una relazione tra una classe e un'interfaccia è di tipo "has-a"

Quindi quando hai una classe astratta Mammals, una sottoclasse Human e un'interfaccia Driving, allora puoi dire

  • ogni essere umano è un mammifero
  • ogni essere umano ha una guida (comportamento)

Il mio suggerimento è che la frase di conoscenza del libro indica che voleva sentire la differenza semantica tra i due (come altri già suggeriti qui).


9

Un'interfaccia è un "contratto" in cui la classe che implementa il contratto promette di implementare i metodi. Un esempio in cui dovevo scrivere un'interfaccia anziché una classe era quando stavo aggiornando un gioco da 2D a 3D. Ho dovuto creare un'interfaccia per condividere le classi tra la versione 2D e la versione 3D del gioco.

package adventure;
import java.awt.*;
public interface Playable {
    public void playSound(String s);
    public Image loadPicture(String s);    
}

Quindi posso implementare i metodi basati sull'ambiente, pur essendo in grado di chiamare quei metodi da un oggetto che non sa quale versione del gioco sta caricando.

public class Adventure extends JFrame implements Playable

public class Dungeon3D extends SimpleApplication implements Playable

public class Main extends SimpleApplication implements AnimEventListener, ActionListener, Playable

In genere, nel mondo di gioco, il mondo può essere una classe astratta che esegue metodi sul gioco:

public abstract class World...

    public Playable owner;

    public Playable getOwner() {
        return owner;
    }

    public void setOwner(Playable owner) {
        this.owner = owner;
    }

6

Le classi astratte non sono pura astrazione perché la sua raccolta di calcestruzzo (metodi implementati) e metodi non implementati. Ma le interfacce sono pura astrazione perché ci sono solo metodi non implementati, non metodi concreti.

Perché lezioni astratte?

  1. Se l'utente desidera scrivere funzionalità comuni per tutti gli oggetti.
  2. Le classi astratte sono la scelta migliore per la reimplementazione in futuro che per aggiungere più funzionalità senza influenzare l'utente finale.

Perché le interfacce?

  1. Se l'utente desidera scrivere funzionalità diverse che sarebbero funzionalità diverse sugli oggetti.
  2. Le interfacce sono la scelta migliore che, se non è necessario modificare i requisiti una volta che l'interfaccia è stata pubblicata.

5

Un interfaccia è come un insieme di geni che sono pubblicamente documentati di avere una sorta di effetto: Un DNA di prova mi dirà se io li ho - e se lo faccio, posso pubblicamente far sapere che io sono un "vettore "e parte del mio comportamento o stato sarà conforme a loro. (Ma ovviamente, potrei avere molti altri geni che forniscono tratti al di fuori di questo ambito.)

Una classe astratta è come l'antenata morta di una specie single-sex (*): non può essere portata in vita ma un discendente vivente (cioè non astratto ) eredita tutti i suoi geni.

(*) Per allungare questa metafora, diciamo che tutti i membri della specie vivono alla stessa età. Ciò significa che anche tutti gli antenati di un antenato morto devono essere morti - e allo stesso modo, tutti i discendenti di un antenato vivente devono essere vivi.


4

Faccio interviste per lavoro e guarderei sfavorevolmente anche la tua risposta (scusa ma sono molto onesta). Sembra che tu abbia letto della differenza e modificato una risposta, ma forse non l'hai mai usata in pratica.

Una buona spiegazione del motivo per cui dovresti usare ciascuno di essi può essere molto meglio che avere una spiegazione precisa della differenza. Alla fine i datori di lavoro vogliono che i programmatori facciano cose che non le conoscono, cosa che può essere difficile da dimostrare in un'intervista. La risposta che hai dato sarebbe buona se richiedessi un lavoro tecnico o basato sulla documentazione ma non un ruolo di sviluppatore.

Buona fortuna con interviste in futuro.

Anche la mia risposta a questa domanda è più sulla tecnica di intervista piuttosto che sul materiale tecnico che hai fornito. Forse considera di leggerlo. https://workplace.stackexchange.com/ può essere un posto eccellente per questo genere di cose.


1
Potresti dirmi come hai risposto? Può essere che mi possa aiutare.
code_fish

darti la risposta offre molto meno che aiutarti a risolverlo, in pratica fornisci un esempio pratico di quando utilizzeresti ciascuno di essi e spiega perché ognuno è adatto ai diversi compiti.
Adrian,

4

Scegli l'interfaccia in Java per evitare il problema del diamante in eredità multipla .

Se vuoi che tutti i tuoi metodi vengano implementati dal tuo client, scegli l'interfaccia. Significa che si progetta l'intera applicazione in astratto.

Scegli la classe astratta se sai già cosa c'è in comune. Ad esempio Prendi una classe astratta Car. A livello superiore si implementano i metodi di auto comuni come calculateRPM(). È un metodo comune e permetti al cliente di implementare il proprio comportamento come
calculateMaxSpeed()ecc. Probabilmente avresti spiegato dando alcuni esempi in tempo reale che hai incontrato nel tuo lavoro quotidiano.



3

La principale differenza che ho osservato è che la classe astratta ci fornisce alcuni comportamenti comuni già implementati e le sottoclassi devono solo implementare funzionalità specifiche corrispondenti a loro. dove per quanto riguarda un'interfaccia specificherà solo quali attività devono essere eseguite e nessuna interfaccia sarà data dall'interfaccia. Posso dire che specifica il contratto tra se stesso e le classi implementate.


3

Anche io ho affrontato la stessa domanda in più interviste e credimi che rende il tuo tempo miserabile convincere l'intervistatore. Se ho intrinseco tutte le risposte dall'alto, allora devo aggiungere un altro punto chiave per renderlo più convincente e utilizzare OO al meglio

Nel caso in cui non si stia pianificando alcuna modifica alle regole , per seguire la sottoclasse, per un lungo futuro, selezionare l'interfaccia, poiché non sarà possibile modificarla e, in tal caso, è necessario modifiche in tutte le altre sottoclassi, mentre, se si pensa, si desidera riutilizzare la funzionalità, impostare alcune regole e anche renderla aperta per la modifica , selezionare la classe Abstract.

Pensa in questo modo, hai usato un servizio di consumo o hai fornito un po 'di codice al mondo e hai la possibilità di modificare qualcosa, supponi un controllo di sicurezza E se sono un consumatore del codice e una mattina dopo un aggiornamento, io trova tutti i segni di lettura nel mio Eclipse, l'intera applicazione non funziona. Quindi, per evitare tali incubi, usa Abstract over Interfaces

Penso che questo potrebbe convincere l'intervistatore in una certa misura ... Interviste felici avanti.


2

Quando provo a condividere il comportamento tra 2 classi strettamente correlate, creo una classe astratta che detiene il comportamento comune e funge da genitore per entrambe le classi.

Quando provo a definire un Tipo, un elenco di metodi su cui un utente del mio oggetto può fare affidamento in modo affidabile, quindi creo un'interfaccia.

Ad esempio, non creerei mai una classe astratta con 1 sottoclasse concreta perché le classi astratte riguardano la condivisione del comportamento. Ma potrei benissimo creare un'interfaccia con una sola implementazione. L'utente del mio codice non saprà che esiste una sola implementazione. Infatti, in una versione futura potrebbero esserci diverse implementazioni, tutte sottoclassi di qualche nuova classe astratta che non esisteva nemmeno quando ho creato l'interfaccia.

Potrebbe anche sembrare un po 'troppo bookish (anche se non l'ho mai visto mettere in quel modo ovunque mi ricordi). Se l'intervistatore (o l'OP) volesse davvero più della mia esperienza personale su questo, sarei stato pronto con aneddoti di un'interfaccia che si sono evoluti per necessità e viceversa.

Un'altra cosa. Java 8 ora consente di inserire il codice predefinito in un'interfaccia, sfocando ulteriormente la linea tra interfacce e classi astratte. Ma da quello che ho visto, questa funzione è abusata anche dai creatori delle librerie core di Java. Quella funzionalità è stata aggiunta, giustamente, per rendere possibile l'estensione di un'interfaccia senza creare incompatibilità binaria. Ma se stai creando un nuovo tipo definendo un'interfaccia, allora l'interfaccia dovrebbe essere SOLO un'interfaccia. Se vuoi fornire anche un codice comune, allora crea una classe di supporto (astratta o concreta). Non ingombrare la tua interfaccia fin dall'inizio con funzionalità che potresti voler cambiare.


2

La differenza di base tra interfaccia e classe astratta è che l'interfaccia supporta l'ereditarietà multipla ma la classe astratta no.

In classe astratta puoi anche fornire tutti i metodi astratti come l'interfaccia.

perché è richiesta la classe astratta?

In alcuni scenari, durante l'elaborazione della richiesta dell'utente, la classe astratta non sa quale intenzione dell'utente. In quello scenario, definiremo un metodo astratto nella classe e chiederemo all'utente che estende questa classe, fornisci la tua intenzione nel metodo astratto. In questo caso le classi astratte sono molto utili

Perché è richiesta l'interfaccia?

Diciamo, ho un lavoro che non ho esperienza in quella zona. Esempio, se vuoi costruire un edificio o una diga, allora cosa farai in quello scenario?

  1. identificherai quali sono i tuoi requisiti e stipulerai un contratto con tali requisiti.
  2. Quindi chiama le offerte per costruire il tuo progetto
  3. Chi mai costruirà il progetto, dovrebbe soddisfare le tue esigenze. Ma la logica di costruzione è diversa da un fornitore all'altro.

Qui non mi preoccupo della logica di come hanno costruito. L'oggetto finale ha soddisfatto o meno le mie esigenze, quello solo il mio punto chiave.

Qui i tuoi requisiti chiamati interfaccia e costruttori sono chiamati implementatore.


2

In poche parole, risponderei in questo modo:

  • l'ereditarietà tramite la gerarchia di classi implica un'eredità di stato ;
  • che l'ereditarietà tramite interfacce rappresenta l' ereditarietà del comportamento ;

Le classi astratte possono essere trattate come qualcosa tra questi due casi (introduce un certo stato ma ti obbliga anche a definire un comportamento), una classe completamente astratta è un'interfaccia (questo è un ulteriore sviluppo delle classi costituito da metodi virtuali solo in C ++ come per quanto ne so della sua sintassi).

Naturalmente, a partire da Java 8 le cose sono leggermente cambiate, ma l'idea è sempre la stessa.

Immagino che questo sia abbastanza per un'intervista tipica di Java, se non vieni intervistato da un team di compilatori.


1

Da quello che ho capito, un'interfaccia, che comprende variabili e metodi finali senza implementazioni, è implementata da una classe per ottenere un gruppo di metodi o metodi che sono collegati tra loro. D'altra parte, una classe astratta, che può contenere variabili e metodi non finali con implementazioni, viene solitamente utilizzata come guida o come superclasse da cui ereditano tutte le classi correlate o simili. In altre parole, una classe astratta contiene tutti i metodi / variabili che sono condivisi da tutte le sue sottoclassi.


1

In classe astratta, puoi scrivere l'implementazione predefinita dei metodi! Ma in Interface non puoi. Fondamentalmente, nell'interfaccia esistono metodi virtuali puri che devono essere implementati dalla classe che implementa l'interfaccia.


1

Sì, le tue risposte erano tecnicamente corrette, ma il punto in cui hai sbagliato non le mostrava che capisci gli aspetti positivi e negativi della scelta l'uno rispetto all'altro. Inoltre, erano probabilmente preoccupati / impazziti per la compatibilità della loro base di codice con gli aggiornamenti in futuro. Questo tipo di risposta potrebbe aver aiutato (oltre a quello che hai detto):

"La scelta di una classe astratta rispetto a una classe di interfaccia dipende da ciò che proiettiamo nel futuro del codice.

Le classi astratte consentono una migliore compatibilità diretta poiché è possibile continuare ad aggiungere comportamenti a una classe astratta anche in futuro senza rompere il codice esistente -> questo non è possibile con una classe di interfaccia.

D'altra parte, le classi di interfaccia sono più flessibili delle classi astratte. Questo perché possono implementare più interfacce . Il fatto è che Java non ha eredità multiple, quindi l'uso di classi astratte non ti permetterà di usare qualsiasi altra struttura gerarchica di classi ...

Quindi, alla fine, una buona regola generale è: preferisci usare le Classi di interfaccia quando non ci sono implementazioni esistenti / predefinite nella tua base di codice. E usa le classi astratte per preservare la compatibilità se sai che aggiornerai la tua classe in futuro. "

Buona fortuna per la tua prossima intervista!


1

Proverò a rispondere usando uno scenario pratico per mostrare la distinzione tra i due.

Le interfacce hanno un payload pari a zero, cioè nessuno stato deve essere mantenuto e quindi sono la scelta migliore per associare un contratto (capacità) a una classe.

Ad esempio, supponiamo che io abbia una classe Task che esegue alcune azioni, ora per eseguire un'attività in thread separato non ho davvero bisogno di estendere la classe Thread piuttosto che la scelta migliore è quella di fare in modo che Task esegua l'interfaccia Runnable (cioè implementi il ​​suo metodo run () ), quindi passa l'oggetto di questa classe Task a un'istanza di Thread e chiama il suo metodo start ().

Ora puoi chiedere cosa succede se Runnable era una classe astratta?

Beh, tecnicamente ciò è stato possibile, ma dal punto di vista del design sarebbe stata una scelta sbagliata, perché

  • Runnable non ha uno stato ad esso associato e neppure "offre" alcuna implementazione predefinita per il metodo run ()
  • Il compito dovrebbe estenderlo, quindi non potrebbe estendere nessun'altra classe
  • L'attività non ha nulla da offrire come specializzazione per la classe Runnable, tutto ciò che serve è sovrascrivere il metodo run ()

In altre parole, la classe Task aveva bisogno di essere eseguita in un thread che aveva ottenuto implementando versi dell'interfaccia Runnable che estendevano la classe Thread che lo avrebbe trasformato in un thread.

Mettici semplicemente l'interfaccia per definire una capacità (contratto), mentre usa una classe astratta per definire l'implementazione scheletrica (comune / parziale) di essa.

Disclaimer: segue l'esempio sciocco, cerca di non giudicare :-P

interface Forgiver {
    void forgive();
}

abstract class GodLike implements Forgiver {
    abstract void forget();
    final void forgive() {
        forget();
    }
}

Ora ti è stata data la scelta di essere come Dio, ma puoi scegliere di essere solo perdonatore (cioè non GodLike) e fare:

class HumanLike implements Forgiver {
    void forgive() {
       // forgive but remember    
    }
}

Oppure puoi scegliere di essere come Dio e fare:

class AngelLike extends GodLike {
    void forget() {
       // forget to forgive     
    }
}

PS con interfaccia java 8 può anche avere metodi statici e predefiniti (implementazione sostituibile) e quindi l'interfaccia b / n di differenza e la classe astratta sono ancora più ristrette.


1

Quasi tutto sembra essere già trattato qui .. Aggiungendo solo un altro punto sull'implementazione pratica della abstractclasse:

abstractla parola chiave viene utilizzata anche solo per impedire un'istanza di una classe. Se hai una classe concreta di cui non vuoi essere istanziata, creala abstract.


1

hmm ora le persone hanno un approccio pratico alla fame, hai ragione, ma la maggior parte degli intervistatori osserva il loro requisito attuale e desidera un approccio pratico.

dopo aver finito la risposta dovresti saltare sull'esempio:

Astratto:

per esempio abbiamo una funzione salariale che ha alcuni parametri comuni a tutti i dipendenti. allora possiamo avere una classe astratta chiamata CTC con un corpo del metodo parzialmente definito e si estenderà da tutti i tipi di dipendenti e verrà ridisegnato secondo i loro extra. Per funzionalità comune.

public abstract class CTC {

    public int salary(int hra, int da, int extra)
    {
        int total;
        total = hra+da+extra;
        //incentive for specific performing employee
        //total = hra+da+extra+incentive;
        return total;
    }
}

class Manger extends CTC
{
}


class CEO extends CTC
{
}

class Developer extends CTC
{   
}

Interfaccia

L'interfaccia in Java consente di avere funzionalità interfacce senza estenderla e devi essere chiaro con l'implementazione della firma della funzionalità che vuoi introdurre nella tua applicazione. ti costringerà ad avere definiton. Per diverse funzionalità.

public interface EmployeType {

    public String typeOfEmployee();
}

class ContarctOne implements EmployeType
{

    @Override
    public String typeOfEmployee() {
        return "contract";
    }

}

class PermanentOne implements EmployeType
{

    @Override
    public String typeOfEmployee() {
        return "permanent";
    }

}

puoi avere tale attività forzata con classe astratta anche da metghi definiti come astratti, ora una classe che estende la classe astratta ricorda quella astratta fino a quando non ha la precedenza su quella funzione astratta.


1

Da quello che ho capito e come mi avvicino,

L'interfaccia è come una specifica / contratto, qualsiasi classe che implementa una classe di interfaccia deve implementare tutti i metodi definiti nella classe astratta (tranne i metodi predefiniti (introdotti in Java 8))

Considerando che definisco un abstract di classe quando conosco l'implementazione richiesta per alcuni metodi della classe e alcuni metodi ancora non so quale sarà l'implementazione (potremmo conoscere la firma della funzione ma non l'implementazione). Lo faccio in modo che più avanti nella parte dello sviluppo quando so come devono essere implementati questi metodi, posso semplicemente estendere questa classe astratta e implementare questi metodi.

Nota: non è possibile avere il corpo della funzione nei metodi di interfaccia a meno che il metodo non sia statico o predefinito.


0

Credo che ciò che l'intervistatore stava cercando di ottenere fosse probabilmente la differenza tra interfaccia e implementazione.

L'interfaccia - non un'interfaccia Java, ma "interfaccia" in termini più generali - a un modulo di codice è, sostanzialmente, il contratto stipulato con il codice client che utilizza l'interfaccia.

L'implementazione di un modulo di codice è il codice interno che fa funzionare il modulo. Spesso è possibile implementare una particolare interfaccia in più di un modo diverso e persino cambiare l'implementazione senza che il codice client sia a conoscenza della modifica.

Un'interfaccia Java deve essere utilizzata solo come interfaccia nel senso generico sopra indicato, per definire il comportamento della classe a vantaggio del codice client che utilizza la classe, senza specificare alcuna implementazione. Pertanto, un'interfaccia include le firme dei metodi - i nomi, i tipi restituiti e gli elenchi di argomenti - per i metodi che dovrebbero essere chiamati dal codice client e, in linea di principio, dovrebbero avere un sacco di Javadoc per ogni metodo che descriva cosa fa quel metodo. Il motivo più convincente per l'utilizzo di un'interfaccia è se si prevede di avere più implementazioni diverse dell'interfaccia, magari selezionando un'implementazione in base alla configurazione di distribuzione.

Una classe astratta Java, al contrario, fornisce un'implementazione parziale della classe, piuttosto che avere uno scopo primario di specificare un'interfaccia. Dovrebbe essere usato quando più classi condividono il codice, ma quando ci si aspetta che anche le sottoclassi forniscano parte dell'implementazione. Ciò consente al codice condiviso di apparire in un solo posto - la classe astratta - chiarendo al contempo che parti dell'implementazione non sono presenti nella classe astratta e dovrebbero essere fornite da sottoclassi.


0

la tua risposta è giusta ma l'intervistatore ha bisogno che tu faccia una distinzione in base alla prospettiva di ingegneria del software e non in base ai dettagli di Java.

Parole semplici:

Un'interfaccia è come l'interfaccia di un negozio tutto ciò che viene mostrato dovrebbe essere lì nel negozio, quindi qualsiasi metodo nell'interfaccia deve essere lì implementato nella classe concreta. Ora cosa succede se alcune classi condividono alcuni metodi esatti e varia in altri. Supponiamo che l'interfaccia riguardi un negozio che contiene due cose e supponiamo che abbiamo due negozi che contengono entrambi attrezzature sportive ma uno ha vestiti extra e l'altro ha scarpe extra. Quindi quello che fai è fare una lezione astratta per lo Sport che implementa il metodo Sport e lasci l'altro metodo non implementato. Classe astratta qui significa che questo negozio non esiste in sé ma è la base per altre classi / negozi. In questo modo si sta organizzando il codice, evitando errori di replica del codice, unificando il codice e garantendo la riusabilità da parte di un'altra classe.

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.