Abstract superclass for type-safe enums.
One feature of the C programming language lacking in Java is enumerations. The
C implementation based on ints was poor and open to abuse. The original Java
recommendation and most of the JDK also uses int constants. It has been recognised
however that a more robust type-safe class-based solution can be designed. This
class follows the basic Java type-safe enumeration pattern.
NOTE:Due to the way in which Java ClassLoaders work, comparing
Enum objects should always be done using
equals()
, not
==
.
The equals() method will try == first so in most cases the effect is the same.
Of course, if you actually want (or don't mind) Enums in different class
loaders being non-equal, then you can use
==
.
Simple Enums
To use this class, it must be subclassed. For example:
public final class ColorEnum extends Enum {
public static final ColorEnum RED = new ColorEnum("Red");
public static final ColorEnum GREEN = new ColorEnum("Green");
public static final ColorEnum BLUE = new ColorEnum("Blue");
private ColorEnum(String color) {
super(color);
}
public static ColorEnum getEnum(String color) {
return (ColorEnum) getEnum(ColorEnum.class, color);
}
public static Map getEnumMap() {
return getEnumMap(ColorEnum.class);
}
public static List getEnumList() {
return getEnumList(ColorEnum.class);
}
public static Iterator iterator() {
return iterator(ColorEnum.class);
}
}
As shown, each enum has a name. This can be accessed using
getName
.
The
getEnum
and
iterator
methods are recommended.
Unfortunately, Java restrictions require these to be coded as shown in each subclass.
An alternative choice is to use the
EnumUtils
class.
Subclassed Enums
A hierarchy of Enum classes can be built. In this case, the superclass is
unaffected by the addition of subclasses (as per normal Java). The subclasses
may add additional Enum constants
of the type of the superclass. The
query methods on the subclass will return all of the Enum constants from the
superclass and subclass.
public final class ExtraColorEnum extends ColorEnum {
// NOTE: Color enum declared above is final, change that to get this
// example to compile.
public static final ColorEnum YELLOW = new ExtraColorEnum("Yellow");
private ExtraColorEnum(String color) {
super(color);
}
public static ColorEnum getEnum(String color) {
return (ColorEnum) getEnum(ExtraColorEnum.class, color);
}
public static Map getEnumMap() {
return getEnumMap(ExtraColorEnum.class);
}
public static List getEnumList() {
return getEnumList(ExtraColorEnum.class);
}
public static Iterator iterator() {
return iterator(ExtraColorEnum.class);
}
}
This example will return RED, GREEN, BLUE, YELLOW from the List and iterator
methods in that order. The RED, GREEN and BLUE instances will be the same (==)
as those from the superclass ColorEnum. Note that YELLOW is declared as a
ColorEnum and not an ExtraColorEnum.
Functional Enums
The enums can have functionality by defining subclasses and
overriding the
getEnumClass()
method:
public static final OperationEnum PLUS = new PlusOperation();
private static final class PlusOperation extends OperationEnum {
private PlusOperation() {
super("Plus");
}
public int eval(int a, int b) {
return (a + b);
}
}
public static final OperationEnum MINUS = new MinusOperation();
private static final class MinusOperation extends OperationEnum {
private MinusOperation() {
super("Minus");
}
public int eval(int a, int b) {
return (a - b);
}
}
private OperationEnum(String color) {
super(color);
}
public final Class getEnumClass() { // NOTE: new method!
return OperationEnum.class;
}
public abstract double eval(double a, double b);
public static OperationEnum getEnum(String name) {
return (OperationEnum) getEnum(OperationEnum.class, name);
}
public static Map getEnumMap() {
return getEnumMap(OperationEnum.class);
}
public static List getEnumList() {
return getEnumList(OperationEnum.class);
}
public static Iterator iterator() {
return iterator(OperationEnum.class);
}
}
The code above will work on JDK 1.2. If JDK1.3 and later is used,
the subclasses may be defined as anonymous.
compareTo
public int compareTo(Object other)
Tests for order.
The default ordering is alphabetic by name, but this
can be overridden by subclasses.
other
- the other object to compare to
- -ve if this is less than the other object, +ve if greater
than,
0
of equal
equals
public final boolean equals(Object other)
Tests for equality.
Two Enum objects are considered equal
if they have the same class names and the same names.
Identity is tested for first, so this method usually runs fast.
other
- the other object to compare for equality
true
if the Enums are equal
getEnum
protected static Enum getEnum(Class enumClass,
String name)
Gets an Enum
object by class and name.
enumClass
- the class of the Enum to get, must not
be null
name
- the name of the Enum
to get,
may be null
- the enum object, or null if the enum does not exist
getEnumClass
public Class getEnumClass()
Retrieves the Class of this Enum item, set in the constructor.
This is normally the same as
getClass()
, but for
advanced Enums may be different. If overridden, it must return a
constant value.
getEnumList
protected static List getEnumList(Class enumClass)
Gets the
List
of
Enum
objects using the
Enum
class.
The list is in the order that the objects were created (source code order).
If the requested class has no enum objects an empty
List
is
returned.
enumClass
- the class of the Enum
to get,
must not be null
getEnumMap
protected static Map getEnumMap(Class enumClass)
Gets the
Map
of
Enum
objects by
name using the
Enum
class.
If the requested class has no enum objects an empty
Map
is returned.
enumClass
- the class of the Enum
to get,
must not be null
getName
public final String getName()
Retrieve the name of this Enum item, set in the constructor.
- the
String
name of this Enum item
hashCode
public final int hashCode()
Returns a suitable hashCode for the enumeration.
- a hashcode based on the name
iterator
protected static Iterator iterator(Class enumClass)
Gets an
Iterator
over the
Enum
objects in
an
Enum
class.
The
Iterator
is in the order that the objects were
created (source code order). If the requested class has no enum
objects an empty
Iterator
is returned.
enumClass
- the class of the Enum
to get,
must not be null
- an iterator of the Enum objects
readResolve
protected Object readResolve()
Handle the deserialization of the class to ensure that multiple
copies are not wastefully created, or illegal enum types created.
toString
public String toString()
Human readable description of this Enum item.
- String in the form
type[name]
, for example:
Color[Red]
. Note that the package name is stripped from
the type name.