You can NOT @Override
a final
method (§8.4.3.3); this much is clear. enum
types (§8.9) are treated very specially in Java, which is why the equals
is final
(also clone
, hashCode
, etc.) It's simply not possible to @Override
the equals
method of an enum
, nor would you really want to in a more typical usage scenario.
HOWEVER, looking at the big picture, it looks like you are trying to follow the pattern recommended in Effective Java 2nd Edition, Item 34: Emulate extensible enums with interfaces (see the language guide for more information about enum
):
You have defined this interface
(now documented explicitly for expected equals
behavior):
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);
}
It is perfectly acceptable for an interface
to define how equals
method for implementors should behave, of course. This is exactly the case with, e.g. List.equals
. An empty LinkedList
is equals
to an empty ArrayList
and vice versa, because that's what the interface
mandates.
In your case, you've chosen to implement some Group
as enum
. Unfortunately you now can't implement equals
as per the specification, since it's final
and you can't @Override
it. However, since the objective is to comply to the Group
type, you can use decorator pattern by having a ForwardingGroup
as follows:
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!
}
}
Now, instead of using your enum
constants directly as Group
, you wrap them in an instance of a ForwardingGroup
. Now this Group
object will have the desired equals
behavior, as specified by the interface
.
That is, instead of:
// before: using enum directly, equals doesn't behave as expected
Group g = BasicGroup.A;
You now have something like:
// after: using decorated enum constants for proper equals behavior
Group g = new ForwardingGroup(BasicGroup.A);
Additional notes
The fact that enum BasicGroups implements Group
, even though it does not itself follow the specification of Group.equals
, should be very clearly documented. Users must be warned that constants must be e.g. wrapped inside a ForwardingGroup
for proper equals
behavior.
Note also that you can cache instances of ForwardingGroup
, one for each enum
constants. This will help reduce the number of objects created. As per Effective Java 2nd Edition, Item 1: Consider static factory methods instead of constructors, you may consider having ForwardingGroup
define a static getInstance(Group g)
method instead of a constructor, allowing it to return cached instances.
I'm assuming that Group
is an immutable type (Effective Java 2nd Edition, Item 15: Minimize mutability), or else you probably shouldn't implement it with enum
in the first place. Given that, consider Effective Java 2nd Edition, Item 25: Prefer lists to arrays. You may choose to have getCoordinates()
return a List<Point>
instead of Point[]
. You can use Collections.unmodifiableList
(another decorator!), which will make the returned List
immutable. By contrast, since arrays are mutable, you'd be forced to perform defensive copying when returning a Point[]
.
See also