Это может произойти, если метод equals
был асимметричным.Предположим, есть два ключа a и b, такие что:
a.hashCode() == b.hashCode()
a.equals(b)
возвращает false b.equals(a)
возвращает true
Затем предположим, что реализация HashMap
ищет существующий ключ, вызывая existingKey.equals(newKey)
для каждого существующего ключа с таким же хеш-кодом, что и у нового ключа.
Теперь предположим, что мы первоначально добавили их вorder {a, b}.
Первый ключ (a
), очевидно, входит без проблем.Вставка второго ключа (b
) в итоге вызывает a.equals(b)
- это ложь, поэтому мы получаем два ключа.
Теперь, создав второй HashMap
, мы можем получить записи в заказе{b, a}.
На этот раз мы сначала добавляем b
, что нормально ... но когда мы вставляем второй ключ (a
), мы в итоге вызываем b.equals(a)
, который возвращает trueтаким образом, мы перезаписываем запись.
Возможно, это не то, что происходит, но это может объяснить вещи - и показывает опасности асимметричного equals
метода.
РЕДАКТИРОВАТЬ: Вот короткая, но полная программа, демонстрирующая эту ситуацию.(Точные данные a
и b
могут не совпадать, но асимметрия такая.)
import java.util.*;
public class Test {
private final String name;
public Test(String name)
{
this.name = name;
}
public static void main(String[] args)
{
Map<Test, String> firstMap = new HashMap<Test, String>();
Test a = new Test("a");
Test b = new Test("b");
firstMap.put(b, "b");
firstMap.put(a, "a");
Map<Test, String> secondMap = new HashMap<Test, String>();
for (Map.Entry<Test, String> entry : firstMap.entrySet())
{
System.out.println("Adding " + entry.getKey().name);
secondMap.put(entry.getKey(), entry.getValue());
}
System.out.println(secondMap.size());
}
@Override public int hashCode()
{
return 0;
}
@Override public boolean equals(Object other)
{
return this.name.equals("b");
}
}
Вывод на мою машину:
Adding a
Adding b
1
Вы не можетеполучить результат в обратном порядке - это зависит от:
- Способ, которым вызывается
equals
(candidateKey.equals(newKey)
или наоборот) - Порядок, в котором записи возвращаются изнабор
Может даже работать по-разному на разных прогонах.