Как HashSet в Java работает с объектами, у которых не переопределён equals()?

«Как HashSet в Java работает с объектами, у которых не переопределён equals()?» — вопрос из категории Java Core, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

HashSet будет работать некорректно, так как его корректность зависит от правильной реализации методов equals() и hashCode().

Проблемы:

  1. Нарушение логики уникальности: HashSet использует equals() для проверки дубликатов. Если метод не переопределён, используется реализация из Object, которая сравнивает ссылки на объекты (==). Это означает, что два разных объекта с одинаковыми данными будут считаться разными и оба добавятся в набор, нарушая контракт Set.

    class BadKey {
        String value;
        // Нет переопределения equals/hashCode
    }
    
    Set<BadKey> set = new HashSet<>();
    set.add(new BadKey("a"));
    set.add(new BadKey("a")); // Добавится! Два разных объекта.
    System.out.println(set.size()); // Выведет 2
  2. Проблемы с поиском: Методы contains() и remove() также полагаются на equals(). Невозможно будет найти или удалить объект, используя другой экземпляр с теми же данными.

Правило: Всегда переопределяйте equals() и hashCode() согласованно, если объекты этого класса будут использоваться как ключи в HashMap или элементы в HashSet.