Per motivi di praticità, hashCode()
restituisce un int
firmato. 2 32 valori possibili. Uno potrebbe banalmente essere un long
invece di un int
e mi farebbe cambiare leggermente il resto di questa risposta.
L'essenza di tutto questo è il principio del pigeonhole . Se hai m
elementi e provi a metterli in n
box e m > n
, allora avrai due elementi che vanno nella stessa casella.
Osserviamo hashCode per Long
- che può avere 2 64 valori. Dal 2 64 > 2 32 avrai due valori con lo stesso valore.
public int hashCode() {
return (int)(value ^ (value >>> 32));
}
Quindi, lascia scrivere un codice rapido.
System.out.println(Long.valueOf(0).hashCode());
System.out.println(Long.valueOf(-1).hashCode());
System.out.println(Long.valueOf(0).equals(Long.valueOf(-1)));
System.out.println(Long.valueOf(0).hashCode() == Long.valueOf(-1).hashCode());
Stampa:
0
0
false
true
E ce l'abbiamo. Due numeri Uno di questi è 0
e l'altro è -1
che ha lo stesso codice hash, ma non lo stesso numero.
Il valore esadecimale di -1
è 0xffffffffffffffff
che quando fai un 0xffffffff ^ 0xffffffff
ottieni 0
Ma aspetta! Cosa succede se abbiamo usato long
per l'hashCode invece!
Come ho detto, è solo un problema leggermente diverso. Dovrei iniziare a scavare in un'altra classe che ha la possibilità di avere più valori di hashCode, come BigInteger o Stringa o Inet6Address (2 128 valori possibili ). Tutto ciò che fa è rendere il calcolo dell'hashCode un po 'più difficile da fare proprio qui (quelli sono più lunghi di una linea con operazioni a due bit). Non cambia il fatto che hashCode, essendo un valore di dimensione fissa, è soggetto al principio del pigeonhole.