Perché una classe astratta che implementa un'interfaccia può perdere la dichiarazione / implementazione di uno dei metodi dell'interfaccia?


123

Una cosa curiosa accade in Java quando si utilizza una classe astratta per implementare un'interfaccia: alcuni dei metodi dell'interfaccia possono mancare completamente (cioè non è presente né una dichiarazione astratta né un'implementazione effettiva), ma il compilatore non si lamenta.

Ad esempio, data l'interfaccia:

public interface IAnything {
  void m1();
  void m2();
  void m3();
}

la seguente classe astratta viene allegramente compilata senza un avviso o un errore:

public abstract class AbstractThing implements IAnything {
  public void m1() {}
  public void m3() {}
}

Puoi spiegare perché?


2
Non si può creare un oggetto di una classe astratta. Quindi, finché non viene fornita un'implementazione per una classe astratta, non è possibile creare oggetti per IAnything. Quindi questo va assolutamente bene per il compilatore. Il compilatore si aspetta che, qualsiasi classe non astratta che implementa IAnything deve implementare tutti i metodi dichiarati da IAnything. E poiché è necessario estendere e implementare AbstractThing per poter creare oggetti, il compilatore genererà un errore, se tale implementazione non implementa i metodi di IAnything tralasciati da AbstractThing.
VanagaS

Avevo una classe concreta che estendeva il proprio "AbstractThing" in uno scenario identico a questo, e anche se non avevo implementato uno dei metodi nell'interfaccia, si stava inspiegabilmente compilando. Ora sta facendo quello che mi aspetto, ma non riesco a capire cosa stesse causando il successo prima. Sospetto di non avere :wuno dei file.
Braden Best

puoi vedere la risposta per una domanda simile stackoverflow.com/questions/8026580/…
Do Nhu Vy

Risposte:


156

Questo perché se una classe è astratta, per definizione ti viene richiesto di creare sottoclassi di essa per istanziarla. Le sottoclassi saranno richieste (dal compilatore) per implementare tutti i metodi di interfaccia che la classe astratta ha omesso.

Seguendo il codice di esempio, prova a creare una sottoclasse di AbstractThingsenza implementare il m2metodo e guarda quali errori ti dà il compilatore. Ti costringerà a implementare questo metodo.


1
Penso che il compilatore dovrebbe comunque lanciare avvertimenti riguardanti classi astratte che implementano interfacce in modo incompleto, semplicemente perché è necessario esaminare 2 definizioni di classe anziché 1 per vedere cosa è necessario in una sottoclasse. Questa è una limitazione del linguaggio / compilatore.
workmad3

3
Non sarebbe una buona idea, poiché in genere possono esserci molte classi astratte e gli avvisi "falsi" presto ti travolgerebbero, facendoti perdere gli avvisi "veri". Se ci pensi, la parola chiave 'abstract' è lì specificamente per dire al compilatore di sopprimere gli avvisi per quella classe.
belugabob

4
@workmad - se hai implementazioni comuni per un sottoinsieme di metodi di interfaccia, ha più senso scomporlo in una classe base separata (DRY prevale sul codice a un posto)
Gishu

4
Sarebbe pericoloso richiedere di inserire implementazioni di metodi vuote in una classe astratta. Se lo facessi, gli implementatori delle sottoclassi erediterebbero questo non comportamento senza che il compilatore dica loro che c'è un problema.
Bill the Lizard

8
Penso che ciò che workmad potrebbe suggerire è di definire i metodi nella classe astratta senza un corpo del metodo e contrassegnarli come astratti. Non mi sembra una cattiva idea.
Dónal

33

Perfettamente bene.
Non puoi istanziare classi astratte ... ma le classi astratte possono essere usate per ospitare implementazioni comuni per m1 () e m3 ().
Quindi, se l' implementazione di m2 () è diversa per ciascuna implementazione, ma m1 e m3 non lo sono. È possibile creare diverse implementazioni concrete di IAnything solo con la diversa implementazione m2 e derivare da AbstractThing, onorando il principio DRY. Convalidare se l'interfaccia è completamente implementata per una classe astratta è inutile.

Aggiornamento : è interessante notare che C # lo impone come errore di compilazione. Sei costretto a copiare le firme del metodo e anteporre loro 'abstract public' nella classe base astratta in questo scenario .. (qualcosa di nuovo ogni giorno :)


7

Va bene. Per capire quanto sopra, devi prima capire la natura delle classi astratte. Sono simili alle interfacce da questo punto di vista. Questo è ciò che Oracle dice al riguardo qui .

Le classi astratte sono simili alle interfacce. Non è possibile istanziarli e possono contenere una combinazione di metodi dichiarati con o senza un'implementazione.

Quindi devi pensare a cosa succede quando un'interfaccia estende un'altra interfaccia. Per esempio ...

//Filename: Sports.java
public interface Sports
{
   public void setHomeTeam(String name);
   public void setVisitingTeam(String name);
}

//Filename: Football.java
public interface Football extends Sports
{
   public void homeTeamScored(int points);
   public void visitingTeamScored(int points);
   public void endOfQuarter(int quarter);
}

... come puoi vedere, anche questo si compila perfettamente. Semplicemente perché, proprio come una classe astratta, NON è possibile istanziare un'interfaccia. Quindi, non è necessario menzionare esplicitamente i metodi dal suo "genitore". Tuttavia, TUTTE le firme del metodo genitore FANNO implicitamente parte dell'interfaccia che si estende o implementa la classe astratta. Quindi, una volta che una classe appropriata (una che può essere istanziata) estende quanto sopra, sarà richiesto di garantire che ogni singolo metodo astratto sia implementato.

Spero che questo aiuti ... e Allahu 'alam!


Questo è un punto di vista interessante. Mi fa pensare che le "classi astratte" siano realmente "interfacce concrete", cioè interfacce con alcuni metodi concreti, piuttosto che classi con alcuni metodi astratti.
Giulio Piancastelli

... un po 'entrambe le cose davvero. Ma una cosa è certa, non sono istanziabili.
Grato

4

Interfaccia indica una classe che non ha implementazione del proprio metodo, ma solo con dichiarazione.
D'altra parte, la classe astratta è una classe che può avere l'implementazione di un metodo insieme a un metodo con solo dichiarazione, nessuna implementazione.
Quando implementiamo un'interfaccia per una classe astratta, significa che la classe astratta ha ereditato tutti i metodi dell'interfaccia. Poiché, non è importante implementare tutto il metodo nella classe astratta, tuttavia si tratta di una classe astratta (anche per ereditarietà), quindi la classe astratta può lasciare parte del metodo nell'interfaccia senza implementazione qui. Ma, quando questa classe astratta verrà ereditata da una classe concreta, dovranno implementare tutti quei metodi non implementati presenti nella classe astratta.


4

Data l'interfaccia:

public interface IAnything {
  int i;
  void m1();
  void m2();
  void m3();
}

Questo è il modo in cui Java lo vede effettivamente:

public interface IAnything {
  public static final int i;
  public abstract void m1();
  public abstract void m2();
  public abstract void m3();
}

Quindi puoi lasciare alcuni (o tutti) questi abstractmetodi non implementati, proprio come faresti nel caso di abstractclassi che estendono un'altra abstractclasse.

Quando si implementan interface, la regola che tutti i interfacemetodi devono essere implementati nel derivato class, si applica solo classall'implementazione concreta (cioè, che non è di per abstractsé).

Se hai davvero intenzione di crearne uno abstract class, allora non esiste una regola che ti dica che devi utilizzare implementtutti i interfacemetodi (nota che in tal caso è obbligatorio dichiarare il derivato classcome abstract)


Utilizzo javap IAnything.classper generare il secondo frammento di codice.
sharhp

3

Quando una classe astratta implementa un'interfaccia

Nella sezione sulle interfacce, è stato notato che una classe che implementa un'interfaccia deve implementare tutti i metodi dell'interfaccia. È possibile, tuttavia, definire una classe che non implementa tutti i metodi dell'interfaccia, a condizione che la classe sia dichiarata astratta. Per esempio,

abstract class X implements Y {   
    // implements all but one method of Y
}

class XX extends X {   
    // implements the remaining method in Y 
} 

In questo caso, la classe X deve essere astratta perché non implementa completamente Y, ma la classe XX, infatti, implementa Y.

Riferimento: http://docs.oracle.com/javase/tutorial/java/IandI/abstract.html


1

Le classi astratte non sono necessarie per implementare i metodi. Quindi, anche se implementa un'interfaccia, i metodi astratti dell'interfaccia possono rimanere astratti. Se provi a implementare un'interfaccia in una classe concreta (cioè non astratta) e non implementi i metodi astratti, il compilatore ti dirà: o implementa i metodi astratti o dichiara la classe come astratta.

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.