Ответ 1
Вы можете НЕ @Override
a final
метод (§8.4.3.3); это ясно. enum
типы (§8.9) обрабатываются очень специфично на Java, поэтому equals
есть final
(также clone
, hashCode
и т.д.). Это просто невозможно @Override
метод equals
для enum
, и вы бы не захотели в более типичном сценарии использования.
ОДНАКО, глядя на общую картину, похоже, вы пытаетесь следовать шаблону, рекомендованному в Effective Java 2nd Edition, пункт 34: Эмулировать расширяемые перечисления с интерфейсами (см. руководство по языку для получения дополнительной информации о enum
):
Вы определили этот interface
(теперь явно зарегистрированный для ожидаемого поведения equals
):
public interface Group implements Group {
public Point[] getCoordinates();
/*
* Compares the specified object with this Group for equality. Returns true
* if and only if the specified object is also a Group with exactly the same
* coordinates
*/
@Override public boolean equals(Object o);
}
Для interface
вполне приемлемо определить способ equals
для разработчиков, который должен вести себя, конечно. Это как раз в случае, например, List.equals
. Пустой LinkedList
равен equals
для пустого ArrayList
и наоборот, потому что это означает, что мандат interface
.
В вашем случае вы выбрали вариант Group
как enum
. К сожалению, теперь вы не можете реализовать equals
согласно спецификации, так как это final
, и вы не можете @Override
его. Однако, поскольку целью является соответствие типу Group
, вы можете использовать шаблон декоратора, указав ForwardingGroup
следующим образом:
public class ForwardingGroup implements Group {
final Group delegate;
public ForwardingGroup(Group delegate) { this.delegate = delegate; }
@Override public Point[] getCoordinates() {
return delegate.getCoordinates();
}
@Override public boolean equals(Object o) {
return ....; // insert your equals logic here!
}
}
Теперь вместо использования констант enum
непосредственно как Group
, вы завершаете их в экземпляр ForwardingGroup
. Теперь этот объект Group
будет иметь желаемое поведение equals
, как указано interface
.
То есть вместо:
// before: using enum directly, equals doesn't behave as expected
Group g = BasicGroup.A;
Теперь у вас есть что-то вроде:
// after: using decorated enum constants for proper equals behavior
Group g = new ForwardingGroup(BasicGroup.A);
Дополнительные примечания
Тот факт, что enum BasicGroups implements Group
, даже если он сам не соответствует спецификации Group.equals
, должен быть очень четко документирован. Пользователи должны быть предупреждены о том, что константы должны быть, например, завернутый внутри a ForwardingGroup
для правильного поведения equals
.
Обратите внимание, что вы можете кэшировать экземпляры ForwardingGroup
, по одному для каждой константы enum
. Это поможет уменьшить количество созданных объектов. В соответствии с эффективным Java 2nd Edition, пункт 1: рассмотрите статические методы factory вместо конструкторов, вы можете подумать о том, чтобы ForwardingGroup
определить метод static getInstance(Group g)
вместо конструктора, позволяя ему возвращать кэшированные экземпляры.
Я предполагаю, что Group
является неизменным типом (эффективное Java 2nd Edition, пункт 15: минимизация изменчивости), иначе вы, вероятно, не должны реализовывать его с enum
в первую очередь. Учитывая это, рассмотрим Эффективное Java 2nd Edition, пункт 25: Предпочтительные списки для массивов. Вы можете выбрать getCoordinates()
вернуть List<Point>
вместо Point[]
. Вы можете использовать Collections.unmodifiableList
(еще один декоратор!), Который сделает возвращаемый List
неизменяемым. Напротив, поскольку массивы изменяемы, вы должны будете выполнить защитное копирование при возврате Point[]
.