All enums in Java inherit from Java.lang.Enum class, and the definition of enum class is as follows:
public abstract class Enum<E extends Enum<E>> implements Comparable<E>, Serializable { // ... }
As you can see from the definition, Enum classes use generics of self defining types.
What's the meaning of self defining type parameters? It ensures that generic parameters must be the same (or have the same base class) as the class being defined, for example:
public class Test { public static void main(String[] args) { MyEnum1 enum1 = new MyEnum1(); MyEnum1 enum11 = new MyEnum1(); MyEnum2 enum2 = new MyEnum2(); MyEnum2 enum22 = new MyEnum2(); MyEnum3 enum3 = new MyEnum3(); MyEnum3 enum33 = new MyEnum3(); enum1.compareTo(enum11); enum2.compareTo(enum22); enum3.compareTo(enum2); } } abstract class AbsEnum<E extends AbsEnum<E>> implements Comparable<E> {} class MyEnum1 extends AbsEnum<MyEnum1> { @Override public int compareTo(MyEnum1 o) { return 0; } } class MyEnum2 extends AbsEnum<MyEnum2> { @Override public int compareTo(MyEnum2 o) { return 0; } } class MyEnum3 extends AbsEnum<MyEnum2> { @Override public int compareTo(MyEnum2 o) { return 0; } }
AbsEnum is a base class that uses self defining types. AbsEnum requires that the generic parameters of all subclasses inherited from AbsEnum must be subclasses of AbsEnum. This provides a boundary for generics.
So, when we define a generic class
public enum Month { JAN, FEB, MAR; }
What the compiler does is to compile this enum into a subclass of the enum class. Using the decompile tool, you can get:
final class Month extends java.lang.Enum<Month> { public static final Month JAN; public static final Month FEB; public static final Month Mar; }
This ensures that the instance of the enumeration class Month can only be compared with the instance of Month (for example, MyEnum1 and MyEnum2 in the above example), instead of two different enumeration classes (for example, MyEnum3 in the above example)