When will a static block be executed in JAVA when creating an object?

class DemoClass { public static void main(String args[]) { System.out.println("Start"); A a=new D(); } } class A { static { System.out.println("Static A"); A c=new C(); } public A() { System.out.println("Constr A"); } } class B extends A { static { System.out.println("Static B"); } public B() { System.out.println("Constr B"); } } class C extends B { static { System.out.println("Static C"); } public C() { System.out.println("Constr C"); } } class D extends C { static { System.out.println("Static D"); } public D() { System.out.println("Constr D"); } } 

The order of execution for the above code:

 Start Static A Constr A Constr B Constr C Static B Static C Static D Constr A Constr B Constr C Constr D 

In my opinion, all static blocks should be executed first, then only the object will be created. But here, first, an object β€œA c = new C ()” is created in the static block of class A, and then other static blocks are executed. Why?

+6
source share
3 answers

The static initializer of all classes started to execute, but to initialize D, C needs to be initialized, so B must be initialized, so A must be initialized. At that moment when the code is executed in the static initializer in A , all the classes involved are in the "initialized" state.

In the static initializer A it creates an instance of C - but C already initializing, so the initializer does not start again ... The JVM just notes that it is already initialized (within the same thread) and continues.

Details on all this in JLS 12.4.2 . In particular, the bullet:

If the Class object for C indicates that initialization is being performed for C by the current thread, this should be a recursive request for initialization. Release LC and finish normally.

and

Further, if C is a class, not an interface, and its superclass has not yet been initialized, then let SC be its superclass and let SI1, ..., SIn be all C superinterfaces that declare at least one default method. [...]

For each S in the list [SC, SI1, ..., SIn], recursively perform this entire procedure for S. If necessary, first check and prepare S.

... relevant.

+13
source

@JonSkeet said everything in technical terms, and I can’t say more. Let me try to explain with an analogy:

Think of static initialization opening the door of a room and executing a constructor, like doing / decorating things in this room.

Now, to open the door of room D, you need to open the door of C, for C you need B, and for B you need A. Now you are in room A, and you have finished doors that open the formalities in room A. And at the end formal door openings in room A you see a note that completes the operation of room C ( A c=new C(); ). Now, since room C and its dependent rooms are already open, you do not need to open it again (which means not initializing a static block). But before you enter Room C, you will end the room. Opening System.out.println("Static A"); , that is, System.out.println("Static A"); So, on the console, you have:

Static A

Now you are in room C, and you need to finish this room, but before that you finish B and A due to dependency (C extends B and B continues A). So in the console you have:

Constr A Constr B Constr C

Now you will return to room A again and see that the formalities for opening the door are completed. So, you will get into room B, then C, and then D. So, in the console you:

Static B Static C Static D

Now you finish the work of room D ( A a=new D(); ), and for this you need to finish the work of C, B and C because of the dependency (D extends C, C continues B and B continues A). So in the console you have:

Constr A Constr B Constr C Constr D

+5
source

when jvm starts at this time, the entire static member will be scanned and memory will be allocated for them, then it will not become static.

so first it will print static, not static

-2
source

All Articles