Посмотрите на реализацию EnumMap.EntryIterator.next()
. Этого должно быть достаточно, чтобы выяснить проблему.
Подсказка в том, что результирующий набор:
[FEMALE=2, FEMALE=2]
что не является правильным результатом.
Эффект, который вы видите, связан с реализацией EnumMap.EntryIterator.hashCode()
(здесь это Map.Entry). Это
h = key ^ value
Это приводит к тому же хеш-значению для записей, создаваемых
map.put(Sex.MALE, Sex.MALE);
map.put(Sex.FEMALE, Sex.FEMALE);
стабильный 0.
или
map.put(Sex.MALE, Sex.FEMALE);
map.put(Sex.FEMALE, Sex.MALE);
здесь это нестабильное (для нескольких исполнений) значение типа int. Вы всегда увидите эффект, если хэши ключей и значений совпадают, поскольку: a ^ b == b ^ a
. Это приводит к тому же хеш-значению для Entry.
Если записи имеют одинаковое хеш-значение, они попадают в один и тот же сегмент хеш-таблицы, и равенства всегда будут работать, так как они в любом случае являются одним и тем же объектом.
Обладая этими знаниями, мы теперь можем также производить тот же эффект с другими типами, такими как Integer (где мы знаем реализацию hashCode):
map.put(Sex.MALE, Integer.valueOf(Sex.MALE.hashCode()));
map.put(Sex.FEMALE, Integer.valueOf(Sex.MALE.hashCode()));
[FEMALE=1671711, FEMALE=1671711]
Бонус : реализация EnumMap нарушает контракт equals ():
EnumMap<Sex, Object> enumMap = new EnumMap<Sex, Object>(Sex.class);
enumMap.put(Sex.MALE, "1");
enumMap.entrySet().iterator().next().equals(enumMap.entrySet().iterator());
Выдает:
Exception in thread "main" java.lang.IllegalStateException: Entry was removed
at java.util.EnumMap$EntryIterator.checkLastReturnedIndexForEntryUse(EnumMap.java:601)
at java.util.EnumMap$EntryIterator.getValue(EnumMap.java:557)
at java.util.EnumMap$EntryIterator.equals(EnumMap.java:576)
at com.Test.main(Test.java:13)