Java — TreeSet и hashCode()

У меня небольшой вопрос о коллекциях TreeSet и hashCode. У меня есть TreeSet, и я добавляю в него объекты, прежде чем добавить объект, я проверяю, существует ли он в TreeSet, используя contains.

У меня есть 2 разных объекта, каждый из которых создает отдельный хэш-код, используя мою реализацию метода хэш-кода, пример ниже:

public int hashCode()
{
    int hash = 7;
    hash = hash * 31 + anAttribute.hashCode();
    hash = hash * 31 + anotherAttribute.hashCode();
    hash = hash * 31 + yetAnotherAttribute.hashCode();
    return hash;
}

Хэш-коды для конкретного запуска: 76126352 и 76126353 (объекты отличаются только одной цифрой в одном атрибуте).

Метод contains возвращает true для этих объектов, несмотря на то, что хэш-коды разные. Есть идеи, почему? Это действительно сбивает с толку, и помощь будет действительно оценена.


person Gaz    schedule 24.09.2009    source источник


Ответы (4)


TreeSet вообще не использует hashCode. Он использует либо compareTo, либо компаратор, который вы передали конструктору. Это используется такими методами, как contains, для поиска объектов в наборе.

Таким образом, ответ на ваш вопрос заключается в том, что ваш метод compareTo или ваш Comparator определены так, что два рассматриваемых объекта считаются равными.

Из javadocs:

экземпляр TreeSet выполняет все сравнения элементов, используя свой метод compareTo (или сравнение), поэтому два элемента, которые считаются равными с помощью этого метода, с точки зрения набора равны.

person sepp2k    schedule 24.09.2009
comment
Он также использует метод equals, поэтому важно, чтобы equals и Comparator/compareTo были согласованы. - person Dan Dyer; 24.09.2009
comment
Это так, потому что интерфейс Set определен в терминах операции equals, но экземпляр TreeSet выполняет все сравнения элементов, используя свой метод compareTo (или сравнение) ... (из java.sun.com/javase/6/docs/api/java/util/TreeSet.html ) - person Dirk; 24.09.2009
comment
это действительно было проблемой, я добавил дополнительный атрибут, обновил equals и hashCode, но забыл о compareTo. Спасибо!! - person Gaz; 24.09.2009
comment
что, если я вставляю объект Integer в TreeSet, а contains() возвращает false, даже если Integer с таким же значением уже существует в TreeSet? - person Nitish Upreti; 06.10.2010

Из Java-документа:

Если два объекта равны в соответствии с методом equals(Object), то вызов метода hashCode для каждого из двух объектов должен давать одинаковый целочисленный результат.

Означает: объекты, которые вы используете для хеширования, не равны.

person tuergeist    schedule 24.09.2009
comment
Это предполагает, что hashCode и equals были определены таким образом, чтобы не нарушать этот контракт. - person sepp2k; 24.09.2009
comment
@ sepp2k Это это «генеральный контракт для hashCode()». Вот почему он использует слово «должен». - person user207421; 29.04.2015

Вам нужно прочитать главу 3 «Эффективная Java» Джошуа Блоха. В ней объясняется контракт equals и как правильно переопределить equals, hashCode и compareTo.

person duffymo    schedule 24.09.2009
comment
Он даже доступен в Интернете: java.sun.com/developer/Books/efficientjava/Chapter3. .pdf - person gustafc; 24.09.2009
comment
Я был готов проголосовать за комментарий gustafc, но ссылка не работает :( - person Matthew Gilliard; 07.01.2013
comment
Иди купи книгу. Это все еще там. - person duffymo; 07.01.2013

Вам не нужно проверять, содержится ли он, потому что вставка () в основном выполняет ту же операцию (т.е. поиск нужной позиции) на пути к точке вставки. Если объект не может быть вставлен (т. е. объект уже содержится), вставка возвращает false.

person helpermethod    schedule 29.03.2010
comment
Это один из примеров (как и большинство классов Collection) очень чистого и лаконичного API. - person helpermethod; 29.03.2010