Newsgroup: it.comp.java
Titolo: L'oggetto si ripete!

Robe da matti:
un metodo (private) riceve un oggetto Sm, il suo compito è quello di
inserirlo in una TreeMap.
private Map pacco=new TreeMap();
protected void add(Sm messaggio) {
  pacco.put(new Integer(messaggio.hashCode()),messaggio);
 }
Questa chiamata viene fatta più volte passando oggetti diversi.
Se dicessi che alla prima chiamata l' Sm è 1, e alla seconda è 2 e alla
terza è 3
vi aspettereste che nel pacco vi siano 1, 2 e 3.
Invece il metodo riceve 1 2 e 3 ma se si prova a stampare il pacco, dentro
vi si troveranno ben numero 3 oggetti di tipo 3
Ho provato a stampare l'Sm passato al metodo ed è correttamente diverso ad
ogni volta.
Non so che inventare.
Idee ??
J

 vi aspettereste che nel pacco vi siano 1, 2 e 3.
Solo se l'hashcode trasformato in intero e' diverso ogni volta.
Davide

 Davide
Per 1 è 47916127
Per 2 è 1003822454
Eppure....
L'hash code è calcolato su parametri dell'oggetto Sm ed i parametri sono
diversi. L'hashcode (ho controllato) è diverso come si nota.
Era una ipotesi che avevo valutato
Ciao
J

Non è che per caso, dato che Java vede che l'oggetto memorizzato nel
pacchetto è sempre lo stesso, allora memorizza nella Map non il valore
dell'oggetto ma il suo riferimento in memoria ?
Quindi nella MAP trovo:
1) hash - addr.oggetto
2) hash2 - addr.oggetto
3) hash3 - addr.oggetto
e quando cambia l'oggetto l'addr rimanendo il medesimo mi spacca i messaggi
?
Come faccio a fargli memorizzare non l'indirizzo dell'oggetto passato al
metodo ma l'oggetto veramente ?
J

 Idee ??
Non e' una buona idea usare l'hashcode di un oggetto come chiave, perche' 
nessuno ti garantisce che sia una chiave primaria per l'oggetto, cioe' 
univoco. hashCode() e' usato da implementazioni di contenitori che usano 
approcci hash - e che gestiscono i casi di collisioni.
-- 
Life's something u don't get out alive..
ObjectZone - 
http://space.tin.it/computer/csadun

 metodo ma l'oggetto veramente ?
Ne crei uno diverso ogni volta...

 approcci hash - e che gestiscono i casi di collisioni.
Lo garantisce il fatto che l'algoritmo per l'hash code l'ho scritto io
appositamente :-)
J

Guarda l'altro mio post, in effetti il problema era proprio questo.
Dato che aggiungevo lo stesso messaggio modificato nei contenuti, nella MAP
veniva memorizzato l'indirizzo in cui era istanziato l'oggetto e non
l'oggetto in sč.
Facendo un new Sm() ogni volta che memorizzo un nuovo oggetto, il problema č
andato a posto.
Grazie cmq, la risposta sarebbe arrivata e questo č il bello dei ng
:-))
J


In ogni caso, concordo con Sadun che non e' l'approccio piu' corretto...
-- 
+-------------------+
| Bagnoli Roberto   |
| Nouvelle srl      |
| MODENA (ITALY)    |
| 
rbag...@orion.it
 |
+-------------------+

L'uso della treeMap č appositamente stato scelto proprio per gestire
collisioni e riunioni.
Sm č un oggetto SMS (messaggino gsm) e come tale deve essere memorizzato in
una struttura di contenimento che identifichi messaggi identici (stesso
dest-mitt e contenuto) o messaggi "uguali" (stesso mitt e testo, ma
destinatari diversi).
Il sistema deve "riunire" i messaggi uguali e sommare i destinatari per
avere un solo multi-sms.
Per ottenere una cosa di questo tipo, dovendo gestire in entrata 4-5000
messaggi per volta, convene usare l'hash code del messaggio che viene
calcolato una volta sola e poi utilizzato per riordinare e inserire i
messaggi nella struttura di contenimento, che a questo punto, lavora da sola
all'inserimento e riunuone dei messaggi.
L'overhead pagato dalla insert nella struttura dati č risparmiato dato che i
messaggi arrivano "piano piano" via rete. Una volta pagato tale overhead, i
messaggi sono gią pronti, riuniti, ordinati, non collisi per essere
utilizzati.
Ne vale la candela.
A titolo esemplificativo, 10.000 messaggi vengono letti in 1 secondo circa e
trasmessi in 3 minuti.
10.000 messaggi identici vengono letti in 2 minuti e trasmessi in 0.1
secondi.
Gią per i due casi teorici limiti, abbiamo un aumento di prestazioni di
circa 1 minuto secco, pari al 30% del tempo massimo per i 10.000 messaggi
tutti diversi (caso pessimo).
Ciao
J

 collisioni e riunioni.
