Class Enum
- java.lang.Object
-
- org.apache.commons.lang.enums.Enum
-
- All Implemented Interfaces:
java.io.Serializable
,java.lang.Comparable
- Direct Known Subclasses:
ValuedEnum
public abstract class Enum extends java.lang.Object implements java.lang.Comparable, java.io.Serializable
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
anditerator
methods are recommended. Unfortunately, Java restrictions require these to be coded as shown in each subclass. An alternative choice is to use theEnumUtils
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.
Nested class Enums
Care must be taken with class loading when defining a static nested class for enums. The static nested class can be loaded without the surrounding outer class being loaded. This can result in an empty list/map/iterator being returned. One solution is to define a static block that references the outer class where the constants are defined. For example:
public final class Outer { public static final BWEnum BLACK = new BWEnum("Black"); public static final BWEnum WHITE = new BWEnum("White"); // static nested enum class public static final class BWEnum extends Enum { static { // explicitly reference BWEnum class to force constants to load Object obj = Outer.BLACK; } // ... other methods omitted } }
Although the above solves the problem, it is not recommended. The best solution is to define the constants in the enum class, and hold references in the outer class:
public final class Outer { public static final BWEnum BLACK = BWEnum.BLACK; public static final BWEnum WHITE = BWEnum.WHITE; // static nested enum class public static final class BWEnum extends Enum { // only define constants in enum classes - private if desired private static final BWEnum BLACK = new BWEnum("Black"); private static final BWEnum WHITE = new BWEnum("White"); // ... other methods omitted } }
For more details, see the 'Nested' test cases.
Lang Enums and Java 5.0 Enums
Enums were added to Java in Java 5.0. The main differences between Lang's implementation and the new official JDK implementation are:
- The standard Enum is a not just a superclass, but is a type baked into the language.
- The standard Enum does not support extension, so the standard methods that are provided in the Lang enum are not available.
- Lang mandates a String name, whereas the standard Enum uses the class name as its name. getName() changes to name().
Generally people should use the standard Enum. Migrating from the Lang enum to the standard Enum is not as easy as it might be due to the lack of class inheritence in standard Enums. This means that it's not possible to provide a 'super-enum' which could provide the same utility methods that the Lang enum does. The following utility class is a Java 5.0 version of our EnumUtils class and provides those utility methods.
import java.util.*; public class EnumUtils { public static Enum getEnum(Class enumClass, String token) { return Enum.valueOf(enumClass, token); } public static Map getEnumMap(Class enumClass) { HashMap map = new HashMap(); Iterator itr = EnumUtils.iterator(enumClass); while(itr.hasNext()) { Enum enm = (Enum) itr.next(); map.put( enm.name(), enm ); } return map; } public static List getEnumList(Class enumClass) { return new ArrayList( EnumSet.allOf(enumClass) ); } public static Iterator iterator(Class enumClass) { return EnumUtils.getEnumList(enumClass).iterator(); } }
- Since:
- 2.1 (class existed in enum package from v1.0)
- Version:
- $Id: Enum.java 912394 2010-02-21 20:16:22Z niallp $
- See Also:
- Serialized Form
-
-
Nested Class Summary
Nested Classes Modifier and Type Class Description private static class
Enum.Entry
Enable the iterator to retain the source code order.
-
Field Summary
Fields Modifier and Type Field Description private static java.util.Map
cEnumClasses
Map
, key of class name, value ofEntry
.private static java.util.Map
EMPTY_MAP
An emptyMap
, as JDK1.2 didn't have an empty map.private int
iHashCode
The hashcode representation of the Enum.private java.lang.String
iName
The string representation of the Enum.protected java.lang.String
iToString
The toString representation of the Enum.private static long
serialVersionUID
Required for serialization support.
-
Constructor Summary
Constructors Modifier Constructor Description protected
Enum(java.lang.String name)
Constructor to add a new named item to the enumeration.
-
Method Summary
All Methods Static Methods Instance Methods Concrete Methods Modifier and Type Method Description int
compareTo(java.lang.Object other)
Tests for order.private static Enum.Entry
createEntry(java.lang.Class enumClass)
Creates anEntry
for storing the Enums.boolean
equals(java.lang.Object other)
Tests for equality.private static Enum.Entry
getEntry(java.lang.Class enumClass)
Gets anEntry
from the map of Enums.protected static Enum
getEnum(java.lang.Class enumClass, java.lang.String name)
Gets anEnum
object by class and name.java.lang.Class
getEnumClass()
Retrieves the Class of this Enum item, set in the constructor.protected static java.util.List
getEnumList(java.lang.Class enumClass)
Gets theList
ofEnum
objects using theEnum
class.protected static java.util.Map
getEnumMap(java.lang.Class enumClass)
Gets theMap
ofEnum
objects by name using theEnum
class.java.lang.String
getName()
Retrieve the name of this Enum item, set in the constructor.private java.lang.String
getNameInOtherClassLoader(java.lang.Object other)
Use reflection to return an objects class name.int
hashCode()
Returns a suitable hashCode for the enumeration.private void
init(java.lang.String name)
Initializes the enumeration.protected static java.util.Iterator
iterator(java.lang.Class enumClass)
Gets anIterator
over theEnum
objects in anEnum
class.protected java.lang.Object
readResolve()
Handle the deserialization of the class to ensure that multiple copies are not wastefully created, or illegal enum types created.java.lang.String
toString()
Human readable description of this Enum item.
-
-
-
Field Detail
-
serialVersionUID
private static final long serialVersionUID
Required for serialization support.- See Also:
Serializable
, Constant Field Values
-
EMPTY_MAP
private static final java.util.Map EMPTY_MAP
An emptyMap
, as JDK1.2 didn't have an empty map.
-
cEnumClasses
private static java.util.Map cEnumClasses
Map
, key of class name, value ofEntry
.
-
iName
private final java.lang.String iName
The string representation of the Enum.
-
iHashCode
private final transient int iHashCode
The hashcode representation of the Enum.
-
iToString
protected transient java.lang.String iToString
The toString representation of the Enum.- Since:
- 2.0
-
-
Constructor Detail
-
Enum
protected Enum(java.lang.String name)
Constructor to add a new named item to the enumeration.
- Parameters:
name
- the name of the enum object, must not be empty ornull
- Throws:
java.lang.IllegalArgumentException
- if the name isnull
or an empty stringjava.lang.IllegalArgumentException
- if the getEnumClass() method returns a null or invalid Class
-
-
Method Detail
-
init
private void init(java.lang.String name)
Initializes the enumeration.- Parameters:
name
- the enum name- Throws:
java.lang.IllegalArgumentException
- if the name is null or empty or duplicatejava.lang.IllegalArgumentException
- if the enumClass is null or invalid
-
readResolve
protected java.lang.Object readResolve()
Handle the deserialization of the class to ensure that multiple copies are not wastefully created, or illegal enum types created.
- Returns:
- the resolved object
-
getEnum
protected static Enum getEnum(java.lang.Class enumClass, java.lang.String name)
Gets an
Enum
object by class and name.- Parameters:
enumClass
- the class of the Enum to get, must not benull
name
- the name of theEnum
to get, may benull
- Returns:
- the enum object, or
null
if the enum does not exist - Throws:
java.lang.IllegalArgumentException
- if the enum class isnull
-
getEnumMap
protected static java.util.Map getEnumMap(java.lang.Class enumClass)
Gets the
Map
ofEnum
objects by name using theEnum
class.If the requested class has no enum objects an empty
Map
is returned.- Parameters:
enumClass
- the class of theEnum
to get, must not benull
- Returns:
- the enum object Map
- Throws:
java.lang.IllegalArgumentException
- if the enum class isnull
java.lang.IllegalArgumentException
- if the enum class is not a subclass of Enum
-
getEnumList
protected static java.util.List getEnumList(java.lang.Class enumClass)
Gets the
List
ofEnum
objects using theEnum
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.- Parameters:
enumClass
- the class of theEnum
to get, must not benull
- Returns:
- the enum object Map
- Throws:
java.lang.IllegalArgumentException
- if the enum class isnull
java.lang.IllegalArgumentException
- if the enum class is not a subclass of Enum
-
iterator
protected static java.util.Iterator iterator(java.lang.Class enumClass)
Gets an
Iterator
over theEnum
objects in anEnum
class.The
Iterator
is in the order that the objects were created (source code order). If the requested class has no enum objects an emptyIterator
is returned.- Parameters:
enumClass
- the class of theEnum
to get, must not benull
- Returns:
- an iterator of the Enum objects
- Throws:
java.lang.IllegalArgumentException
- if the enum class isnull
java.lang.IllegalArgumentException
- if the enum class is not a subclass of Enum
-
getEntry
private static Enum.Entry getEntry(java.lang.Class enumClass)
Gets an
Entry
from the map of Enums.- Parameters:
enumClass
- the class of theEnum
to get- Returns:
- the enum entry
-
createEntry
private static Enum.Entry createEntry(java.lang.Class enumClass)
Creates an
Entry
for storing the Enums.This accounts for subclassed Enums.
- Parameters:
enumClass
- the class of theEnum
to get- Returns:
- the enum entry
-
getName
public final java.lang.String getName()
Retrieve the name of this Enum item, set in the constructor.
- Returns:
- the
String
name of this Enum item
-
getEnumClass
public java.lang.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.- Returns:
- the
Class
of the enum - Since:
- 2.0
-
equals
public final boolean equals(java.lang.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.
If the parameter is in a different class loader than this instance, reflection is used to compare the names.
- Overrides:
equals
in classjava.lang.Object
- Parameters:
other
- the other object to compare for equality- Returns:
true
if the Enums are equal
-
hashCode
public final int hashCode()
Returns a suitable hashCode for the enumeration.
- Overrides:
hashCode
in classjava.lang.Object
- Returns:
- a hashcode based on the name
-
compareTo
public int compareTo(java.lang.Object other)
Tests for order.
The default ordering is alphabetic by name, but this can be overridden by subclasses.
If the parameter is in a different class loader than this instance, reflection is used to compare the names.
- Specified by:
compareTo
in interfacejava.lang.Comparable
- Parameters:
other
- the other object to compare to- Returns:
- -ve if this is less than the other object, +ve if greater
than,
0
of equal - Throws:
java.lang.ClassCastException
- if other is not an Enumjava.lang.NullPointerException
- if other isnull
- See Also:
Comparable.compareTo(Object)
-
getNameInOtherClassLoader
private java.lang.String getNameInOtherClassLoader(java.lang.Object other)
Use reflection to return an objects class name.
- Parameters:
other
- The object to determine the class name for- Returns:
- The class name
-
toString
public java.lang.String toString()
Human readable description of this Enum item.
- Overrides:
toString
in classjava.lang.Object
- Returns:
- String in the form
type[name]
, for example:Color[Red]
. Note that the package name is stripped from the type name.
-
-