Newsgroup: it.comp.java
Titolo: Equals e ricorsivita'

scusate, ma mettiamo che la classe A è fatta così
class A {
	...un un po' di campi...
	private B objB;
}
e B così
class B {
	...un po' di campi...
	private A objA;
}
quando implemento equals o hashcode, non posso includere tutti i campi,
perché se da A uso B.equals e B.equals chiama A.equals vado in
ricorsione infinita.
Però formalmente per verificare che un A sia uguale a un altro A devo
verificare che tutti i suoi campi siano uguali. 
E quindi, come faccio?
-- 
Herbie


1) se l'implementazione di equals non è accorta va in StackOverflow.
2) indipendentemente da che gli oggetti A e B siano immutabili o no, il 
controllo d'uguaglianza sui riferimenti si può (e deve) fare nell'equals:
if (this == o) return true;
questo t'impedisce la ricorsione nel caso siano la stessa istanza.
se invece hai una catena d'oggetti (A1->B1, B1->A2, A2->B2...) allora 
scorre tutta la catena fino a che ricade o nel caso 1) o la risolve.
3) considera che in alcuni casi l'uguaglianza tra oggetti potrebbe non 
comprendere necessariamente l'uguaglianza di tutti gli attributi: 
dipende dal dominio applicativo.
--
sv.

 dipende dal dominio applicativo.
in effetti è vero, e non ci pensavo, e credo sia l'unica soluzione, a
meno di non tenere traccia dei nodi già "visitati"
-- 
Herbie

 a1.equals chiama b1.equals, che chiama a1.equals e così via
Pardon, sull'equals di A, chiamiamolo così, mi ero dimenticato la
condizione "==" sull'istanza. In effetti quel controllo dovrebbe
risolvere loop tipo A->B->A perché mi pare proprio che B chiama equals
di A con parametro A. Poi proverò 
-- 
Herbie

 dipende dal dominio applicativo.
Credo che questo sia il punto-chiave del discorso: il dominio 
applicativo! Se sei *sicuro* che un insieme di attributi sia in grado di 
discernere un oggetto da un altro (una cosiddetta "superchiave" parlando 
in termini relazionali), allora puoi tranquillamente includerli i 
equals() & hashcode(). Il discorso in effetti diventa ancora più 
delicato se si sta lavorando con la persistenza degli oggetti, dove due 
istanze diverse nella stessa JVM possono rappresentare lo "stesso" 
oggetto, con la complicazione che spesso gli ID non si sanno fino a 
quando non si salva sul database...
Ecco un ottimo punto di partenza:
http://community.jboss.org/wiki/EqualsandHashCode
oltre al sempreverde Effective Java:
http://java.sun.com/developer/Books/effectivejava/Chapter3.pdf
-- 
Dimitri De Franciscis
Phone:  
(+39) 3401570778
Website: 
http://www.megadix.it/

 equals() & hashcode(). 
In effetti, a parte il problema descritto, ne ho avuto e ne ho uno più
grosso concettualmente. 
Ho un oggetto O che ha un set temporale di attributi. Questo significa
che in un istante O ha un certo set di attributi, e questo set può
cambiare da istante a istante.
Ho trovato jTemporal che offre peraltro proprio la classe TemporalSet,
ma c'è un problema: un attributo A è composto da una serie di proprietà
A1..An che sono la "chiave", e da V che è il valore che ha in quel
momento.
Inizialmente ho definito equals dell'attributo su A1..An e V, ma questo
mi permetteva di inserire nel temporal set, in un istante, due attributi 
con uguale chiave A1...An ma diverso valore. Cosa che non deve accadere. 
Ora ho optato di avere O che ha una collezione di TipologieDiAttributo,
ognuna avente attributi A1..An e equals definito su A1..An, e poi ogni
TipologiaDiAttributo ha al suo interno un attributo temporale, dove si
ha un solo valore per ogni istante.
Però per certi versi mi era comodo evitare il livello
TipologiaDiAttributo.
Riassumendo, ho: O->Collection<TipologiaAttributo>,
TipologiaAttributo->TemporalAttribute<Valore>
Effettivamente, credo corrisponda alla rappresentazione che dovrò avere
su db.
In un certo senso ho sperimentato l'equivalenza tra
TemporalSet<AttributiConValore> e Set<AttributiSenzaValore> più
AttributiSenzaValore->TemporalAttribute<Valore>
-- 
Herbie

 ricorsione infinita.
certo, se non presti attenzione finisce in un loop infinito ogni tre
per due, la struttura è palesemente prona a questo tipo di errore.
prova ad esempio a fare questa modifica al codice apparentemente
innocua (banale inizializzazione delle variabili):
private B objB = new B();
...
private A objA = new A();
poi istanza uno a caso dei due oggetti e vedi che succede...
io rifletterei bene sulla struttura invece di focalizzarmi
sull'equals.