Ответ
Класс-ключ для HashMap должен корректно реализовывать методы hashCode() и equals(). Это необходимо для правильной работы структуры данных, основанной на хэшировании.
Критерии для hashCode() и equals():
-
Контракт между
equals()иhashCode():- Если два объекта равны по
equals(), ихhashCode()обязаны быть одинаковыми. - Обратное не обязательно: разные объекты могут иметь одинаковый хэш-код (коллизия).
- Если два объекта равны по
-
Требования к
equals(Object o):- Рефлексивность:
x.equals(x)— всегдаtrue. - Симметричность: если
x.equals(y) == true, то иy.equals(x) == true. - Транзитивность: если
x.equals(y)иy.equals(z), тоx.equals(z). - Консистентность: многократный вызов
equals()с неизменными объектами всегда возвращает одинаковый результат. - Сравнение с
null:x.equals(null)— всегдаfalse.
- Рефлексивность:
-
Требования к
hashCode():- Консистентность: для неизменного объекта хэш-код должен быть постоянным.
- Эффективность: минимизация коллизий для повышения производительности.
Практический пример: Класс с полями name и id в качестве составного ключа.
import java.util.Objects;
public final class PersonKey {
private final String name;
private final int id;
public PersonKey(String name, int id) {
this.name = name;
this.id = id;
}
// Реализация equals, учитывающая все значимые поля
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PersonKey personKey = (PersonKey) o;
return id == personKey.id && Objects.equals(name, personKey.name);
}
// Реализация hashCode на основе тех же полей
@Override
public int hashCode() {
return Objects.hash(name, id); // Стандартная утилита из Java 7+
}
}
Важно: Если ключ является mutable-объектом, и его поля, участвующие в расчете hashCode/equals, изменяются после добавления в HashMap, элемент может стать "потерянным" (невозможность найти по этому ключу). Поэтому предпочтительны immutable ключи.