Содержит и равно - PullRequest
       1

Содержит и равно

3 голосов
/ 26 августа 2011

Я немного озадачен каким-то кодом:

for (AbstractItem item : mSetOfItems) {
        if (item.equals(pPrimaryItem))
        {
            System.out.println("Contains? " + mSetOfItems.contains(pPrimaryItem));
        }
}

Как могло случиться, что item.equals (pPrimaryItem) разрешается как true, а mSetOfItems.contains (pPrimaryItem) разрешается как false? Потому что это то, что я вижу в своем коде.

Другими словами, если я перебираю свой набор, я могу найти элемент, равный моему тестовому элементу. Но если я использую содержит, мои тестовые элементы не сообщается в наборе. Я сбит с толку, потому что думал, что содержит использованные равные. Что я мог упускать из виду?

Ответы [ 5 ]

9 голосов
/ 26 августа 2011

Вы не указали тип mSetOfItems, но я предполагаю, что AbstractItem переопределяет .equals(), но не .hashcode(). Это плохо.

Если mSetOfItems использует хеш-код для поиска, который он может основывать на своем типе, вы получите поведение, которое вы описали.

Вы предполагаете, что .contains() реализован с итерацией и .equals(). Там нет списка интерфейса, который гарантирует это.

6 голосов
/ 26 августа 2011

Что такое реализация mSetOfItems?

  • Если это дерево, возможно, ваша функция сравнения возвращает несовместимые значения.
  • Если это хеш, возможно, ваш equals() возвращает истину для объектов с разными хеш-кодами или объект hashCode() изменился с момента его вставки в набор.
3 голосов
/ 26 августа 2011

Если ваш набор является TreeSet или каким-либо другим набором, в котором вы используете собственный компаратор, то вы можете увидеть это, если компаратор был сломан, либо не вернув правильный отсортированный порядок, либо имея объекты, которые на самом делеравное сравнение неравноеКогда набор внутренне ищет элемент и использует компаратор, он сделает неправильный выбор и не увидит элемент.

Если ваш набор равен HashSet, ваша хеш-функция может быть нарушена и вызвать два объекта.которые равны, чтобы иметь другой хэш-код.Внутренне, так как HashSet использует хеш-код объекта, чтобы выяснить, где искать, он может в конечном итоге искать неправильный сегмент.

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

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

2 голосов
/ 26 августа 2011

Если mSetOfItems - это java.util.HashTable (или аналогичный «Hash» Collection, Set и т. Д.), То вы также должны реализовать hashCode(). boolean contains(Object elem) сначала попытается найти переданный объект, рассчитав его хеш и получив его в Коллекции. После того, как содержит что-то, он будет использовать метод equals для проверки того, что два объекта являются одинаковыми объектами в соответствии с вашей реализацией.

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

При реализации hashCode () напомните, что:

  • Всякий раз, когда он вызывается для одного и того же объекта более одного раза во время выполнения приложения Java, метод hashCode должен последовательно возвращать одно и то же целое число при условии, что никакая информация, используемая в сравнениях сравнения для объекта, не изменяется. Это целое число не обязательно должно оставаться согласованным при выполнении одного приложения другим исполнением того же приложения.
  • Если два объекта равны в соответствии с методом equals (Object), то вызов метода hashCode для каждого из двух объектов должен давать одинаковый целочисленный результат.
  • Не требуется, чтобы, если два объекта были неравны в соответствии с методом equals (java.lang.Object), то вызов метода hashCode для каждого из двух объектов должен приводить к разным целочисленным результатам. Тем не менее, программист должен знать, что выдача различных целочисленных результатов для неравных объектов может повысить производительность хеш-таблиц.

Кроме того, убедитесь, что вы правильно переопределили функцию равенства, соблюдая ее сигнатуру:

 public boolean equals(Object obj);
2 голосов
/ 26 августа 2011

Проверьте метод hashcode () вашего класса

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...