2012-04-20 9 views
7

Se implemento equals() e in entrambe le classi padre e figlio, è necessario chiamare super.equals() in equals() nella classe figlio, ad es.Chiamando super.equals e super.hashCode nella classe child?

public boolean equals(Object obj) { 

    if (obj.getClass() != ChildClass.class) { 
    return false; 
    } 

    return super.equals() && this.var == ((ChildClass) obj).var; 

} 
+0

P.S. Suppongo che la classe genitore non sia Object e dia la definizione corretta di 'equals' e' hashCode'. –

risposta

8

No, non è necessario e probabilmente si sbaglia. In effetti, parte del motivo per cui stai ignorando lo equal è perché super.equals non dà il comportamento corretto (giusto?).

In altre parole, se super.equals fornisce il comportamento corretto, probabilmente non è necessario risolvere il problema di sovrascriverlo.

Ma se si sta annullando equals, allora sì, è necessario eseguire l'override di hashCode.

+2

'SuperClass.equals' può ovviamente confrontare solo istanze' SuperClass' e non sa nulla di 'Sottoclassella'. Ecco perché 'SubClass' deve sovrascriverlo, anche se è perfettamente corretto in termini di' SuperClass'. Ma sarebbe sciocco reimplementare il suo comportamento in 'SubClass' (o in ognuna delle molte sottoclassi) invece di chiamare' super.equals' (prima di confrontare le parti di sottoclasse), giusto? –

+4

Bene, se l'uguaglianza dei valori viene implementata, può essere necessario chiamare 'super.equals()' per avere i campi ereditati controllati per l'uguaglianza ... – Alan

+0

in realtà, molte volte è sufficiente aggiungere controlli per campi aggiuntivi (come @ Alan ha detto), quindi è necessario chiamare 'super.equals()'. Inoltre, se si aggiungono solo campi, non si ha _need_ per sovrascrivere 'hashCode()'. – jtahlborn

2

Se la super classe non implementa eguali, super.equals quindi chiamando ti porterà l'attuazione dell'oggetto che confronta soltanto i riferimenti, così in qualsiasi normale uguale implementazione in cui si desidera confrontare una chiave di business sarebbe in realtà causa molti falsi negativi.

Detto questo, la tua implementazione sopra non è affatto diversa dalla semantica di quella predefinita in Object, dal momento che stai usando solo == per il confronto.

Per quanto riguarda l'hashCode, se si esegue l'override di uguali, è necessario sovrascrivere hashCode per mantenere il contratto dei due. Ad esempio, se si sta utilizzando una chiave aziendale per pari, è consigliabile utilizzare la stessa chiave aziendale per l'hashcode in modo che due oggetti uguali generino lo stesso codice hash.

0

EDIT

ho appena notato utilizzato l'uguaglianza di classe, non instanceof - il che significa che la riflessività sarebbe essere corretta. Nel tuo esempio, l'uso di super.equals è probabilmente corretto, purché la superclasse non fornisca una definizione di uguaglianza che è contro quella che la tua sottoclasse desidera (come ad esempio Object).

Il punto principale è che la definizione di uguaglianza dovrebbe provenire esattamente da un tipo (classe o interfaccia) nella gerarchia della classe. Se l'implementazione di tale definizione si avvale di super.equals, va bene.

END EDIT, testo originale sotto

E 'quasi certamente la cosa sbagliata da fare, perché violerebbe la proprietà riflettente di uguaglianza.

Supponiamo di avere una forma ed è uguale a un'altra forma se sono dello stesso tipo: quadrato uguale a quadrato, cerchio uguale a cerchio, ecc. Ora lo estendi per creare una cornice colorata che aggiunge un controllo del colore.

Shape shape1 = new Shape(SQUARE); 
Shape shape2 = new ColoredShape(SQUARE, RED); 

Si implementa ColoredSquare.equals come super.equals(other) && other.color == this.color, come nella sua interrogazione. Ma ora, si noti che shape1.equals(shape2) == true (dal shape1 utilizza solo il Shape.equals), ma shape2.equals(shape1) == false (poiché aggiunge il controllo del colore).

La morale della storia è che l'utilizzo di questo tipo di uguaglianza a cascata è davvero difficile, se non impossibile. Fondamentalmente, l'uguaglianza dovrebbe provenire esattamente da un tipo all'interno della tua gerarchia di tipi: sia Object, il tuo tipo stesso, un super tipo, o qualche interfaccia che definisce un contratto (es. Nel quadro delle collezioni, che definisce l'uguaglianza per Set, List, ecc.).

+0

La morale della storia è piuttosto che si dovrebbe ereditare solo da classi astratte, non da quelle concrete. È una violazione di questa regola che causa i problemi che descrivi bene, non chiamando 'super.equals' dal metodo' equals' della sottoclasse. –

+0

@ PéterTörök Non sono sicuro di come si possa applicare, dal momento che una classe astratta potrebbe ancora fornire 'equals' e' hashCode'. Nel mio esempio, fingere 'Shape' è astratto e ha due sottoclassi,' ColoredShape' e 'ColorlessShape', solo l'ultimo dei quali aggiunge il controllo del colore all'eguaglianza. Stesso problema. – yshavit

+0

No, perché se 'Shape' è astratto, non puoi avere semplici oggetti' Shape', solo 'ColoredShape's e/o' ColorlessShape's. E per questi è possibile implementare 'equals' correttamente con o senza riutilizzare' super.equals'. Perché non puoi mai avere una situazione in cui objectOfA * è un * B ma objectOfB * non è un * A. –

Problemi correlati