Por que o HashSet permite itens iguais se os códigos de hash forem diferentes?
oHashSet classe tem umadd (Objeto o) método, que não é herdado de outra classe. O Javadoc para esse método diz o seguinte:
Adiciona o elemento especificado a este conjunto, se ele ainda não estiver presente. Mais formalmente, adiciona o elemento especificadoe
para este conjunto se este conjunto não contiver elementoe2
de tal modo que(e==null ? e2==null : e.equals(e2))
. Se este conjunto já contiver o elemento, a chamada deixará o conjunto inalterado e retornaráfalse
.
Em outras palavras, se dois objetos forem iguais, o segundo objeto não será adicionado e o HashSet permanecerá o mesmo. No entanto, descobri que isso não é verdade se objetose
ee2
têm códigos de hash diferentes, apesar do fato de quee.equals(e2)
. Aqui está um exemplo simples:
import java.util.HashSet;
import java.util.Iterator;
import java.util.Random;
public class BadHashCodeClass {
/**
* A hashcode that will randomly return an integer, so it is unlikely to be the same
*/
@Override
public int hashCode(){
return new Random().nextInt();
}
/**
* An equal method that will always return true
*/
@Override
public boolean equals(Object o){
return true;
}
public static void main(String... args){
HashSet<BadHashCodeClass> hashSet = new HashSet<>();
BadHashCodeClass instance = new BadHashCodeClass();
System.out.println("Instance was added: " + hashSet.add(instance));
System.out.println("Instance was added: " + hashSet.add(instance));
System.out.println("Elements in hashSet: " + hashSet.size());
Iterator<BadHashCodeClass> iterator = hashSet.iterator();
BadHashCodeClass e = iterator.next();
BadHashCodeClass e2 = iterator.next();
System.out.println("Element contains e and e2 such that (e==null ? e2==null : e.equals(e2)): " + (e==null ? e2==null : e.equals(e2)));
}
Os resultados do método principal são:
Instance was added: true
Instance was added: true
Elements in hashSet: 2
Element contains e and e2 such that (e==null ? e2==null : e.equals(e2)): true
Como o exemplo acima mostra claramente, o HashSet conseguiu adicionar dois elementos ondee.equals(e2)
.
Eu vou assumir que isso énão um bug em Java e que, de fato, existe uma explicação perfeitamente racional para o porquê disso. Mas não consigo descobrir exatamente o que. o que estou perdendo?