Java HashSet разрешает дублирование; проблема с сопоставимым? - PullRequest
9 голосов
/ 03 июня 2010

У меня есть класс "Аккумулятор", который реализует метод Comparable compareTo, и я пытаюсь поместить эти объекты в HashSet.

Когда я добавляю () к HashSet, я не вижу никакой активности в моем методе compareTo в отладчике, независимо от того, где я установил свои точки останова. Кроме того, когда я закончу с add (), я вижу несколько дубликатов в наборе.

Что я облажался здесь; почему он не сравнивает, и, следовательно, разрешает обман?

Спасибо
IVR Avenger

Ответы [ 8 ]

17 голосов
/ 03 июня 2010

Что я тут напортачила?

HashSet основан на hashCode(), а не compareTo(). Вы можете путать это с TreeSet. В обоих случаях обязательно реализуйте equals() способом, совместимым с другим методом.

11 голосов
/ 03 июня 2010

Вам нужно правильно реализовать hashCode() и equals().

Вы должны переопределить hashCode и вернуть число на основе значений в вашем классе, чтобы любые два равных объекта имели одинаковый хеш-код.

6 голосов
/ 03 июня 2010

HashSet использует методы hashCode() и equals() для предотвращения добавления дубликатов. Во-первых, он получает хеш-код объекта, который вы хотите добавить. Затем он находит соответствующий сегмент для этого хэш-кода и перебирает каждый объект в этом сегменте, используя метод equals(), чтобы проверить, существуют ли какие-либо идентичные объекты в наборе.

Ваш отладчик не работает на compareTo(), потому что он никогда не используется с HashSet!

Правила таковы:

  1. Если два объекта равны, то их хэш-коды должен быть равным.

  2. Но если хеш-коды двух объектов равны, то это не означает объекты равны! Возможно что два объекта просто имеют одинаковый хэш.

2 голосов
/ 04 апреля 2013

Одна вещь, которую люди склонны игнорировать, что приводит к огромной ошибке.При определении метода equals всегда принимайте параметр как класс объекта, а затем конвертируйте объект в нужный класс.Например,

   public bolean equals(Object aSong){
     if(!(aSoneg instanceof Song)){
       return false;
     }
     Song s=(Song) aSong;
     return getTitle().equals(s.getTitle());
   }

Если вы пропустите запись Song aSong вместо Object aSong, ваш метод equals никогда не будет вызван.

Надеюсь, это поможет

2 голосов
/ 03 июня 2010

Ваши объекты Comparable, и, вероятно, вы также реализовали equals(), но HashSets имеет дело с хешами объектов, и, скорее всего, вы не реализовали hashCode() (или ваша реализация hashCode() не не возвращает одинаковый хэш для двух объектов, которые (a.equals(b) == true).

2 голосов
/ 03 июня 2010

Когда hashCode возвращает разные значения для 2 объектов, то значение равно не используется. Кстати, сравнить, что не имеет ничего общего с коллекциями хэширования :), но отсортированные коллекции

1 голос
/ 14 декабря 2012

Когда вы создаете объект класса Аккумулятор , он занимает новое место в JVM и возвращает уникальный hashCode каждый раз, когда вы добавляете объект в HashSet . Он не зависит от значения объекта, поскольку вы не переопределили метод hashCode () , следовательно, он вызовет Object class hashCode () метод, который вернет метод уникальный хэш-код для каждого объекта, созданного в вашей программе.

Решение:

Переопределите hashCode () и метод equals () и примените свою логику в зависимости от свойств вашего класса. Обязательно прочитайте равно и хэш-код контракта

http://www.ibm.com/developerworks/java/library/j-jtp05273/index.html

1 голос
/ 03 июня 2010

HashSet использует hashCode и равно. TreeSet использует сопоставимый интерфейс. Примечание: если вы решите переопределить либо хеш-код, либо равно, вы всегда должны переопределять другой.

...