Почему Java не разрешает переопределять равные (Object) в Enum?
Я заметил, что следующий фрагмент...
@Override
public boolean equals(Object otherObject) {
...
}
... не разрешено для Enum, так как метод equals(Object x)
определяется как final
в Enum
. Почему это так?
Я не могу придумать какой-либо прецедент, который потребует переопределения equals(Object)
для Enum. Мне просто интересно узнать причину такого поведения.
Ответы
Ответ 1
Любое, кроме return this == other
, будет противоречивым и нарушит принцип наименьшего удивления. Ожидается, что две константы перечисления будут equal
если и только если они являются одним и тем же объектом, и возможность переопределить это поведение будет подвержена ошибкам.
То же самое относится и к hashCode()
, clone()
, compareTo(Object)
, name()
, ordinal()
и getDeclaringClass()
.
JLS не мотивирует выбор сделать его окончательным, но упоминает о равных в контексте перечислений здесь. Snippet:
Метод equals в Enum
- это последний метод, который просто вызывает super.equals
для своего аргумента и возвращает результат, таким образом выполняя сравнение идентичности.
Ответ 2
Уже существует сильное интуитивное представление о том, что означает для экземпляров (значений) enum
равным. Разрешение перегрузки метода equals
приведет к нарушению этого понятия, что приведет к неожиданному поведению, ошибкам и т.д.
Ответ 3
Иногда нам приходится иметь дело с данными, которые не соответствуют стандартам именования 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;
}
Ответ 4
Именно потому, что разработчики Java не могли придумать какой-либо мыслимый вариант использования для переопределения Enum.equals(Object), что этот метод объявлен как final, так что такое переопределение было бы невозможным.
Ответ 5
Я должен признаться, что перечисления - это последнее, что я хотел бы переопределить equals()
in.
Я думаю, что причина equals()
является окончательной в перечислениях, так это то, что Java поощряет ==
для сравнения enum, а реализация equals()
в перечислениях просто использует ее, поэтому разрешение equals()
на переопределение - t22 > и equals()
от поведения по-другому, чего не ожидали бы другие разработчики.