Java Set не может различать разные объекты

У меня есть один класс Human, который содержит два поля: age(int) и имя(строка). В eclipse я переопределяю методы hashCode() и equals() с этими двумя полями. Я также создаю Comparator на основе поля age.

Теперь я создаю объект TreeSet с Comparator возраста, а также два экземпляра (с разными значениями полей) класса Human. Затем я добавляю эти два объекта в набор, однако в наборе всегда только один объект.

Чтобы понять проблему, я распечатываю хэш-значение этих двух объектов и обнаруживаю, что они разные. Затем я тестирую их метод equals(), он выдает false, когда я сравниваю два экземпляра с разными значениями полей. Итак, теперь я не могу понять, почему TreeSet не может справиться (различить) проблему. Кто-нибудь может мне помочь? Большое спасибо !


person Ensom Hodder    schedule 12.07.2012    source источник


Ответы (2)


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

Поэтому, если ваш компаратор сравнивает только возраст людей, все люди одного возраста будут считаться равными. Если вы хотите, чтобы люди считались равными, когда у них одинаковый возраст и имя, тогда компаратор должен сравнивать по возрасту, а затем сравнивать по имени, если сравнение возраста возвращает 0.

person JB Nizet    schedule 12.07.2012
comment
Да, хорошо подмечено. Используйте оба поля в вашем методе compareTo(). Вы хотите отсортировать по возрасту, поэтому упорядочите по имени в пределах возраста, тогда 2 имени с одинаковым возрастом будут по-прежнему отсортированы правильно, но не будут считаться равными (т.е. ваш compareTo будет соответствовать равенству). - person MattR; 12.07.2012
comment
Но в документации по Java интерфейс Comparator имеет только метод compare(), а не compareTo(), не так ли? - person Ensom Hodder; 12.07.2012
comment
да. Но если ваши объекты реализуют Comparable, вам не нужно передавать компаратор конструктору TreeSet. В этом случае TreeSet будет сравнивать объекты, используя их метод compareTo. - person JB Nizet; 12.07.2012
comment
Итак, еще один вопрос для HashSet, который использует метод equals(). Если я не переопределяю метод equals(), почему HashSet может различать два разных объекта? Примечание: мой класс Human теперь реализует интерфейс Comparable! - person Ensom Hodder; 12.07.2012
comment
Все объекты имеют методы equals() и hashCode(), так как java.lang.Object реализует их. Эта реализация по умолчанию считает объект равным только самому себе. - person JB Nizet; 12.07.2012

Из документации

Это так, потому что интерфейс Set определен в терминах операции equals, но экземпляр TreeSet выполняет все сравнения элементов, используя свой метод compareTo (или сравнение), поэтому два элемента, которые считаются равными с помощью этого метода, с точки зрения набор, равный. Поведение набора четко определено, даже если его порядок несовместим с равными; он просто не подчиняется общему контракту интерфейса Set.

person hvgotcodes    schedule 12.07.2012