Java Enums
- Java Enums
- Why use enums?
- Properties of enums
- 1. Declaration
- 2. Enums extend java.lang.Enum
- 3. Enumerated types aren’t integers
- 4. Enums have no public constructor
- 5. Enum values are public, static, and final
- 6. The enum itself is effectively final
- 7. Enum declared inside a class becomes a final static inner class
- 8. Enum values can be compared with == or equals()
- 9. Enums override toString()
- 10. Enums provide valueOf() method
- 11. Enums define a final instance method named ordinal()
- 12. Enums define a values() method
- 13. Enum constructor
- 14. Any method added to an enum is implicitly static
- 15. Enums work with switch
- 16. Maps of Enums
- 17. Sets of Enums
- 18. Interfaces with Enums
- 19. Value specific class bodies
- 20. Manually define a custom enum
- 21. Extending an enum
- 22. Check if an object is an instance of enum or class
- 23. Get all existing enum constants from an enum instance
- 24. Why is Enum declared with generics in the API?
- 25. Modify enums during runtime
Why use enums?
Checkout this answer from stackoverflow.
Start with a real time scenario of using enums:
package test;
import test.GradeTest.Grade;
public class GradeTest {
public enum Grade { A, B, C, D, F, INCOMPLETE };
public static void main(String[] args) {
Student student1 = new Student("John");
Student student2 = new Student("Ben");
student1.setGrade(Grade.B);
student2.setGrade(Grade.INCOMPLETE);
System.out.println(student1);
System.out.println(student2);
}
}
class Student {
private String name;
private Grade grade;
public Student(String name) {
this.name = name;
}
public void setGrade(Grade grade) {
this.grade = grade;
}
public Grade getGrade() {
return grade;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "Student: " + name + " got grade " + grade.toString();
}
}
Properties of enums
1. Declaration
Enums are declared using the enum keyword.
2. Enums extend java.lang.Enum
java.lang.Enum is an abstract class. This is the implicit base class for all enum types. It is declared as follows:
public abstract class Enum extends Object implements Comparable, Serializable
This clearly means that enums are comparable and serializable implicitly.
3. Enumerated types aren’t integers
Each declared value is an instance of the enum class itself; this ensures type-safety and allows for even more compile-time checking.
4. Enums have no public constructor
5. Enum values are public, static, and final
6. The enum itself is effectively final
It cannot be subclassed. In fact, the specification says that you are not allowed to declare an enum as final or abstract, as the compiler will take care of those details.
7. Enum declared inside a class becomes a final static inner class
When declared inside a class (like the example above) it becomes a final static inner class. This explains why we needed to import test.GradeTest.Grade within the same program (the same goes for inner classes). Also if you check the generated class files, you will notice that there is a GradeTest$Grade.class file.
Note: Java does not have static (top-level) classes but has static inner classes (also known as static member classes). More here.
As enum is static, you cannot access surrounding class’s instance variables.
If enum is defined outside the class:
package test;
enum Grade { A, B, C, D, F, INCOMPLETE };
public class GradeTest {
/* No changes */
}
class Student {
/* No changes */
}
Then we see that there is no need for the import. (Now after compiling, there is a Grade.class file.)
8. Enum values can be compared with == or equals()
9. Enums override toString()
The toString() method on an enumerated type returns the name of the value. Grade.A.toString() returns A.
10. Enums provide valueOf() method
The final static valueOf() method internally calls name(). Grade.valueOf("A") returns A.
11. Enums define a final instance method named ordinal()
ordinal() returns the integer position of each enumerated value, starting at zero, based on the declaration order in the enum.
enum Grade {
A, B, C, D, F, INCOMPLETE;
public String toString() {
return "Name of enum: " + this.name() + "; " + "Ordinal of enum: " + this.ordinal();
}
};
public class GradeTest {
public static void main(String[] args) {
System.out.println(Grade.A.toString());
System.out.println(Grade.valueOf("A"));
}
}
Output:
Name of enum: A; Ordinal of enum: 0
Name of enum: A; Ordinal of enum: 0
12. Enums define a values() method
values() returns an array of the enum type. So, values() allows for iteration over the values of an enum.
for (Grade grade : Grade.values()) {
System.out.println(grade.name());
}
prints
A
B
C
D
F
INCOMPLETE
13. Enum constructor
By default, enums do not require you to give constructor definitions and their default value is always represented by the string used in declaration.
You MUST use private constructors when you override the default constructor.
enum Grade {
A(5), B(4), C(3), D(2), F(1), INCOMPLETE(-1);
private int gpa;
private Grade(int gpa) {
this.gpa = gpa;
}
public int getGpa() {
return gpa;
}
};
Each enum constant corresponds to an enum object of that given enum type.
In our example when the enum class Grade is initialized, the constructors are called and 6 objects created.
14. Any method added to an enum is implicitly static
enum Grade {
A(5), B(4), C(3), D(2), F(0), INCOMPLETE(-1);
private int gpa;
private String comment;
private Grade(int gpa) {
this.gpa = gpa;
}
public int getGpa() {
return gpa;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
};
System.out.println(Grade.A);
Grade.A.setComment("You rock! Keep rocking!!");
System.out.println(Grade.A.getComment());
Grade grade1 = Grade.A;
grade1.setComment("hihi");
Grade grade2 = Grade.A;
grade2.setComment("hoho");
if (grade1 == grade2) {
System.out.println("grade1==grade2");
}
if (grade1 == Grade.A) {
System.out.println("grade1==Grade.A");
}
15. Enums work with switch
Prior to Java 1.4, switch only worked with int, short, char, and byte values.
Grade grade = Grade.A;
switch (grade) {
case A:
System.out.println("You got top grade");
break;
default:
System.out.println("Die. The rest of you");
break;
}
16. Maps of Enums
See EnumMap.
17. Sets of Enums
See EnumSet.
18. Interfaces with Enums
interface GiftMachine {
public String sendGift();
}
enum Grade implements GiftMachine {
A(5), B(4), C(3), D(2), F(0), INCOMPLETE(-1);
private int gpa;
private Grade(int gpa) {
this.gpa = gpa;
}
public int getGpa() {
return gpa;
}
@Override
public String sendGift() {
System.out.println("sending Gift");
if (this.equals(Grade.A)) {
return "You get 10 million dollars";
}
return "boo... you get nothing";
}
};
19. Value specific class bodies
It means that each enumerated value within a type can define value-specific methods. This cannot be done exclusively for a specific type. Instead the method is declared abstract for the enum and each type defines their own implementation.
What happens is, 6 anonymous class definitions are created and instantiated. And now each type, say A, refers to this instance.
If you check your class files, you will find 6 new files: Grade$1.class … Grade$6.class.
enum Grade {
A(5) {
public void doSomething() {
System.out.println("promote this guy");
}
}, B(4) {
public void doSomething() {
// don't do anything
}
}, C(3) {
public void doSomething() {
// don't do anything
}
}, D(2) {
public void doSomething() {
// don't do anything
}
}, F(0) {
public void doSomething() {
// don't do anything
}
}, INCOMPLETE(-1) {
public void doSomething() {
System.out.println("fail this guy");
}
};
private int gpa;
private Grade(int gpa) {
this.gpa = gpa;
}
public int getGpa() {
return gpa;
}
public abstract void doSomething();
};
Grade grade = Grade.A;
grade.doSomething();
20. Manually define a custom enum
You cannot do this. The compiler stops you.
class MyEnum extends Enum { }
21. Extending an enum
You cannot do this. The compiler stops you.
enum StudentGrade extends Grade { }
22. Check if an object is an instance of enum or class
Using Class.isEnum():
Grade grade = Grade.A;
System.out.println(grade.getClass().isEnum());
23. Get all existing enum constants from an enum instance
Using Class.getEnumConstants():
Grade grade = Grade.A;
Grade[] allgrades = grade.getClass().getEnumConstants();
for (Grade g : allgrades) {
System.out.println(g.name());
}
Note: we could also just write Grade[] allgrades = Grade.class.getEnumConstants(); to get the same result.
24. Why is Enum declared with generics in the API?
public abstract class Enum<E extends Enum<E>>
extends Object
implements Comparable<E>, Serializable
Why is generics used here? A detailed answer is here.
But if you need a concise explanation, here it is:
abstract class Foo<SubClassOfFoo extends Foo<SubClassOfFoo>> {
/** subclasses are forced to return themselves from this method */
public abstract SubClassOfFoo subclassAwareDeepCopy();
}
class Bar extends Foo<Bar> {
public Bar subclassAwareDeepCopy() {
Bar b = new Bar();
// ...
return b;
}
}
Bar b = new Bar();
Foo<Bar> f = b;
Bar b2 = b.subclassAwareDeepCopy();
Bar b3 = f.subclassAwareDeepCopy(); // no need to cast, return type is Bar
The trick going on here is:
- Any subclass of
Foomust supply a type argument toFoo. - That type argument must actually be a subclass of
Foo. - Subclasses of
Foo(likeBar) follow the idiom that the type argument they supply toFoois themselves. Foohas a method that returnsSubClassOfFoo. Combined with the above idiom, this allowsFooto formulate a contract that says “any subclass of me must implementsubclassAwareDeepCopy()and they must declare that it returns that actual subclass”.
Now, java.lang.Enum is declared as Enum<E extends Enum<E>>.
E is used in the return type of getDeclaringClass(), and as an argument to compareTo(). Which means you can write code like the following that (a) doesn’t need to cast and (b) can use methods defined in Enum in terms of the concrete enum subclass:
Rank r = Rank.ACE;
Suit s = Suit.HEART;
r.compareTo(s); // syntax error, argument must be of type Rank
Rank z = Enum.valueOf(Rank.class, "TWO");
25. Modify enums during runtime
Older solution: niceideas.ch
A little improved solution: javaspecialists
Note that both solutions use a little bit of hacking using the sun.reflect package. These packages, though included in the JDK, are not accessible by default to the program. Reason being that these are used internally by the JDK and are not part of the supported, public interface.
Oracle explains it further:
A Java program that directly calls into sun.* packages is not guaranteed to work on all Java-compatible platforms. In fact, such a program is not guaranteed to work even in future versions on the same platform.
To make it work, if you are using Eclipse then open Java build path -> Libraries -> Expand JRE System Library -> Double click Access rules -> Add access.

Also see: Java enum lookup by name or field without throwing