Что такое свойство симметричности (symmetry) в контракте метода equals в Java?

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

Ответ

Симметричность (Symmetry) — одно из обязательных свойств корректной реализации метода equals(Object o) в Java. Оно требует, что для любых не-null ссылок x и y, выражение x.equals(y) должно возвращать true тогда и только тогда, когда y.equals(x) возвращает true.

Нарушение симметричности — распространенная ошибка:

class CaseInsensitiveString {
    private String s;
    public CaseInsensitiveString(String s) { this.s = s; }

    // НЕПРАВИЛЬНО: Нарушает симметричность!
    @Override
    public boolean equals(Object o) {
        if (o instanceof CaseInsensitiveString) {
            return s.equalsIgnoreCase(((CaseInsensitiveString) o).s);
        }
        // Опасная попытка быть совместимым с обычной String
        if (o instanceof String) {
            return s.equalsIgnoreCase((String) o);
        }
        return false;
    }
}

Проблема:

CaseInsensitiveString cis = new CaseInsensitiveString("Java");
String s = "java";

cis.equals(s); // true (наш метод сравнивает без учета регистра)
s.equals(cis); // false (метод String.equals не знает о CaseInsensitiveString)
// Нарушено: cis.equals(s) != s.equals(cis)

Правильная реализация, обеспечивающая симметричность:

@Override
public boolean equals(Object o) {
    // Сравниваем только с объектами того же класса
    if (o == null || o.getClass() != this.getClass()) {
        return false;
    }
    CaseInsensitiveString other = (CaseInsensitiveString) o;
    return this.s.equalsIgnoreCase(other.s);
}

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