I got a question about Enum.
I have an enum class looks like below
public enum FontStyle {
NORMAL("This font has normal style."),
BOLD("This font has bold style."),
ITALIC("This font has italic style."),
UNDERLINE("This font has underline style.");
private String description;
FontStyle(String description) {
this.description = description;
}
public String getDescription() {
return this.description;
}
}
I wonder when this Enum object is created.
Enum looks like 'static final' Object since its value will never changed. So in that purpose, it is efficient to initialize in compile time only.
But it calls its own constructor in top, so I doubt that it could generate whenever we call it, for example, in switch statement.
Explanation: The order of appearance of variables in Enum is their natural order (the natural order means the order in which they are declared inside Enum type). However, the compareTo() method is implemented to order the variable in ascending order.
values() is a static method of Enum , which always returns the values in same order.
4. Order and redundancy do matter when we specify an enumeration: we can enumerate the positive integers beginning with 1, 2, 3, 1, ..., but the pattern is easier to see when enumerated in the standard way as 1, 2, 3, 4, ...
Enumerated (enum) types are data types that comprise a static, ordered set of values.
TLDR: enum values are constants created once at runtime, during the initialization phase of the enum class loading. This is efficient as the enum values are only created once.
Long answer: Enums are not magical elements, but it takes some time to understand how they work. The enum behavior is related to the class loading process which can be summarized by 3 phases:
Let's explain this using the following enum class:
package mypackage;
public enum MyEnum {
V1, V2;
private MyEnum() {
System.out.println("constructor "+this);
}
static {
System.out.println("static init");
}
{
System.out.println("block "+this);
}
}
In order to understand how it works for enums, lets decompile the code using javap -c MyEnum
. This will learn us that:
public static final
values) in the classMyEnum.values()
returns the list of all enum values as an immutable copy of the enum values array.The decompiled code is the following:
// 1. an enum is implemented as a special class
public final class mypackage.MyEnum extends java.lang.Enum<mypackage.MyEnum> {
public static final mypackage.MyEnum V1; // 2. enum values are constants of the enum class
public static final mypackage.MyEnum V2;
static {};
Code: // 3. all enum values are created in the static initializer block
// create the enum value V1
0: new #1 // class mypackage/MyEnum
3: dup
4: ldc #14 // String V1
6: iconst_0
7: invokespecial #15 // Method "<init>":(Ljava/lang/String;I)V
10: putstatic #19 // Field V1:Lmypackage/MyEnum;
// create the enum value V2
13: new #1 // class mypackage/MyEnum
16: dup
17: ldc #21 // String V2
19: iconst_1
20: invokespecial #15 // Method "<init>":(Ljava/lang/String;I)V
23: putstatic #22 // Field V2:Lmypackage/MyEnum;
// create an array to store all enum values
39: iconst_2
40: anewarray #1 // class mypackage/MyEnum
43: dup
44: iconst_0
45: getstatic #19 // Field V1:Lmypackage/MyEnum;
48: aastore
49: dup
50: iconst_1
51: getstatic #22 // Field V2:Lmypackage/MyEnum;
54: aastore
61: putstatic #27 // Field ENUM$VALUES:[Lmypackage/MyEnum;
64: getstatic #29 // Field java/lang/System.out:Ljava/io/PrintStream;
67: ldc #35 // String "static init"
69: invokevirtual #37 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
72: return
public static mypackage.MyEnum[] values();
Code: // 4. it returns an immutable copy of the field ENUM$VALUES
0: getstatic #27 // Field ENUM$VALUES:[Lmypackage/MyEnum;
3: dup
4: astore_0
5: iconst_0
6: aload_0
7: arraylength
8: dup
9: istore_1
10: anewarray #1 // class mypackage/MyEnum
13: dup
14: astore_2
15: iconst_0
16: iload_1
17: invokestatic #67 // Method java/lang/System.arraycopy:(Ljava/lang/Object;ILjava/lang/Object;II)V (=immutable copy)
20: aload_2
21: areturn
public static mypackage.MyEnum valueOf(java.lang.String);
Code:
0: ldc #1 // class mypackage/MyEnum
2: aload_0
3: invokestatic #73 // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
6: checkcast #1 // class mypackage/MyEnum
9: areturn
}
Consequently, the enum values are created when the static initializer block is executed, that is in the initialization phase. This can be done with one of the following methods:
System.out.println(MyEnum.V1)
)MyEnum.valueOf()
or MyEnum.myStaticMethod()
)Class.forName("mypackage.MyEnum")
(which does the loading, linking and initializing phases)MyEnum.class.getEnumConstants()
However the enum values will NOT be initialized with the following operation (which do only the loading phase, and potentially the linking phase):
MyEnum.class.anyMethod()
(except getEnumConstants()
of course): basically we access only the class metadatas, not the implementationClass.forName("myPackage.MyEnum", false, aClassLoader)
: the false
value parameter tells the classloader to avoid the initialization phaseClassLoader.getSystemClassLoader().loadClass("myPackage.MyEnum")
: explicitely does only the loading phase.Some fun other facts about enums:
Class<MyEnum>.getInstance()
throws an Exception: because there is no public constructor in the enumblock V1
, then constructor block constructor V1
, then static initializer static init
): from the decompiled code, we saw that enum values initialization takes place on the beginning of the static initializer block. For each enum value, this static initializer create a new instance, which calls the instance initializer block, then the constructor block. The static initializer ends by executing the custom static initializer block.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With