Что произойдет, если в TreeSet добавить объекты, которые равны по equals, но compareTo возвращает ненулевое значение?

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

Ответ

TreeSet добавит оба объекта, что нарушает контракт Set (уникальность элементов). TreeSet определяет уникальность исключительно через compareTo/Comparator, игнорируя equals().

Пример нарушения контракта:

class InconsistentItem implements Comparable<InconsistentItem> {
    private int id;
    private String name;

    // equals сравнивает только id
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof InconsistentItem)) return false;
        return this.id == ((InconsistentItem) o).id;
    }

    // compareTo сравнивает name
    @Override
    public int compareTo(InconsistentItem other) {
        return this.name.compareTo(other.name);
    }

    // hashCode на основе id
    @Override
    public int hashCode() { return Objects.hash(id); }
}

TreeSet<InconsistentItem> set = new TreeSet<>();
InconsistentItem item1 = new InconsistentItem(1, "apple");
InconsistentItem item2 = new InconsistentItem(1, "banana"); // Тот же id!

set.add(item1);
set.add(item2); // Добавится, хотя equals() вернет true!

System.out.println(set.size()); // 2 - НАРУШЕНИЕ: в Set дубликаты!
System.out.println(item1.equals(item2)); // true

Правила TreeSet:

  1. Уникальность определяется compareTo() (0 = дубликат)
  2. Сортировка также через compareTo()
  3. equals() игнорируется для определения дубликатов

Best practice:

// compareTo и equals ДОЛЖНЫ быть согласованы
@Override
public int compareTo(MyItem other) {
    int result = this.name.compareTo(other.name);
    if (result == 0) {
        result = Integer.compare(this.id, other.id);
    }
    return result;
}

@Override
public boolean equals(Object o) {
    // Такая же логика, как в compareTo
    if (!(o instanceof MyItem)) return false;
    MyItem other = (MyItem) o;
    return Objects.equals(this.name, other.name) 
           && this.id == other.id;
}

Вывод: Всегда обеспечивайте согласованность между compareTo() и equals()!