Type parameter E in Enum is defined as <E extends Enum<E>>. So why in Enum implementation source code, we still need to check getClass() and getDeclaringClass() in compareTo method? I don't think compiler can pass when I set a different enum type object in compareTo.
2 Answers
It covers the case of comparing raw types and values obtained via unsafe / unchecked casts and conversions (such as Comparable, or Object a):
static enum Fruit { Apple, Orange, Banana }; static enum Animal { Cat, Dog, Horse }; public static final void main (String[] args) throws Exception { Enum f = Fruit.Apple; Enum a = Animal.Cat; f.compareTo(a); } There, compareTo would fail with a ClassCastException at the explicit getDeclaringClass comparison, as it would pass the first explicit cast (Enum other = (Enum)o) with no issue.
As for comparing getClass, it's tagged as an "optimization" in that source. The reason this is an optimization is that if the value classes are the same, then they're definitely from the same enum, and so there's no need to call the slightly more expensive getDeclaringClass. Since the vast majority of enums are likely simple enums (no value class bodies), it's optimized for that case.
9 Comments
f and a to have type Object.a is Object. If f is Object then you would not have f.compareTo available. Also the exception stack trace is actually slightly different for an Enum vs Object type for a, so I need to think about how to clearly formulate that in words before I add a mention of Object to this answer.f to Comparable<?> you do. (OK Object was the wrong choice ... my bad.) Also, consider Enum<?> which technically is not a raw type (see JLS 4.8). But my point is that "raw types" are not the only reason for this.f was Comparable<?>, how would f.compareTo(a); compile?It can, if you use Enum as a raw type. For instance in this program:
public static void main(String[] args) { Enum e = A.x; // All occurrences of E are erased to Enum e.compareTo(B.i); // B.i extends Enum, so this is fine } enum A {x,y,z}; enum B {i,j,k}; 2 Comments
E is not Enum here. If you tried to provide Enum as E, it wouldn't compile. There just isn't an E.compareTo(E) is compareTo(Enum).