2011-11-13 8 views
15

Qual è il motivo della decisione di includere questi metodi in java.lang.Object? L'uguaglianza e l'hashing non hanno senso per molte classi.Perché equals e hashCode sono stati definiti in Object?

Sarebbe più logico fare due interfacce:

interface Equalable { 
    boolean equals(Equalable other); 
} 

interface Hashable extends Equalable { 
    int hashCode(); 
} 

Per esempio definizione HashSet potrebbe essere simile

class HashSet<T extends Hashable> ... 

Si eviterebbe uno degli errori più comuni principiante - utilizzando insieme di elementi, senza implementazione equals/hashCode.

+0

Date un'occhiata [qui] (http://msmvps.com/blogs/jon_skeet/archive/2008/12/05/redesigning-system-object-java-lang-object.aspx) per un buon articolo su qualcosa related (di Jon Skeet). Il collegamento –

+1

sembra morto. [Questo] (http://codeblog.jonskeet.uk/2008/12/05/redesigning-system-object-java-lang-object/) potrebbe essere lo stesso articolo. – tkokasih

risposta

13

Quando implementiamo un Interface abbiamo il contratto definito dall'interfaccia inject (or accept).

Equalable & Hashable sono due contratti diversi. Ma se osserviamo da vicino, vedremo che entrambi dipendono l'uno dall'altro, il che significa che fanno parte di uno single interface, qualcosa come EqualableAndHashable.

Ora la domanda ovvia è se debbano essere parte di questa nuova interfaccia EqualableAndHashable o Object?

Scopriamolo. Abbiamo == (equal operator) per controllare l'uguaglianza di due oggetti. L'operatore == conferma se valori/riferimenti sono uguali per due diversi primitivi/oggetti. Tuttavia, non è sempre possibile rispondere semplicemente controllando con l'operatore ==.

Ora la domanda è se questa uguaglianza, which is also a contract, debba essere iniettata tramite interfacce o parte della classe Object?

Se diamo uno sguardo, non possiamo semplicemente dire qualcosa del tipo:

TypeX non garantisce il contratto uguaglianza.

Diventerà un caos se alcuni tipi di oggetto offrono uguaglianza e altri no. Il che significa che l'oggetto di TypeX deve rispettare il contratto di uguaglianza che è vero anche per tutti gli altri tipi di oggetto. Quindi, non deve iniettare l'uguaglianza da un'interfaccia, perché l'uguaglianza dovrebbe essere la parte del contratto per qualsiasi oggetto per impostazione predefinita, altrimenti creerà il caos.

Quindi abbiamo bisogno di Oggetti per realizzare l'implementazione di equals. Ma non può implementare solo il metodo equals, ma deve anche implementare il metodo hashcode.

+2

'=' è in realtà l'operatore di assegnazione;) –

+0

@DaveNewton grazie. modificato di conseguenza – Kowser

+1

Non capisco il "caos" di cui parli. Attuo sempre questi metodi per utilizzare le mie lezioni in Set e Maps. Sarebbe più semplice per me evitare l'implementazione predefinita a tutti i costi, quindi sono a rimuovere questi metodi da Object. : D –

1

(Personalmente, se fossero in un'interfaccia, mi piacerebbe entrambi messo lì per evitare almeno una classe di equals/hashCode errori.)

Penso che ci si vuole un'implementazione in oggetto, come un meccanismo di fall-back, il che significa che tutto avrebbe comunque un'implementazione, un'interfaccia o meno.

Sospetto che sia molto storico; la programmazione di Java oggi sembra piuttosto diversa rispetto alla programmazione di Java.

0

È un'implementazione generica. Dovresti scavalcare l'implementazione se ne hai bisogno. Altrimenti hai un'implementazione predefinita ragionevole.

Almeno l'equivalente è un must. La creazione di interfacce per le operazioni di base probabilmente comporterebbe un sovraccarico.

+0

Il tuo punto di essere? – delnan

1

Mhh non sono sicuro, ma quando Java 1.0 è stato rilasciato i generici non esistevano ancora. Sono stati aggiunti in Java 5.0 nel 2004, quindi la proposta non può essere implementata per Java 1.0

+2

Se 'TreeSet' potrebbe richiedere chiavi per implementare' Comparable' se non è stato specificato 'Comparator', perché HashSet non potrebbe richiedere' Hashable'? C'è di più rispetto ai farmaci generici. – meriton

0

Se si dispone di un elenco di oggetti e si chiama il metodo contains, cosa deve fare Java? Penso che l'implementazione di default (confrontare i riferimenti) sia una decisione decente. In questo modo non dovrai implementare te stesso equals e hashcode per ogni classe che utilizzi in una raccolta.

1

Originariamente, in Java, non c'erano generici. Ciò è stato risolto consentendo a qualsiasi Object di essere un membro di qualsiasi raccolta, e quindi qualsiasi hashCode e equals. Ormai è troppo radicato per cambiare.

+0

L'assenza di generici è irrilevante. Ad esempio, non ha impedito a 'TreeSet' di richiedere chiavi per implementare' Comparable' se non è stato specificato 'Comparator'. – meriton

2

L'implementazione predefinita in java.lang.Object ha senso. Spesso, è abbastanza buono. In JPA/applicazioni web, mi trovo molto raramente, se mai sovrascrivendo equals e hashCode.

Una domanda migliore potrebbe essere: per oggetti di valore immutabile come String, Long ecc. Ho visto molti più errori a causa di quello che ho del default equivale a/hashCode che non sta facendo la cosa giusta. Ad esempio,

Long x = obj.getId(); 
Long y = obj2.getId(); 
if (x == y) { // oops, probably meant x.equals(y)! } 

E 'una domanda giusta, però, perché i metodi di default non sono bloccati dietro un'interfaccia di tagging come il default Object.clone(). Esiste un'implementazione predefinita, ma devi riconoscere esplicitamente che desideri utilizzarla implementando Cloneable. Potrebbe esserci un'interfaccia di tag simile come Collectible o Equitable, e quindi la firma per i metodi di raccolta avrebbe potuto essere Equitable anziché Object.

0

In realtà, è solo per comodità, ed è meglio così. Bene, pensare a cosa ci vorrebbe per fare uguaglianza oggetto se non aveste il metodo .equals:

AreEqual(Object obj1,Object obj2) { 
    if(!obj1 instanceof Equalable) return false; 
    if(!obj2 instanceof Equalable) return false; 
    return ((Equalable)(obj1).equals((Equalable)obj2); 
} 

Questo è vero anche per un hashCode. A volte l'uguaglianza di riferimento è sufficiente. Se hai reso HashSet accettato solo oggetti che implementano Hashable, allora dovresti rendere esplicitamente le tue classi, anche se vuoi solo l'uguaglianza di riferimento. E hai ridotto l'universalità di una struttura dati altrimenti eccezionale.

È meglio che Object abbia una funzione predefinita (e talvolta sufficiente) .equals e .hashCode e causi alcuni problemi per i nuovi arrivati, piuttosto che rendere più frequenti gli utenti della lingua attraverso una maggiore burocrazia.

0

Qualsiasi oggetto, indipendentemente dal suo tipo, può rispondere sensibilmente se è equivalente a qualsiasi altro oggetto, anche se il tipo di un altro oggetto è uno di cui non si ha mai sentito parlare. Se non si è mai sentito parlare del tipo di un altro oggetto, questo fatto da solo è sufficiente per segnalare che non è equivalente a quest'ultimo oggetto.