I had learned that in Java the static block gets executed when the class is initialized and instance block get executed before the construction of each instance of the class . I had always seen the static block to execute before the instance block . Why the case is opposite for enums
?
Can anyone please explain me the output of the sample code :
enum CoffeeSize {
BIG(8), LARGE(10),HUGE(12),OVERWHELMING();
private int ounces ;
static {
System.out.println("static block ");
}
{
System.out.println("instance block");
}
private CoffeeSize(int ounces){
this.ounces = ounces;
System.out.println(ounces);
}
private CoffeeSize(){
this.ounces = 20;
System.out.println(ounces);
}
public int getOunces() {
return ounces;
}
}
Output:
instance block
8
instance block
10
instance block
12
instance block
20
static block
You need to know that enum values are static fields which hold instances of that enum type, and initialization order of static fields depends on their position.
See this example
class SomeClass{
public SomeClass() { System.out.println("creating SomeClass object"); }
}
class StaticTest{
static{ System.out.println("static block 1"); }
static SomeClass sc = new SomeClass();
static{ System.out.println("static block 2"); }
public static void main(String[] args) {
new StaticTest();
}
}
output
static block 1
creating SomeClass object
static block 2
Now since enum values are always placed at start of enum type, they will always be called before any static initialization block, because everything else can only be declared after enum values.
BUT initialization of enum values (which happens at class initialization) their constructors are called and as you said non-static initialization blocks are executed at start of every constructor which is why you see them:
- for every enum value
- and before any static initialization block.
Little late and building up on Pshemo’s answer. The output of the (compiling) code below is as follows:
8
10
Foo
static block
Bar
So the enum constant initializations are executed first (as Pshemo said, they are always implicitly static
and final
, see second blockquote) and then all fields explicitly declared as static
are initialized. As mentioned, the language specification says this about the order of execution during class initialization and about enum constants:
class StaticTest {
enum CoffeeSize {
BIG(8), LARGE(10);
private int ounces;
static Foo foo = new Foo();
static { System.out.println("static block "); }
static Bar bar = new Bar();
private CoffeeSize(int ounces){
this.ounces = ounces;
System.out.println(ounces);
}
}
public static void main(String[] args) {
CoffeeSize cs = CoffeeSize.LARGE;
}
}
class Foo { public Foo() { System.out.println("Foo"); } }
class Bar { public Bar() { System.out.println("Bar"); } }
Use bytecode to make out this problem.
import java.util.ArrayList;
import java.util.List;
public enum EnumDemo {
ONE(1), TWO(2);
private final static List<Integer> vals;
static {
System.out.println("fetch instance from static");
vals = new ArrayList<>();
EnumDemo[] values = EnumDemo.values();
for (EnumDemo value : values) {
vals.add(value.val);
}
}
private int val;
EnumDemo(int val){
this.val = val;
System.out.println("create instance:" + val);
}
}
use javac compile to class file, and then javap -c EnumDemo.class
, got this:
Compiled from "EnumDemo.java"
public final class EnumDemo extends java.lang.Enum<EnumDemo> {
public static final EnumDemo ONE;
public static final EnumDemo TWO;
public static EnumDemo[] values();
Code:
0: getstatic #1 // Field $VALUES:[LEnumDemo;
3: invokevirtual #2 // Method "[LEnumDemo;".clone:()Ljava/lang/Object;
6: checkcast #3 // class "[LEnumDemo;"
9: areturn
public static EnumDemo valueOf(java.lang.String);
Code:
0: ldc_w #4 // class EnumDemo
3: aload_0
4: invokestatic #5 // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
7: checkcast #4 // class EnumDemo
10: areturn
static {};
Code:
0: new #4 // class EnumDemo
3: dup
4: ldc #16 // String ONE
6: iconst_0
7: iconst_1
8: invokespecial #17 // Method "<init>":(Ljava/lang/String;II)V
11: putstatic #18 // Field ONE:LEnumDemo;
14: new #4 // class EnumDemo
17: dup
18: ldc #19 // String TWO
20: iconst_1
21: iconst_2
22: invokespecial #17 // Method "<init>":(Ljava/lang/String;II)V
25: putstatic #20 // Field TWO:LEnumDemo;
28: iconst_2
29: anewarray #4 // class EnumDemo
32: dup
33: iconst_0
34: getstatic #18 // Field ONE:LEnumDemo;
37: aastore
38: dup
39: iconst_1
40: getstatic #20 // Field TWO:LEnumDemo;
43: aastore
44: putstatic #1 // Field $VALUES:[LEnumDemo;
47: getstatic #8 // Field java/lang/System.out:Ljava/io/PrintStream;
50: ldc #21 // String fetch instance from static
52: invokevirtual #15 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
55: new #22 // class java/util/ArrayList
58: dup
59: invokespecial #23 // Method java/util/ArrayList."<init>":()V
62: putstatic #24 // Field vals:Ljava/util/List;
65: invokestatic #25 // Method values:()[LEnumDemo;
68: astore_0
69: aload_0
70: astore_1
71: aload_1
72: arraylength
73: istore_2
74: iconst_0
75: istore_3
76: iload_3
77: iload_2
78: if_icmpge 109
81: aload_1
82: iload_3
83: aaload
84: astore 4
86: getstatic #24 // Field vals:Ljava/util/List;
89: aload 4
91: getfield #7 // Field val:I
94: invokestatic #26 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
97: invokeinterface #27, 2 // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
102: pop
103: iinc 3, 1
106: goto 76
109: return
}
So, enum instance is the static instance, and at the head.
1. An enum type is a type whose fields consist of a fixed set of constants. Common examples include compass directions (values of NORTH, SOUTH, EAST, and WEST) and the days of the week.
2. They are static final constant, therefore have all letters in Caps.
3. And static variables are initialized as soon as the JVM loads the class.
For further details see this link:
http://docs.oracle.com/javase/1.5.0/docs/guide/language/enums.html
I just wanted to add that I would instantly be a regular customer of any cafe that offered an
OVERWHELMING
size of coffee mug.