В HashMap встречаются одинаковые ключи! Почему?
У меня имеется цикл, который наполняет HashMap. Работает по принципу - для каждого руководителя отдела(например: бухгалтерия) имеется значение в виде списка работников этого отдела. То есть: Руководитель - ключ, список его подчиненных - список. Как так получается, что при выполнении цикла у меня получется несколько одинаковых ключей. Я на всех ресурсах вычитываю, что Мап хранит УНИКАЛЬНЫЕ ключи, либо их перезаписывает за место уже имеющихся. Как это можно исправить(возможно,есть варианты удаление всех дубликатов ключей)? И как так вообще происходит?
P.S. В классе самом equals и hashCode перепоределены. Так же в класса Gate, Depatrment и Room.
Employee:
public class Employee extends EmployeeGeneral {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Employee)) return false;
Employee that = (Employee) o;
return room.equals(that.room) && department.equals(that.department) && upDepartment.equals(that.upDepartment) && gate.equals(that.gate);
}
@Override
public int hashCode() {
return Objects.hash(room, department, upDepartment, gate);
}
private static final long serialVersionUID = 372342343809L;
private Room room;
private Department department;
private Department upDepartment;
private Gate gate;
public static final Field ROOM;
Метод:
for (MSEmployee m : employees) {
MSEmployee manager = msEmployeeRepository
.findFirstByDocID(departmentManagerMap.get(m.getDepartment().getId()));
if (manager == null) continue;
List<MSEmployee> msEmployeeList = msEmployeeRepository
.findAllByIdInAndDepartmentDocIdIn(employeesIds, manager.getDepartmentDocId());
employeesWithManagers.put(manager, msEmployeeList);
}
Результат:
Ответы (2 шт):
Для переопределения hadhCode желательно использовать финальные поля: хешмапа работает примерно след образом: у объекта берется хеш-код, по этому хеш коду обычно определяется, на каком индексе располагается объект в ассоциативном массиве (в нашел случае хеш мап).например: hashmap у нас размером 16, а хешкод у объекта 31, значит этот объект поместится на позицию 31%16=15 (индекс). Тоесть, чтобы достать значение из мапы мы просто обращаемся к индексу, как в обычном массиве, поэтому использование hashset hashmap такое быстрое. Когда происходят коллизии (тоесть хешкоды совпадают у разных объектов), в этой мапе эти объекты помещаются на один индекс, но в односвязный список. И когда мы хотим достать объект по индексу, мы видим: тут у нас односвязный список, значит нам придется найти нужный нам объект с помощью линейного поиска - здесь и вступает в дело переопределенный equals(). Если вы работаете в intellij, нажмите комбинацию клавиш alt+insert(виндовс) , и в меню появится генератор, в списке которого вам нужно выбрать equals + hashcode, - тогда среда разработки все сделает за вас. Я бы предложила использовать в переопределении этих методов, например, id работника - private final поле, и тогда понадобится только оно, при условии, что для каждого работника айдишник уникален
Если у Вас одинаковые хешкоды Employee, то исходя из показанного кода логически вытекает только 2 варианта:
- У Вас не переопределены hashCode() в классах Room, Department и Gate + вы в разные экземпляры employee передаете одни и те же экземпляры этих классов, которые сравниваются по == в непереопределенных hashCode().
- У Вас неправильно переопределены hashCode() в перечисленных классах. Если 2 сущности находятся в разном состоянии, то согласно контракту hashCode очень желательно, чтобы у них были разные хеш суммы. Что это за контракт можно посмотреть здесь.
PS Зачем Вы добавили в hashCode() и equals() public static final поле? Оно не участвует в состоянии employee. Это константа, которая одинакова для всех экземпляров employee.
