Strange behavior using braces in Java
Asked Answered
A

9

40

When I run the following code:

public class Test {

  Test(){
    System.out.println("1");
  }

  {
    System.out.println("2");
  }

  static {
    System.out.println("3");
  }

  public static void main(String args[]) {
    new Test();
  }
}

I expect to get the output in this order:

1
2
3

but what I got is in reverse order:

3
2
1

Can anyone explain why it is output in reverse order?

================

Also, when I create more than one instance of Test:

new Test();
new Test();
new Test();
new Test();

static block is executed only at first time.

Annamariaannamarie answered 18/11, 2011 at 16:41 Comment(3)
+1 See also §8.7 Static Initializers.Pelias
Out of curiosity, why do you consider this behavior strange? Why do you expect the blocks to run in the order you describe?Shari
For complete explanation see my answer below.Urticaceous
T
62

It all depends on the order of execution of initialization statements. Your test demonstrates that this order is:

  1. Static initialization blocks
  2. Instance initialization blocks
  3. Constructors

Edit

Thanks for the comments, now I can quote the appropriate part in the JVM specification. Here it is, the detailed initialization procedure.

Tutt answered 18/11, 2011 at 16:44 Comment(4)
nitpick: the test proves nothing. It does demonstrate the order you describe. For a proof, you need to look at the Java Language Spec.Dublin
double nitty pick - I'd suggest looking at the VM spec, not the language spec. Specifically, section 2.17. (note, some initializers are executed in textual order).Tension
@ObscureRobot: Whether you call it "proves" or "demonstrates", its the same thing: an emperical fact. The specs say what SHOULD happen, which may or may not match with what /does/ happen. Given that the OP expected something else, either word would be appropriate (although I will grant that demonstrates is a bit better).Stoddard
no, proof and demonstrations are very different. As are general theories and individual pieces of empirical evidence. Just because you observe some behavior on your desktop today doesn't mean that it will be there tomorrow. It may be that you are simply observing a quirk of the current implementation that will go away the next time you update your JDK or JRE. The difference is subtle but important. "Proof" has very little use in software development... unless you are talking to your boss about the budget for new hardware :)Dublin
O
30

3 - is a static initializer, it runs once when the class is loaded, which happens first.

2 - is an initializer block, the java compiler will actually copy this into each constructor, so you can share some initialization between contructors if you like. Rarely used.

1 - will be executed when you construct the object, after (3) and (2)..

More information here

Offset answered 18/11, 2011 at 16:45 Comment(0)
P
18

Static blocks are executed first.

And then the instance instance intialization blocks

Please see JLS for instance intializers

{

// sop statement

}

you cannot have a return statment within the instance initialization block, just like constructors.

Philosophism answered 18/11, 2011 at 16:42 Comment(0)
C
5
Test(){System.out.println("1");}

    {System.out.println("2");}

    static{System.out.println("3");}

static things are executed first, {System.out.println("2");} isn't a part of a function, because of its scope it is called first, and Test(){System.out.println("1");} is called last because the other two are called first

Chemistry answered 18/11, 2011 at 16:45 Comment(0)
I
5

First, class is loaded into the JVM and class initialization happens. During this step static blocks are executed. "{...}" is just a syntactic equivalent of "static{...}". Since there is already a "static{...}" block in the code, "{...}" will be appended to it. That's why you have 3 printed before 2.

Next once the class is loaded, java.exe (which I assumed you executed from the command line) will find and run the main method. The main static method initializes the instance whose constructor is invoked, so you get "1" printed last.

Instalment answered 18/11, 2011 at 16:50 Comment(1)
The block printing 2 is an instance initializer: java.sun.com/docs/books/jls/third_edition/html/classes.html#8.6 . It is not equivalent to a static initializer.Yolanthe
C
4

Because the static{} code is run when the class is first initialized within the JVM (i.e. even before main() is called), the instance {} is called when an instance is first initialized, before it's constructed, and then the constructor is called after all that is done.

Cockalorum answered 18/11, 2011 at 16:45 Comment(0)
C
4

I‘ve get the bytecode-like code here by ASM .

I think this can answer your question , explaining what happened when a object is created in this occasion.

public class Test {
static <clinit>() : void
GETSTATIC System.out : PrintStream
LDC "3"
INVOKEVIRTUAL PrintStream.println(String) : void
RETURN


<init>() : void
ALOAD 0: this
INVOKESPECIAL Object.<init>() : void
GETSTATIC System.out : PrintStream
LDC "2"
INVOKEVIRTUAL PrintStream.println(String) : void
GETSTATIC System.out : PrintStream
LDC "1"
INVOKEVIRTUAL PrintStream.println(String) : void
RETURN

public static main(String[]) : void
NEW Test
INVOKESPECIAL Test.<init>() : void
RETURN
}

we can see LDC "3" is in the "clinit" , this is a class initializer .

The lifetime of a object usually is : loading class -> linking class -> class initialization -> object instantiation -> use -> GC . That's why 3 appears first. And as this is in the class level , not object level , it will appear once as class type will be loaded once . For details , referencing to inside the Java2 Virtual Machine : life time of a type

LDC "2" and `LDC "1" is in "init" , the constructor.

Reason why it's in this order is : Constructor will first execute some implict instruction such as super constructor and code in the {} of a class , then execute code which's in their construtor explicit.

That's what a compiler will do to the java file.

Cruiserweight answered 18/11, 2011 at 18:2 Comment(0)
U
4

Complete Explanation

The order of execution is like,

  1. static block
  2. instance block
  3. constructor

Explanation

Static block will always be called only once in the very beginning whenever the class is accessed by any means, in your case which is when you run the program. (That is what static block is meant for). It does not depend on instances therefore not called again when new instances are created.

Then the Instance initialization block will be called for each instance created and after that the constructor for each instance created. Because both of them can be used to instantiate the instance.

Is instance initialization block actually called before constructor?

After compilation the code will become,

public class Test {

  Test(){
    super();
    System.out.println("2");
    System.out.println("1");
  }


  static {
    System.out.println("3");
  }

  public static void main(String args[]) {
    new Test();
  }
}

So you can see, the statement written in instance block itself becomes part of the constructor. Therefore it is executed before the statements already written in the constructor.

From this documentation

The Java compiler copies initializer blocks into every constructor. Therefore, this approach can be used to share a block of code between multiple constructors.

Urticaceous answered 21/11, 2011 at 13:19 Comment(0)
M
4

It doesn't look like anyone stated why the 3 is only printed once explicitly. So I would add that this is related to why it is printed first.

Statically defined code is flagged as being separate from any particular instance of the class. In general, statically defined code can be considered to not be any class at all (of course there's some invalidity in that statement when scoping is considered). Thus that code gets run once the class is loaded, as stated above, as in, it isn't being called when an instance is constructed Test(), thus calling the constructor multiple times will not result in the static code being run anymore.

The bracketed code containing the 2 gets prepended to the construct, as started above, because it is sort of a precondition to all of the constructors in the class. You don't know what will happen in the constructors for Test, but you are guaranteed that they all start by printing 2. Thus this happens before anything in any specific constructor, and is called every time a(ny) constructor is called.

Midsection answered 22/11, 2011 at 17:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.