Paolovox ha scritto:
Però la JVM è intelligente e spesso fa puntare due variabili allo stesso oggetto nel caso si riferiscano a due oggetti uguali.
Se ti riferisci al "auto-boxing" (feature da Java 5 in poi), ci sarebbe da fare un discorso un po' più lungo. Se ti interessa e vuoi, apri pure un'altra discussione su questo.
Paolovox ha scritto:
Ho capito l'inefficienza delle collisioni.
In caso di collisioni risulterebbe inefficiente dato che non si avrebbe più un tempo O(1) costante per accedere ad un oggetto, ma quando più oggetti collidono vengono messi in una lista puntata dalla posizione dell'hash code nella tabella hash, quindi va scandita la lista per trovare l'oggetto utilizzando ogni volta il metodo equals.
Esatto, il hashCode alla fine viene usato solo per indirizzare il giusto bucket ("secchio") in cui sono contenuti più oggetti. E il caso estremo-peggiore è proprio se si fa ritornare da hashCode() un valore fisso, es. 10. In questo caso
tutti gli oggetti di quella classe andranno a finire nello stesso bucket e quindi ci sarà una grossa lista linkata per cui i benefici di una hash-table vanno a farsi friggere.
L'obiettivo di hashCode() è appunto quello di fornire valori il più possibile distribuiti e distinti. Ma le collisioni possono comunque sempre esserci.
Paolovox ha scritto:
L'hash code viene utilizzato solo per memorizzare oggetti nelle Hash Table?
Sì, hashCode() è stato fatto ed è utilizzato quasi esclusivamente per le collezioni basate su hash-table.
Paolovox ha scritto:
Giusto con i generics potrei dichiarare la mia classe:
public class MyList<Elemento> implements Iterable<Elemento>
e utilizzare nell'Iterator solo Elemento.
No, la tua classe MyList non è "generica". In MyList<Elemento> nella definizione della classe, il Elemento non è un tipo concreto ma una type variable (come il <E> delle collezioni). E il fatto poi che tu abbia una classe con nome Elemento, complicherebbe solo le cose a livello di nomi.
Quindi è corretto:
public class MyList implements Iterable<Integer>
Paolovox ha scritto:
Ma se un oggetto è mutabile perchè ad ogni mutazione generarne uno diverso? Il precedente non potrebbe andare bene?
Innanzitutto per hashCode non è obbligatorio usare per forza tutto lo "stato" di un oggetto. Si potrebbe usarne solo una parte, purché resti corretto il contratto tra equals e hashCode. Se cambia quella parte di stato, chiaramente hashCode viene influenzato ma è giusto che sia così.
È chiaro che se metti in un HashSet un oggetto "mutabile" e tenendo il reference all'oggetto poi ne modifichi il suo stato
dopo che l'oggetto è stato inserito nel HashSet .... succede una brutta cosa: potresti non trovare più l'oggetto.
Paolovox ha scritto:
Costruttore che utilizza l'Elemento first e last per linkare gli elementi.
public MyList(int... interi) {
for ( int i =0 ; i<interi.length ; i++){
int x = i;
hash+= ++x * interi[i];
if(first == null) {
first = new Elemento(interi[i],null); continue;
}
Elemento l;
if(first.next == null){
l = first;
}
else l=last;
last = new Elemento(interi[i],null);
l.next = last;
}
}
Se c'è il last è molto più semplice e il tuo codice si può ridurre/semplificare. E innanzitutto sarebbe anche pulito avere un metodo apposito per il add di un elemento:
public void add(int valore) {
Elemento e = new Elemento(valore, null);
if (last != null) {
last.next = e;
}
last = e;
if (first == null) {
first = last;
}
}
E poi nel costruttore banalmente:
public MyList(int... interi) {
for (int v : interi) {
add(v);
}
}
Paolovox ha scritto:
E ho visto dal tuo sito personale che sei un javista d'onore.
Grazie.