Почему HashSet допускает равные элементы, если хэш-коды отличаются?
HashSet класс имеетдобавить (объект o) метод, который не наследуется от другого класса. Javadoc для этого метода говорит следующее:
Добавляет указанный элемент к этому набору, если его еще нет. Более формально добавляет указанный элементe
к этому набору, если этот набор не содержит элементовe2
такой, что(e==null ? e2==null : e.equals(e2))
, Если этот набор уже содержит элемент, вызов оставляет набор неизменным и возвращаетfalse
.
Другими словами, если два объекта равны, то второй объект не будет добавлен, и HashSet останется прежним. Тем не менее, я обнаружил, что это не так, если объектыe
а такжеe2
имеют разные хэш-коды, несмотря на то, чтоe.equals(e2)
, Вот простой пример:
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)));
}
Результаты основного метода:
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
Как ясно показывает приведенный выше пример, HashSet смог добавить два элемента, гдеe.equals(e2)
.
Я собираюсь предположить, что этоне ошибка в Java и что на самом деле есть совершенно рациональное объяснение, почему это так. Но я не могу понять, что именно. Что мне не хватает?