2015-06-17 17 views
19

Io uso una biblioteca dove una classe astratta sostituisce un metodo concreto ereditato da Object con un metodo astratto:Perché una classe astratta può forzare un metodo concreto per essere sovrascritto?

public abstract class A { 
    @Override 
    public abstract boolean equals(Object obj); 
} 

Per estendere questa classe, devo implementare il metodo equals:

public class B extends A { 
    @Override 
    public boolean equals(Object obj) { 
     return obj != null && obj.getClass() == B.class; 
    } 
} 

Perché un metodo astratto (A::equals) sovrascrive un metodo concreto (Object::equals)? Non vedo l'obiettivo di questo.

+1

È il contrario qui: la classe base ha un metodo astratto e una classe derivata non astratta ha un metodo non astratto che sovrascrive il metodo della classe base. – sharptooth

+1

@sharptooth La mia domanda non era molto chiara. Sto parlando di 'A :: equals' che sovrascrive' Object :: equals' – gontard

+0

Immagino che dovresti dirlo esplicitamente nella domanda. Dato che hai presentato solo due dei tuoi corsi, ero sicuro che la domanda riguardasse solo loro. – sharptooth

risposta

24

In questo specifico esempio ha perfettamente senso. Se le sottoclassi di A sono pensate per essere utilizzate nelle collezioni, dove lo standard equals è ampiamente utilizzato per individuare gli oggetti, il metodo equals del metodo A ti costringe a dare un'implementazione non predefinita di equals in qualsiasi sottoclasse di A (invece di utilizzando l'implementazione predefinita della classe Object che confronta solo i riferimenti all'istanza).

Ovviamente, l'implementazione suggerita di equals in B ha poco senso. Dovresti confrontare le proprietà delle istanze 2 B per determinare se sono uguali.

Questa è un'implementazione più adatto:

public class B extends A { 
    @Override 
    public boolean equals(Object obj) { 
     if (!(obj instanceof B)) 
      return false; 
     B other = (B) obj; 
     return this.someProperty.equals(other.someProperty) && this.secondProperty.equals(other.secondProperty); 
    } 
} 

Inoltre, ricordarsi di eseguire l'override hashCode ogni volta che si sostituisce equals (dato che il contratto di equals e hashCode richiede che se a.equals(b) == true poi a.hashCode() == b.hashCode()).

+0

Se 'B' non ha altre proprietà (e nessuno dei due ha' A') che rende le istanze diverse l'una dall'altra, un l'implementazione come nella domanda potrebbe essere ragionevole. Sebbene il confronto con l'istanza 'this.getClass()' di 'B.class' sarebbe più corretto quando si considerano le sottoclassi di' B'. –

+0

Sì, forse 'B' è un Singleton – acbabis

10

Perché in questo caso, si desidera che gli oggetti definiscano il proprio equals, che si suppone si comportino diversamente dall'implementazione predefinita.

Non si dovrebbe considerare questo come rimuovendo la funzionalità, ma piuttosto come imporre che gli oggetti ereditari implementino il proprio.

+0

Sei miope, ho davvero visto questo * come la rimozione della funzionalità *. – gontard

+0

@gontard: in questo caso, * si desidera * implementare le classi per stabilire il proprio comportamento. Per fare ciò, è necessario assicurarsi che l'implementazione predefinita non sia accessibile in modo da ottenere il comportamento desiderato. – npinti

+0

In realtà [è ancora accessibile] (http://stackoverflow.com/a/2692379/823393) ma non è affatto facile. – OldCurmudgeon

6

Ciò consentirebbe di forzare una sottoclasse a reimplementare un metodo. Se questa è una buona idea o no è un'altra questione. Lo farebbe solo se si volesse applicare un contratto più forte rispetto al metodo originale fornito. Dovresti quindi documentare attentamente il nuovo contratto.

3

significa che necessario implementare il proprio metodo di equals()

1

Perché tutte le classi in Java intrinsecamente estendono la classe Object. La classe A erediterà il metodo Object#equals. Si supponga di voler forzare un errore di compilazione quando il metodo equals non è implementato esplicitamente come in questo example. Rendere astratto il metodo equals senza un blocco di implementazione ti permetterebbe di farlo.