Newsgroup: it.comp.java
Titolo: hashcode e equals questi sconosciuti

Ciao a tutti, da circa un paio di settimane ho cominciato ad avvicinarmi a 
Java.
In un esercizio mi veniva chiesto di inserire in un "vettore"(perdonatemi 
l'eventuale inesattezza (^__^)) stazione di tipo set Tre oggetti di tipo 
treno caratterizzato da tre stringhe: il n°treno, la destinazione e la 
tipologia(intercity, regionale, ecc...)
Posto qua sotto il codice che ho fatto:
-----------------------------------------------------
import java.util.*;
public class Treno
{
 String n_treno;
 String destinazione;
 String tipologia;
 public Treno(String n_treno,String destinazione, String tipologia)
 {
  this.n_treno=n_treno;
  this.destinazione=destinazione;
  this.tipologia=tipologia;
 }
 public int hashCode()
 {
  //n_treno=this.n_treno.hashCode();
  return this.n_treno.hashCode();
 }
 public boolean equals(Object obj)
 {
  Treno it=(Treno) obj;
  if(this.n_treno.compareTo(it.n_treno)==0)
  return true;
  else return false;
 }
 public String toString()
 {
  System.out.println("\n---------------------------------"+n_treno+"------------------------------------");
  return("Numero Treno= "+n_treno+"\n"+"Destinazione= 
"+destinazione+"\n"+"Tipo di Treno= "+tipologia+"\n");
 }
 public void stampaTreni(Set treni)
 {
  Iterator i=treni.iterator();
  while(i.hasNext())
  System.out.println(i.next());
 }
 public static void main(String [] args)
 {
  Treno t1=new Treno("432","Chiavenna","Regionale");
  Treno t2=new Treno("432","Milano","Regionale");
  Treno t3=new Treno("4443","Bari","Eurostar");
  Set stazione=new HashSet();
  boolean stato=stazione.add(t1);
  stato=stazione.add(t2);
  stato=stazione.add(t3);
  t1.stampaTreni(stazione);
}
}
--------------------------------------------------------------------------------------------------------------------
Il codice funziona: infatti non mi inserisce t2 in quanto la stringa n_treno 
e' indentica: questo perchè volevo rendere la stringa univoca.
Tuttavia non ho capito alcuni dettagli.
Caratteristiche delle variabili di tipo set e' quella di definire oggetti 
non identici
Un primo esperimento che ho fatto con i numeri infatti mi dava esito 
positivo: inserendo tramite il metodo add 123 e poi 123 di fatto mi inseriva 
solo il primo 123.
Con l'oggetto treno invece mi inseriva oggetti con attributi identici: 
questo perchè di fatto veniva invocato l'hashcode di object che restituiva 
due valori diversi se i due oggetti puntavano a diversi indirizzi di 
memoria(giusto? magari mi confondo con equals!) e anche l'equals non 
ridefinito mi dava lo stesso problema.
Li ho quindi ridefiniti e il codice funzia.
Al momento di fare stazione.add(t1) nel main vengono automaticamente 
chiamati hashcode e equals giusto?
Quello che non ho capito e' perche' ci vuole questo doppio controllo: non 
basta che le due stringhe n_treno di t1 e t2 siano identiche o ricevano lo 
stesso hashcode?
Non so se mi sono spiegato: ho provato a leggere le javadoc ma non ci ho 
capito molto
Qualcuno di voi può spiegarmi molto terra terra(^__^) perchè?
Grazie in anticipo per le risposte
Stefano
 


Beh il fatto che il Set che usi si chiami HashSet dovrebbe metterti un
pulce nell'orecchio sull'importanza
dell hascode. Hashcode e' sostanzialmente una scorciatoia per non
dover invocare equals tutte le volte.
I set, quando aggiungi un elemento, lo devo aggiungere solo se non ce
n'e' gia uno uguale all interno.
Uguale per java vuol diire una cosa sola: che il metodo equals
restituisce true. Se il set agisse solo con la "forza
bruta" e contiene N elementi, all'aggiunta di un nuovo elemnto
dovrebbe chiamare N VOLTE equals. Cosa che potresti fare te a mano
usando un arraylist e implementandoti il ciclo a manina. bel cesso di
Data Structure. Fortunatamente HashSet e'
piu' intelligente. hascode e' un metodo che ritorna un intero che e'
una specie di impronta digitale dell'oggetto. DEVE dare un numero
UGUALE per oggetti UGUALI, e POSSIBILIMENTE DIVERSO per oggetti
DIVERSI.Non e' obbligaorio comqunque
che oggetti diversi diano hascode diverso. Questo significa che l
hascode 1 e' considerato legale, perche ' oggeti uguali danno hascode
uguale. Chiaramente non e' un hascode efficente visto che anche
oggetti diversi dano hascode uguale. Ora cosa fa un HashSet quando gli
inserisci un nuovo elemento? Confronta il suo hashcode con quelli
degli oggetti che gia' contiene.
Se l'hascode e' diverso , sa gia' che l oggetto non e' uguale a
nessuno di quelli che contiene, e lo puo' aggungere, senza chiamare
nemmeno un equals. Se l'  hascode e' uguale a quello di, diciamo 2
oggetti, beh allora HashSet si prendera' il disturbo di chiamare due
volte equals fra il nuovo ogegtto e quelli con hashcode uguale per
scoprire se l hascode e' uguale per coincidenza o perche gli ogegtti
sono davvero uguali. Quindi hascode e equals sono legati da un
contratto: se tu definisci il concetto di uguaglianza di oggetti in
una tua classe ridefinendo equals, devi ricordarti di ridefinire anche
hascode in modo che sia coerente con equals. Coerente significa che
oggetti uguali devono dare hascode uguale. Se ti dimentichi , HashSet
non funziona piu' correttamente, perche ' la versione originaria di
hashcode si basa sugli indirizzi degli oggetti, e da' uguale solo per
lo stesso oggetto in memoria. Quindi se hai la classe cliente in cui
il metodo uquals rritorna true se , ad esempio, una private String
codicefiscale e uguale tra due oggetti , e provi a mettere due clienti
con stesso codice fiscale in un HashSet, ce li ritrovi tutti e due,
anche se secondo te sono uguali. Il motivo e' che HashSet si e
chiamatio hascode dui due clienti, ha ottenuto un risultato diverso
visto che sono due oggetti con diversi indirizzo in memoria, e ha
concluso che devono essere oggeti diversi.
Per una discussione molto piu' chiara di questa, e molti altri tips &
tricks su java ti consiglio Effective Java di Joshua Bloch

 ha scritto nel messaggio 
news:1173560446....@v33g2000cwv.googlegroups.com...


 writes:
ra> Ora cosa fa un HashSet quando
ra> gli inserisci un nuovo elemento? Confronta il suo hashcode con
ra> quelli degli oggetti che gia' contiene.  Se l'hascode e' diverso ,
ra> sa gia' che l oggetto non e' uguale a nessuno di quelli che
ra> contiene, e lo puo' aggungere, senza chiamare nemmeno un
ra> equals.
Unica precisazione:
l'hashcode viene usato per calcolare  in tempo costante l'indice di un
array in cui depositare il valore.
Se  al  momento dell'inserimento  l'elemento  è  vuoto, allora  nessun
problema.
Altrimenti confronta  gli oggetti per  verificare se si tratta  di una
sovrascrittura o  di una collisione  (due oggetti che hanno  lo stesso
hash) e quindi chiama equals().
É per  questo che  se a.equals(b) allora  deve essere  a.hashCode() ==
b.hashCode(), perché lo stato  dell'oggetto è il medesimo (a.equals(b)
ritorna vero) e quindi deve  per forza andare a "cascare" nello stesso
posto.
-- 
 /\           ___
/___/\_|_|\_|__|___Gian Uberto Lauri_____
  //--\| | \|  |   Integralista GNUslamico
\/                 e coltivatore diretto di Software