Почему Java не позволяет переопределять equals (Object) в Enum? - PullRequest
37 голосов
/ 03 июня 2010

Я заметил, что следующий фрагмент ...

@Override
public boolean equals(Object otherObject) {
    ...
}

... недопустимо для Enum, поскольку метод equals(Object x) определен как final в Enum. Почему это так?

Я не могу вспомнить ни одного варианта использования, который потребовал бы переопределения equals(Object) для Enum. Мне просто любопытно узнать причину этого поведения.

Ответы [ 5 ]

39 голосов
/ 03 июня 2010

Все, кроме return this == other было бы нелогичным и нарушало бы принцип наименьшего удивления . Ожидается, что две константы enum будут equal тогда и только тогда, когда они являются одним и тем же объектом и возможность переопределить это поведение будет подвержена ошибкам.

То же самое относится к hashCode(), clone(), compareTo(Object), name(), ordinal() и getDeclaringClass().


JLS не мотивирует выбор сделать его окончательным, но упоминает равные в контексте перечислений здесь . Отрывок:

Метод equals в Enum является последним методом, который просто вызывает super.equals для своего аргумента и возвращает результат, таким образом выполняя сравнение идентификаторов.

3 голосов
/ 03 июня 2010

Уже имеется строгое интуитивное представление о том, что значит для экземпляров (значений) enum быть равными. Допустимая перегрузка метода equals приведет к нарушению этого понятия, что приведет к неожиданному поведению, ошибкам и т. Д.

1 голос
/ 10 января 2019

Иногда нам приходится иметь дело с данными, которые не соответствуют стандартам именования Java. Было бы неплохо иметь возможность сделать что-то вроде этого:

public enum Channel
{
    CallCenter("Call Center"),
    BankInternal("Bank Internal"),
    Branch("Branch");

    private final String value;

    Channel(String value)
    {
        this.value = value;
    }

    @Override
    public String toString()
    {
        return value;
    }

    public static Channel valueOf(String value)
    {
        for (Channel c : Channel.values())
            if (c.value.equals(value))
                return c;
        return null;
    }

    @Override
    public boolean equals(Object other) 
    {
        if (other instanceof String)
            other = Channel.valueOf((String)other);
        return super.equals(other);
    }
}

Класс "String" необходимо изменить, чтобы он соответствовал ...

public boolean equals (Object object) {
    if (object == this) return true;
    if (object instanceof Enum) 
        object = object.toString();
    if (object instanceof String) {
        String s = (String)object;
        // There was a time hole between first read of s.hashCode and second read
        //  if another thread does hashcode computing for incoming string object
        if (count != s.count ||
            (hashCode != 0 && s.hashCode != 0 && hashCode != s.hashCode))
                return false;
        return regionMatches(0, s, 0, count);
    }
    return false;
}
0 голосов
/ 03 июня 2010

Должен признаться, перечисления - это последнее, что я хотел бы переопределить equals() in.

Я думаю, причина того, что equals() является окончательной в перечислениях, заключается в том, что Java поощряет == для сравнения перечислений, а реализация equals() в перечислениях просто использует ее, поэтому разрешение переопределения equals() означает предотвращение == и equals() ведут себя по-разному, чего другие разработчики не ожидают.

0 голосов
/ 03 июня 2010

Именно потому, что разработчики Java не могли придумать ни одного возможного варианта использования для переопределения Enum.equals (Object), этот метод объявлен как final - так что такое переопределение было бы невозможным.

...