Enums - static and instance blocks

23,592

Solution 1

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.

Solution 2

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:

Next, execute either the class variable initializers and static initializers of the class, or the field initializers of the interface, in textual order, as though they were a single block.

In addition to the members that an enum type E inherits from Enum, for each declared enum constant with the name n, the enum type has an implicitly declared public static final field named n of type E. These fields are considered to be declared in the same order as the corresponding enum constants, before any static fields explicitly declared in the enum type.


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"); } }

Solution 3

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.

Solution 4

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

Share:
23,592
AllTooSir
Author by

AllTooSir

Updated on July 09, 2022

Comments

  • AllTooSir
    AllTooSir almost 2 years

    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

    • Ti Strga
      Ti Strga over 4 years
      I just wanted to add that I would instantly be a regular customer of any cafe that offered an OVERWHELMING size of coffee mug.
  • Maarten Bodewes
    Maarten Bodewes almost 12 years
    Which is why you should write them will all capitals, which indicates static final for constants, which is what they are.
  • AllTooSir
    AllTooSir almost 12 years
    @Pshemo : But I am not able to define the static block before defining the constants in that enum .It gives compilation error . Does that mean for all enums the static final constants will be initialized first and then any other static block will be executed ?
  • Pshemo
    Pshemo almost 12 years
    @noob In enum's code first thing must always be its elements. But it is not true that all static final constants will be initialized first and then any other static block. For example if you place after enum elements some static block and after it some static final element then static block will be invoked before that static final element.