Why use enums?
Checkout this answer from stackoverflow.
Start with a real time scenario of using enums:
Properties of 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:
- enums are declared using enum keyword.
- enums extends 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, SerializableThis clearly means that enums are comparable and serializable implicitly.
- 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.
- Enums have no public constructor.
- Enum values are public, static, and final.
- The enum itself is effectively final, and so 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.
- 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 doesnot have static (top-level) classes but has static inner classes (also known as static member classes).
More here http://www.javaworld.com/article/2077372/learn-java/static-class-declarations.html
- As enum is static, you cannot access surrounding classes instance variables.
If enum is defined outside the class.
Then we see that there is no need for the import. (Now after compiling, there is a Grade.class file)package test; enum Grade { A, B, C, D, F, INCOMPLETE }; public class GradeTest { /*No changes*/ } class Student { /*No changes*/ }
- Enum values can be compared with == or equals().
- Enums override toString().
The toString() method on an enumerated type returns the name of the value.
Grade.A.toString() returns A.
- Enums provide valueOf() method.
The final static valueOf() method internally calls toString().
Grade.valueOf("A") returns A.
- Enums define a final instance method named ordinal().
oridinal() 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")); } }
Name of enum: A; Ordinal of enum: 0
Name of enum: A; Ordinal of enum: 0
- Enums define a values() method.
values() return an array of the enum type. So, values() allows for iteration over the values of an enum.
printsfor(Grade grade : Grade.values()) { System.out.println(grade.name()); }
A
B
C
D
F
INCOMPLETE
- Enum constructor
By default, enums do not require you to give constructor definitions and
their default values is always represented by string used in declaration.
You MUST use private constructors when you override the default constructor.
Each enum constant corresponds to an enum object of that given enum type.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; } };
In our example when the enum class Grade is initialized, the constructors are called and
6 objects created.
- Any method added to an enum are 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"); }
- Enums work with switchs
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; }
- Maps of Enums
http://docs.oracle.com/javase/7/docs/api/java/util/EnumMap.html
- Sets of Enums
http://docs.oracle.com/javase/7/docs/api/java/util/EnumSet.html
- 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"; } };
- Value specific class bodies
It means is 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" now 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();
- Manually define a custom enum
You cannot do this.
Compiler stops you.class MyEnum extends Enum { }
- Extending an enum
You cannot do this.
Compiler stops you.enum StudentGrade extends Grade { }
- Check if an object is an instance of enum or class - using Class.isEnum()
Grade grade = Grade.A; System.out.println(grade.getClass().isEnum());
- Get all existing enum constants from a enum instance - using Class.getEnumConstants();
Grade grade = Grade.A; Grade[] allgrades = grade.getClass().getEnumConstants(); for(Grade g : allgrades) { System.out.println(g.name()); }
- Why is enum declared in the API as follows
public abstract class Enum<e extends Enum<E>> extends Object implements Comparable
, Serializable
Why is generics used here?
A detailed answer is here
But if you need a consise 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
{ public Bar subclassAwareDeepCopy() { Bar b = new Bar(); // ... return b; } } Bar b = new Bar(); Foo 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 Foo must supply a type argument to Foo.
That type argument must actually be a subclass of Foo.
Subclasses of Foo (like Bar) follow the idiom that the type argument they supply to Foo is themselves.
Foo has a method that returns SubClassOfFoo. Combined with the above idiom,
this allows Foo to formulate a contract that says "any subclass of me must implement subclassAwareDeepCopy() and they
must declare that it returns that actual subclass".
Now,
E is used in the return type of getDeclaringClass(), and as an argument to compareTo().java.lang.Enum is declared as Enum<e extends Enum<E>>.
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");
- 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 is not accessible by default to the program. Reason being that these are used internally by 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 -> Added access.
Hi John,
ReplyDeleteIn example 25 we could just write
Grade[] allgrades = Grade.class.getEnumConstants();
to get the same result.
Point 12, "The final static valueOf() method internally calls toString()". This is incorrect, it calls name().
ReplyDelete