Il senso di usare un algoritmo hash e' - lo dice il nome - di avere indici 
non univoci a fronte di chiavi univoche, per bilanciare velocita' e consumo 
di spazio. Se gli hash delle chiavi sono univoci, stai semplicemente usando 
un'array camuffato.


Consiglierei, comunque, di usare la chiamata:
System.identityHashCode(Object x)
che, come da doc. Sun, ritorna l'ID univoco dell'object "o"
per la JVM corrente.
Bye!
(non male come tips, vero?!?!? L'ho scoperto,
 quasi per caso, l'altro giorno! ;) :) )



che afferma:
    If two objects are equal according to the equals(Object) method,
    then calling the hashCode method on each of the two objects
    must produce the same integer result.
Esempio che dimostra quanto da me detto:
class Simple{
  public int n;
  Simple(int val) {n = val;}
  public int hashCode() {return n;}
  public boolean equals(Object obj) {
    return obj!= null && obj.getClass() == Simple.class
           && (this == obj || n == ((Simple)obj).n);
  }
  public static void main(String [] args){
    Simple a = new Simple(1);
    Simple b = new Simple(1);
    Simple c = new Simple(2);
    System.out.println(" a.equals(b)="+a.equals(b)+
                       " a.equals(c)="+a.equals(c)+
                       " b.equals(c)="+b.equals(c));
    System.out.println(" a="+a.hashCode()+
                       " b="+b.hashCode()+
                       " c="+c.hashCode());
    System.out.println(" a="+System.identityHashCode(a)+
                       " b="+System.identityHashCode(b)+
                       " c="+System.identityHashCode(c));
  }
}
-- Dario

 Esempio che dimostra quanto da me detto:
In che senso? Quello nella documentazione e' un contratto.
Tu hai fatto l'override di equals e hashCode() in un modo in cui 
evidentemente il contratto non e' rispettato. 
Le implementazioni in Object lo rispettano:
Object obj1=new Object();
Object obj2=new Object();
Object obj3=obj1;
System.out.println("obj1.equals(obj2): "+(obj1.equals(obj2)));
System.out.println("obj1.equals(obj3): "+(obj1.equals(obj3)));
System.out.println("obj1.hashCode() == obj3.hashCode():"+
    	(obj1.hashCode()==obj1.hashCode()));
scrive correttamente
obj1.equals(obj2): false
obj1.equals(obj3): true
obj1.hashCode() == obj3.hashCode(): true
Occhio che *potrebbe* valare sia obj1.hashCode()==obj2.hashCode() che !=. 
Il contratto di hashCode() niente dice, appunto, sull'unicita' degli hash 
di oggetti *diversi* (che anzi non si puo' assumere).


 evidentemente il contratto non e' rispettato. 
Le mie equals e hash rispettano il contratto.
E' la System.identityHashCode che non lo rispetta.
Ovvero System.identityHashCode ritorna (volutamente!)
valori differenti per oggetti A e B anche se A.equals(B) == true.
Volevo solo dire questo!
D'altronde la specifica (di identityHashCode) della Sun
viola volutamente (!) la specifica data dalla stessa Sun
(per la hashCode) in modo da ottenere proprio una sorta
di "indirizzo" degli oggetti passati. Sic!
Per far questo la identityHashCode ritorna proprio l'indirizzo
dell'oggetto passato! Ed e' proprio per questo motivo
che viola la specifica perche' se ho due diversi oggetti a e b
(a != b) tali pero' che a.equals(b) == true
allora dovrebbe essere a.hashCode() != b.hashCode()
ma invece identityHashCode(a) == identityHashCode(b).
Nulla di + nulla di -.
-- Dario

 Volevo solo dire questo!
Non avevo capito cosa intendessi. :-)


Comunque rimango dell'opinione che se si fa overriding anche di equals il
problema non si pone :)
J