Equivalente o profondo, quale è idiomatico in Java?

3

Ho un modello di dominio in cui utilizzo alcune relazioni di aggregazione, cioè un oggetto di classe A contiene zero o più oggetti di classe B .

Uso Java per l'implementazione e rappresento una tale aggregazione come un campo di tipo List<B> in A , e un campo di tipo A in B . In questo modo, ogni oggetto può essere la radice di un albero di aggregazione. Classi A e B possono anche contenere altri campi shallow , cioè campi di tipo int , float , String e così via.

Ora ho bisogno di definire diversi tipi di metodi di uguaglianza sul mio modello:

  1. Uguaglianza ridotta : confronta due istanze di A confrontando solo i suoi campi poco profondi, ad esempio tralasciando i riferimenti ad altri oggetti di dominio. In questo caso, mi interessa solo sapere se due nodi hanno lo stesso contenuto.
  2. Uguaglianza profonda : confronta due istanze di A confrontando i suoi campi poco profondi e confrontando ricorsivamente i suoi figli. In questo caso, voglio controllare se due alberi completi sono uguali.

Ho preso in considerazione l'override dei metodi hashCode() e equals() per la classe A , ma non so se questo dovrebbe essere l'uguaglianza superficiale o il metodo dell'uguaglianza profonda. Una volta deciso quale dei due metodi di uguaglianza è implementato come A.equals() , definirò l'altro metodo con un altro nome. Questa è una scelta importante perché il metodo equals() determina cose come l'appartenenza a Set .

Quindi, una delle due possibilità (shallow vs deep ugality) è considerata una scelta più idiomatica per l'implementazione del metodo equals in Java?

    
posta Giorgio 18.01.2014 - 17:45
fonte

4 risposte

10

Preferisco pensare a "uguale" in questo modo: se a.equals (b), allora puoi sostituire tutti i riferimenti a b con i riferimenti a a e il comportamento del programma non cambierà. Questo è vero per le classi di valori immutabili come String e dovrebbe essere vero per le classi quasi-valore come Date. Penso che questo è il modo in cui la maggior parte dei programmatori Java si aspetta un comportamento "uguale".

Definire gli uguali in un altro modo, in modo che le cose siano in ordine di grandezza, è probabile che porti a bug sottili quando qualche futuro programmatore mette queste istanze in una tabella hash o in un set. Quel programmatore ti odierà per sempre.

    
risposta data 18.01.2014 - 21:51
fonte
4

This is an important choice because the equals() method determines such things as membership in a Set.

In qualche modo hai risposto alla tua domanda lì. È una tua decisione basata su le tue esigenze . Se hai bisogno che i tuoi oggetti vengano posizionati in Set in base all'uguaglianza superficiale , devi implementare equals() e hashcode() di conseguenza. Se hai bisogno di basarlo sull'uguaglianza deep , lo implementerai in questo modo.

    
risposta data 18.01.2014 - 18:39
fonte
1

Come dice l'altra risposta, devi decidere in base alle tue esigenze.

Qualcos'altro da considerare è che devi confrontare l'uguaglianza dei campi nel tuo oggetto usando la tua decisione su ciò che è importante, ma lascia che quegli stessi oggetti decidano che cosa è importante al loro interno.

quindi se hai class A con int x , int[] y e B z allora:

Confrontate x? Confrontate y? Confrontate z? Quelle sono le tue scelte. Il confronto y richiederebbe quasi certamente l'uso di Arrays.equals() come si vorrebbe confrontare tutti i membri di y.

Se il metodo .equals() nella classe B va avanti per fare un ulteriore confronto approfondito dei suoi membri è quindi una decisione che deve essere delegata a quella classe B. Non proverai a fare un confronto tra il contenuto di B da all'interno di A, a meno che tu non abbia davvero dovuto.

Quindi la scelta non è realmente "profonda" o meno. È ciò che i membri di questa classe devono essere confrontati. Se alcuni di questi membri sono Oggetti stessi, quegli oggetti definiscono il proprio algoritmo di uguaglianza e possono di nuovo scavare più in profondità in ulteriori oggetti membri o in super classi. Tuttavia, ogni fase si preoccupa solo della sua uguaglianza.

    
risposta data 18.01.2014 - 19:01
fonte
0

I riferimenti che sono tenuti allo scopo di identificare gli oggetti dovrebbero fare riferimento-a confronto. Le referenze che sono conservate allo scopo di incapsulare lo stato di un oggetto dovrebbero essere "profondamente" comparate. Le collezioni, tuttavia, rappresentano un problema in quanto l'uso di oggetti nella collezione non dipende dalla collezione stessa, ma dalla cosa che contiene un riferimento alla collezione. Le raccolte sono generalmente istanziate dal codice che sa come verranno utilizzati i contenuti, ma le raccolte di framework raramente forniscono alcun mezzo per fare una tale distinzione (ci sono alcuni tipi come IdentitySet che specificano chiaramente che le chiavi incapsulano l'identità, ma nessuna delle i tipi distinguono i loro contenuti abbastanza bene da consentire a equals o clone di operare al livello semantico appropriato.

    
risposta data 18.01.2014 - 19:44
fonte

Leggi altre domande sui tag