Why do static and instance init blocks in Enums behave differently from those in Classes
Asked Answered
S

2

5

In studying for the Java certification test I learned that static initialization blocks run once when the class is loaded, in order of appearance within the source code, that instance initialization blocks run each time an instance is created, and that code in constructors runs each time an instance is created after that. To test that I created a class with some static and instance init blocks and a contructor with print stuff. Everything worked as expected -- except I thought "loaded" meant just at runtime, but I guess it happens when the first instance is created, since I don't get any output at all unless I create at least 1 instance of the class. Then I tried the same with an enum and the order was all off. First, the initialization blocks run one time for each value the enum has when the enum is first referenced in code, secondly -- the init blocks marked static run after what I assumed were instance init blocks! This is the opposite of what I expected. Here is a breakdown of my questions.

  1. Why do the init blocks marked static run last in an enum?
  2. Can an enum have instance init blocks?
  3. Why do the blocks I thought were instance init blocks run only once when the enum is loaded and not each time a new enum value is referenced?
  4. Class static init blocks run when a class is "loaded". What does loaded mean? Does it occur just once when an object is instantiated in the class?

Thanks! This is very confusing to me.

public class EnumInit {
public static void main(String[] args) {
    System.out.println(Color.RED.toString() + " Main");
    MyInit myInit = new MyInit();
    System.out.println(Color.BLUE.toString() + " Main");
    MyInit mySecondInit = new MyInit();

}
}

enum Color {    
RED, BLUE, GREEN;
String instanceVar = "Enum Instance Variable Text";
static { System.out.println("Enum Static init block 1"); }
{ System.out.println("Enum Instance init block 1"); }
static { System.out.println("Enum Static static init block 2"); }
Color() { 
    System.out.println(instanceVar);
    System.out.println("Enum String Literal"); 
}
{ System.out.println("Enum Instance init block 2"); }   
}

class MyInit {
String instanceVar = "Class Instance Variable Text";
static { System.out.println("Class Static init block 1"); }
{ System.out.println("Class Instance init block 1"); }
static { System.out.println("Class Static static init block 2"); }
MyInit() { 
    System.out.println(instanceVar);
    System.out.println("Class String Literal"); 
}
{ System.out.println("Class Instance init block 2"); }  
}
Supplejack answered 16/12, 2013 at 20:9 Comment(1)
for #4: Classes arent loaded until they have had meaningful use. This could be calling a static method on the class, or creating an instance, or calling Class.forName() or whatever. I believe this is to keep the number of classes currently loaded into the perma gen to a minimum.Padnag
T
8

The Java Language Specification says this about enum constants

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. Each such field is initialized to the enum constant that corresponds to it.

So

enum Color {    
    RED, BLUE, GREEN;
    ...
}

is actually

public static final Color RED = new Color();
public static final Color BLUE = new Color();
public static final Color GREEN = new Color();

which will get evaluated before the static blocks you have.

Why do the init blocks marked static run last in an enum?

See above.

Can an enum have instance init blocks?

Yes, compile your code and you will see.

Why do the blocks I thought were instance init blocks run only once when the enum is loaded and not each time a new enum value is referenced?

Enum constants are created (instantiated) once the enum type is initialized. You don't create a new enum any time you do

Color color = Color.RED;

You are just referencing an already created, existing object.

Class static init blocks run when a class is "loaded". What does loaded mean? Does it occur just once when an object is instantiated in the class?

When a class is referenced in the JVM for the first time, it is loaded by the ClassLoader and initialized. Read more about it here.

Title answered 16/12, 2013 at 20:14 Comment(3)
So do the init blocks that aren't marked static run when each implicit constructor runs, and then the static blocks run last?Supplejack
@Supplejack Yes, those instance initializer blocks are run when new Color(); is invoked implicitly. Since enum constants are the first thing you declare in the body of an enum, those will always happen before any static blocks declared in the enum.Title
Thanks, that actually makes this process really clear.Supplejack
B
0

In enum the static init block is executed last.

Enums
    1st  - instance init block 
    2nd  - constructor block
    last - static init block or any other declared static (only once and will be always last executed)

Classes
    1st - static init block or any other declared static (only once, always first to be executed)
    2nd - instance init block
    3rd - constructor
Beckerman answered 21/12, 2021 at 3:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.