Reputation:
Java enums are classes. They are compiled as classes.
How will the following example be compiled? What is its "class version"? What is the exact class code? I want actual Java code.
public enum Ordinals {
FIRST("st"),
SECOND("nd"),
THIRD("rd");
private String notation;
private Ordinals(String notation) {
this.notation = notation;
}
public String getNotation() {
return notation;
}
}
Upvotes: 24
Views: 10520
Reputation: 8353
Using the javap - p Ordinals.class
command you will obtain the following code:
public final class Ordinals extends java.lang.Enum<Ordinals> {
public static final Ordinals FIRST;
public static final Ordinals SECOND;
public static final Ordinals THIRD;
private java.lang.String notation;
private static final Ordinals[] $VALUES;
public static Ordinals[] values();
public static Ordinals valueOf(java.lang.String);
private Ordinals(java.lang.String);
public java.lang.String getNotation();
static {};
}
So, every value of the enum
is translated to a public static final
field of the class type. If I did understand right, in the static
block those field are initialized using the private
constructor, such that
static {
Ordinals.FIRST = new Ordinals("st");
Ordinals.SECOND = new Ordinals("nd");
Ordinals.THIRD = new Ordinals("rd");
// ...
}
As stated in the item 3 of the Effective Java book, an enum
is treated more or less like a Singleton and this is reflected in the use of the above public final static
fields.
Upvotes: 4
Reputation: 9945
Each enum
class is compiled as a class being a subclass of java.lang.Enum
. Each enum constant becomes a static final
constant within that class. Then, an array $VALUES
is created with all of the enum constants, in order of declaration.
You can disassemble the code using the command javap -p -c Ordinals
(on the compiled .class file) to find out the details.
Compiled from "Ordinals.java"
public final class Ordinals extends java.lang.Enum<Ordinals> {
public static final Ordinals FIRST;
public static final Ordinals SECOND;
public static final Ordinals THIRD;
private java.lang.String notation; // your custom field
private static final Ordinals[] $VALUES; // all enum constants
public static Ordinals[] values(); // every enum class has this static method
Code:
0: getstatic #1 // Field $VALUES:[LOrdinals;
3: invokevirtual #2 // Method "[LOrdinals;".clone:()Ljava/lang/Object;
6: checkcast #3 // class "[LOrdinals;"
9: areturn
public static Ordinals valueOf(java.lang.String); // every enum class has this static method
Code:
0: ldc_w #4 // class Ordinals
3: aload_0
4: invokestatic #5 // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
7: checkcast #4 // class Ordinals
10: areturn
private Ordinals(java.lang.String);
Code:
0: aload_0
1: aload_1
2: iload_2
3: invokespecial #6 // Method java/lang/Enum."<init>":(Ljava/lang/String;I)V
6: aload_0
7: aload_3
8: putfield #7 // Field notation:Ljava/lang/String;
11: return
public java.lang.String getNotation();
Code:
0: aload_0
1: getfield #7 // Field notation:Ljava/lang/String;
4: areturn
static {}; // fills the $VALUES array and initializes the static fields corresponding to the enum constants
Code:
0: new #4 // class Ordinals
3: dup
4: ldc #8 // String FIRST
6: iconst_0
7: ldc #9 // String st
9: invokespecial #10 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;)V
12: putstatic #11 // Field FIRST:LOrdinals;
15: new #4 // class Ordinals
18: dup
19: ldc #12 // String SECOND
21: iconst_1
22: ldc #13 // String nd
24: invokespecial #10 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;)V
27: putstatic #14 // Field SECOND:LOrdinals;
30: new #4 // class Ordinals
33: dup
34: ldc #15 // String THIRD
36: iconst_2
37: ldc #16 // String rd
39: invokespecial #10 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;)V
42: putstatic #17 // Field THIRD:LOrdinals;
45: iconst_3
46: anewarray #4 // class Ordinals
49: dup
50: iconst_0
51: getstatic #11 // Field FIRST:LOrdinals;
54: aastore
55: dup
56: iconst_1
57: getstatic #14 // Field SECOND:LOrdinals;
60: aastore
61: dup
62: iconst_2
63: getstatic #17 // Field THIRD:LOrdinals;
66: aastore
67: putstatic #1 // Field $VALUES:[LOrdinals;
70: return
}
That would translate back to Java as
public final class Ordinals extends java.lang.Enum<Ordinals> {
public static final Ordinals FIRST;
public static final Ordinals SECOND;
public static final Ordinals THIRD;
private String notation;
private static final Ordinals[] $VALUES;
public static Ordinals[] values() {
return $VALUES.clone();
}
public static Ordinals valueOf(String name) {
return (Ordinals) Enum.valueOf(Ordinals.class, name);
}
private Ordinals(String name, int ordinal, String notation) {
super(name, ordinal);
this.notation = notation
}
static {
FIRST = new Ordinals("FIRST", 0, "st");
SECOND = new Ordinals("SECOND", 1, "nd");
THIRD = new Ordinals("THIRD", 2, "rd");
Ordinals[] $VALUES = new Ordinals[3];
$VALUES[0] = FIRST;
$VALUES[1] = SECOND;
$VALUES[2] = THIRD;
Ordinals.$VALUES = $VALUES;
}
}
Class version is totally unrelated to that - it depends on the version of the Java compiler that you used (or on the explicit setting on the compiler to force it to compile for an older Java version).
Upvotes: 31
Reputation: 34618
The output of javap -private
for this is:
public final class Ordinals extends java.lang.Enum<Ordinals> {
public static final Ordinals FIRST;
public static final Ordinals SECOND;
public static final Ordinals THIRD;
private java.lang.String notation;
private static final Ordinals[] $VALUES;
public static Ordinals[] values();
public static Ordinals valueOf(java.lang.String);
private Ordinals(java.lang.String);
public java.lang.String getNotation();
static {};
}
As you see, the compiler added a few things.
There is a synthetic Array $VALUES
, which is going to be copied out whenever you call the values()
method.
The values()
method itself is added to the class, to conform to the requirement of every enum that there should be a static values()
method returning an array of all the enum constants. Why is it added by the compiler rather than inherited from Enum()
? Because it is static.
In the same manner, valueOf
has been added. It is implemented by calling the static Enum.valueOf
.
One thing that you do not see in this listing is that the constructors have two additional, unseen parameters, which are passed when the enum constants are set up. They are the constant's name and its ordinal number. They are passed up to the super()
constructor from Enum
and used for the methods name()
and ordinal()
which are inherited from it.
Upvotes: 1
Reputation: 95958
You can think about enums as a class with typed constants. You can think of your code as:
public enum Ordinals {
public static final FIRST = "st";
public static final SECOND = ..;
// ...
private String notation;
private Ordinals(String notation) {
this.notation = notation;
}
public String getNotation() {
return notation;
}
}
The javap
command might be useful for you, try this:
javap Example.class
:
public final class Example extends java.lang.Enum<Example> {
public static final Example FIRST;
public static final Example SECOND;
public static final Example THIRD;
public static Example[] values();
public static Example valueOf(java.lang.String);
public java.lang.String getNotation();
static {};
}
Upvotes: 3
Reputation: 73548
Class version
is what tells which Java version a class file is compiled with. You probably weren't interested in that.
Your enum
will be compiled normally, with Ordinals
implicitly extending the Enum
class, and with 3 class level variables, all instances of the Ordinals
class.
Upvotes: 2