HashMap говорит, что ключ не существует, хотя он существует

#java #hashmap

#java #hashmap

Вопрос:

Я столкнулся с интересной проблемой, в которой, я почти уверен, виноват HashMap . Рассмотрим следующий отладочный код (AMap — это хэш-карта, ключ — это значение, переданное этому методу)

 System.out.println("getBValues - Given: "   key);
System.out.println("getBValues - Contains Key: "   AMap.containsKey(key));
System.out.println("getBValues - Value: "   AMap.get(key));
for(Map.Entry<A,HashSet<B>> entry : AMap.entrySet()) {
    System.out.println("getBValues(key) - Equal: "   (key.equals(entry.getKey())));
    System.out.println("getBValues(key) - HashCode Equal: " (key.hashCode() == entry.getKey().hashCode()));
    System.out.println("getBValues(key) - Key: "   entry.getKey());
    System.out.println("getBValues(key) - Value: "   entry.getValue());
}
  

Теперь в эту карту я вставляю один ключ (канал) и значение. Позже я пытаюсь вернуть значение с помощью get() и запускаю этот отладочный код, который в моем случае выдает этот результат:

 getBValues - Given: Channel(...)
getBValues - Contains Key: false <--- Doesnt contain key?!
getBValues - Value: null   <--- Null (bad)
getBValues(key) - Equal: true <--- Given key and AMap key is equal
getBValues(key) - HashCode Equal: true
getBValues(key) - Key: Channel(Same...)
getBValues(key) - Value: []    <--- Not null (This is the expected result)
  

Как вы можете видеть, извлечение ключа из HashMap напрямую не работает, но при циклическом просмотре я получаю точно такой же ключ, что означает, что он там, с которым его просто нельзя найти get() . Мой вопрос в том, что могло бы вызвать это? Как get() не найти существующий ключ?

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

Любые предложения о том, что может быть причиной этого?

Комментарии:

1. «… что, я почти уверен, является ошибкой HashMap» . Повторяйте за мной. «Ошибка в моем коде». — programmers.stackexchange.com/questions/1785 / …

2. @Stephen Я имел в виду это больше как «Некоторую «особенность» в HashMap, вызывающую это»

Ответ №1:

Бьюсь об заклад, вы неправильно переопределили equals и hashCode в своем классе key Channel. Это бы все объяснило.

Джошуа Блох рассказывает вам, как это правильно сделать в главе 3 «Эффективная Java».

http://java.sun.com/developer/Books/effectivejava/Chapter3.pdf

Комментарии:

1. Я сделал это с Project Lombok, даже специально исключив 2 хэш-набора в классе, которые повлияли бы на равенство.

2. Я не знаю, что такое Project Lombok; я не могу сказать, означает ли это «да, у меня есть правильные equals и реализованный хэш-код». Лучше всего, если ключи тоже будут неизменяемыми. Это верно для вашего канала?

3. В его конкретном тесте hashCode дает одинаковое значение для ключа и сохраненного ключа. Это может быть реализовано неправильно или корректно, но в этом экземпляре это правильно. Клавиша. equals(entry.key) также выдает true. единственная оставшаяся причина, по которой я могу видеть, является ли entry.key.equals (ключ) ложным.

4. Извините, это да. Хэш-код реализован правильно. Посмотрите сюда projectlombok.org/features/EqualsAndHashCode.html

5. Переопределение hashCode помогло мне. Потому что я переопределил только equals ранее, но вы должны переопределить оба, чтобы заставить его работать. Спасибо

Ответ №2:

Из того, что я вижу, мы все еще не исключили, связано ли это с неизменяемостью. Если вы делаете:

 aMap.put(key, value);
key.setFieldIncludedInHashCodeAndEquals(25);
  

тогда вы получите результат выше.

Чтобы исключить это, либо покажите нам больше вашего кода, либо, в цикле for в вашем примере выше, добавьте

 System.out.println(aMap.get(entry.getKey()));
  

Кроме того, используйте отладчик. Таким образом, вы можете увидеть, находится ли ваш объект в правильном сегменте.

Комментарии:

1. Хм … это дало мне нулевое значение. Я предполагаю, что хэш-код меняется после его добавления. Я посмотрю, смогу ли я обновить свой код до чего-то работоспособного.

2. Итак, изменилось ли какое-либо поле, являющееся частью hashCode или equals в объекте, который вы сохранили как ключ в aMap, после добавления объекта на вашу карту?

3. Вот почему ключи в картах должны быть неизменяемыми.