In what order do static/instance initializer blocks in Java run?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2007666/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 02:25:14  来源:igfitidea点击:

In what order do static/instance initializer blocks in Java run?

javastatic-initializer

提问by Pops

Say a project contains several classes, each of which has a static initializer block. In what order do those blocks run? I know that within a class, such blocks are run in the order they appear in the code. I've read that it's the same across classes, but some sample code I wrote disagrees with that. I used this code:

Say a project contains several classes, each of which has a static initializer block. In what order do those blocks run? I know that within a class, such blocks are run in the order they appear in the code. I've read that it's the same across classes, but some sample code I wrote disagrees with that. I used this code:

package pkg;

public class LoadTest {
    public static void main(String[] args) {
        System.out.println("START");
        new Child();
        System.out.println("END");
    }
}

class Parent extends Grandparent {
    // Instance init block
    {
        System.out.println("instance - parent");
    }

    // Constructor
    public Parent() {
        System.out.println("constructor - parent");
    }

    // Static init block
    static {
        System.out.println("static - parent");
    }
}

class Grandparent {
    // Static init block
    static {
        System.out.println("static - grandparent");
    }

    // Instance init block
    {
        System.out.println("instance - grandparent");
    }

    // Constructor
    public Grandparent() {
        System.out.println("constructor - grandparent");
    }
}

class Child extends Parent {
    // Constructor
    public Child() {
        System.out.println("constructor - child");
    }

    // Static init block
    static {
        System.out.println("static - child");
    }

    // Instance init block
    {
        System.out.println("instance - child");
    }
}

and got this output:

and got this output:

START
static - grandparent
static - parent
static - child
instance - grandparent
constructor - grandparent
instance - parent
constructor - parent
instance - child
constructor - child
END

START
static - grandparent
static - parent
static - child
instance - grandparent
constructor - grandparent
instance - parent
constructor - parent
instance - child
constructor - child
END

The obvious answer from that is that parents' blocks run before their children's, but that could just be a coincidence and doesn't help if two classes aren't in the same hierarchy.

The obvious answer from that is that parents' blocks run before their children's, but that could just be a coincidence and doesn't help if two classes aren't in the same hierarchy.

EDIT:

EDIT:

I modified my example code by appending this to LoadTest.java:

I modified my example code by appending this to LoadTest.java:

class IAmAClassThatIsNeverUsed {
    // Constructor
    public IAmAClassThatIsNeverUsed() {
        System.out.println("constructor - IAACTINU");
    }

    // Instance init block
    {
        System.out.println("instance - IAACTINU");
    }

    // Static init block
    static {
        System.out.println("static - IAACTINU");
    }
}

As implied by the class name, I never referenced the new class anywhere. The new program produced the same output as the old one.

As implied by the class name, I never referenced the new class anywhere. The new program produced the same output as the old one.

采纳答案by Chris Jester-Young

The static initializer for a class gets run when the class is first accessed, either to create an instance, or to access a static method or field.

The static initializer for a class gets run when the class is first accessed, either to create an instance, or to access a static method or field.

So, for multiple classes, this totally depends on the code that's run to cause those classes to get loaded.

So, for multiple classes, this totally depends on the code that's run to cause those classes to get loaded.

回答by Keith Randall

See section 12.4 and 12.5 of the JLS version 8, they go into gory detail about all of this (12.4 for static and 12.5 for instance variables).

See section 12.4 and 12.5 of the JLS version 8, they go into gory detail about all of this (12.4 for static and 12.5 for instance variables).

For static initialization (section 12.4):

For static initialization (section 12.4):

A class or interface type T will be initialized immediately before the first occurrence of any one of the following:

A class or interface type T will be initialized immediately before the first occurrence of any one of the following:

  • T is a class and an instance of T is created.
  • T is a class and a static method declared by T is invoked.
  • A static field declared by T is assigned.
  • A static field declared by T is used and the field is not a constant variable (§4.12.4).
  • T is a top level class (§7.6), and an assert statement (§14.10) lexically nested within T (§8.1.3) is executed.
  • T is a class and an instance of T is created.
  • T is a class and a static method declared by T is invoked.
  • A static field declared by T is assigned.
  • A static field declared by T is used and the field is not a constant variable (§4.12.4).
  • T is a top level class (§7.6), and an assert statement (§14.10) lexically nested within T (§8.1.3) is executed.

(and several weasel-word clauses)

(and several weasel-word clauses)

回答by Pops

Keith's and Chris's answers are both great, I'm just adding some more detail for my specific question.

Keith's and Chris's answers are both great, I'm just adding some more detail for my specific question.

Static init blocks run in the order in which their classes are initialized.So, what order is that? Per JLS 12.4.1:

Static init blocks run in the order in which their classes are initialized.So, what order is that? Per JLS 12.4.1:

A class or interface type T will be initialized immediately before the first occurrence of any one of the following:

  • T is a class and an instance of T is created.
  • T is a class and a static method declared by T is invoked.
  • A static field declared by T is assigned.
  • A static field declared by T is used and the field is not a constant variable (§4.12.4).
  • T is a top-level class, and an assert statement (§14.10) lexically nested within T is executed.

Invocation of certain reflective methods in class Class and in package java.lang.reflect also causes class or interface initialization. A class or interface will not be initialized under any other circumstance.

A class or interface type T will be initialized immediately before the first occurrence of any one of the following:

  • T is a class and an instance of T is created.
  • T is a class and a static method declared by T is invoked.
  • A static field declared by T is assigned.
  • A static field declared by T is used and the field is not a constant variable (§4.12.4).
  • T is a top-level class, and an assert statement (§14.10) lexically nested within T is executed.

Invocation of certain reflective methods in class Class and in package java.lang.reflect also causes class or interface initialization. A class or interface will not be initialized under any other circumstance.

To illustrate, here's a walkthrough of what's happening in the example:

To illustrate, here's a walkthrough of what's happening in the example:

  1. Enter main
  2. Print "START"
  3. Attempt to create first instance of Child, which requires initialization of Child
  4. Attempting to initialize Child causes initialization of Parent
  5. Attempting to initialize Parent causes initialization of Grandparent
  6. At the start of initialization of Grandparent, Grandparent's static initialization block is run
  7. Technically, Object gets the last say in the initialization chain by virtue of being Grandparent's parent, but it has nothing to contribute
  8. After Grandparent's static initialization block ends, program falls back to Parent's static initialization block
  9. After Parent's static initialization block ends, program falls back to Child's static initialization block
  10. At this point, Child is initialized, so its constructor may proceed
  11. Since IAmAClassThatIsNeverUsed never gets referenced, none of its code ever runs, including static initializer blocks
  12. The rest of this walkthrough doesn't concern static initializers and is included only for completeness
  13. Child's constructor implicitly calls super() (i.e., Parent's constructor)
  14. Parent's constructor implicitly calls super() (i.e., Grandparent's constructor)
  15. Grandparent's constructor does the same, which has no effect (again, Object has nothing to contribute)
  16. Immediately after Grandparent's constructor's call to super() comes Grandparent's instance initializer block
  17. The rest of Grandparent's constructor's constructor runs and the constructor terminates
  18. The program falls back to Parent's constructor, immediately after its call to super() (i.e., Grandparent's constructor) resolves
  19. As above, Parent's instance initializer does its thing and its constructor finishes up
  20. Similarly, the program returns to and completes Child's constructor
  21. At this point, the object has been instantiated
  22. Print "END"
  23. Terminate normally
  1. Enter main
  2. Print "START"
  3. Attempt to create first instance of Child, which requires initialization of Child
  4. Attempting to initialize Child causes initialization of Parent
  5. Attempting to initialize Parent causes initialization of Grandparent
  6. At the start of initialization of Grandparent, Grandparent's static initialization block is run
  7. Technically, Object gets the last say in the initialization chain by virtue of being Grandparent's parent, but it has nothing to contribute
  8. After Grandparent's static initialization block ends, program falls back to Parent's static initialization block
  9. After Parent's static initialization block ends, program falls back to Child's static initialization block
  10. At this point, Child is initialized, so its constructor may proceed
  11. Since IAmAClassThatIsNeverUsed never gets referenced, none of its code ever runs, including static initializer blocks
  12. The rest of this walkthrough doesn't concern static initializers and is included only for completeness
  13. Child's constructor implicitly calls super() (i.e., Parent's constructor)
  14. Parent's constructor implicitly calls super() (i.e., Grandparent's constructor)
  15. Grandparent's constructor does the same, which has no effect (again, Object has nothing to contribute)
  16. Immediately after Grandparent's constructor's call to super() comes Grandparent's instance initializer block
  17. The rest of Grandparent's constructor's constructor runs and the constructor terminates
  18. The program falls back to Parent's constructor, immediately after its call to super() (i.e., Grandparent's constructor) resolves
  19. As above, Parent's instance initializer does its thing and its constructor finishes up
  20. Similarly, the program returns to and completes Child's constructor
  21. At this point, the object has been instantiated
  22. Print "END"
  23. Terminate normally

回答by Martin Tapp

You can have multiple static and instance initializers in the same class, therefore

You can have multiple static and instance initializers in the same class, therefore

  • Static initializers are called in the textual order they are declared (from 12.4.2)
  • Instance initializers are called in the textual order they are declared (from 12.5)
  • Static initializers are called in the textual order they are declared (from 12.4.2)
  • Instance initializers are called in the textual order they are declared (from 12.5)

Each is executed as if it was a single block.

Each is executed as if it was a single block.

回答by Bala

Initialization of a class consists of executing its static initializers and the initializers for static fields (class variables) declared in the class.

Initialization of a class consists of executing its static initializers and the initializers for static fields (class variables) declared in the class.

Initialization of an interface consists of executing the initializers for fields (constants) declared in the interface.

Initialization of an interface consists of executing the initializers for fields (constants) declared in the interface.

Before a class is initialized, its direct superclass must be initialized, but interfaces implemented by the class are not initialized. Similarly, the superinterfaces of an interface are not initialized before the interface is initialized.

Before a class is initialized, its direct superclass must be initialized, but interfaces implemented by the class are not initialized. Similarly, the superinterfaces of an interface are not initialized before the interface is initialized.

回答by Avinash Perla

http://docs.oracle.com/javase/tutorial/java/javaOO/initial.html

http://docs.oracle.com/javase/tutorial/java/javaOO/initial.html

kindly check java documentation.

kindly check java documentation.

then clearly mentioned no matter how may static blocks are there they will be executed as a single block in the order they appear

then clearly mentioned no matter how may static blocks are there they will be executed as a single block in the order they appear

So,

So,

My understanding here is java is looking your code as

My understanding here is java is looking your code as

static{
i=1;
i=2;
}

static int i;

static int i;

that is why you are getting output 2

that is why you are getting output 2

hope this is helpful

hope this is helpful

回答by Java Main

There is one case in which a static block will not be called.

There is one case in which a static block will not be called.

class Super {
    public static int i=10;
}
class Sub extends Super {
    static {
        system.out.println("Static block called");
    }
}
class Test {
    public static void main (String [] args) {
        system.out.println(Sub.i);
    } 
}

The above code outputs 10

The above code outputs 10



Update from an "editor"

Update from an "editor"

The technical explanation for this is in JLS 12.4.1

The technical explanation for this is in JLS 12.4.1

"A reference to a static field (§8.3.1.1) causes initialization of only the class or interface that actually declares it, even though it might be referred to through the name of a subclass, a subinterface, or a class that implements an interface."

"A reference to a static field (§8.3.1.1) causes initialization of only the class or interface that actually declares it, even though it might be referred to through the name of a subclass, a subinterface, or a class that implements an interface."

The intuitive explanation is Super.iand Sub.iare actually the same variable, and nothing in Subactually needs to be initialized for the Super.ito get the correct value.

The intuitive explanation is Super.iand Sub.iare actually the same variable, and nothing in Subactually needs to be initialized for the Super.ito get the correct value.

(It would be different if the initialization expression for Super.ireferred to the Subclass. But then you would have a cycle in the initialization order. A careful reading of JLS 12.4.1and JLS 12.4.2explains that this is allowed, and allows you to work out exactly what would happen in practice.)

(It would be different if the initialization expression for Super.ireferred to the Subclass. But then you would have a cycle in the initialization order. A careful reading of JLS 12.4.1and JLS 12.4.2explains that this is allowed, and allows you to work out exactly what would happen in practice.)

回答by GraceMeng

class A {
  public A() { 
    // 2
  }
}

class B extends A{
  static char x = 'x'; // 0
  char y = 'y'; // 3
  public B() { 
    // 4
  }

  public static void main(String[] args) {
    new B(); // 1
  }
}

Numbers in the comment indicate the evaluation order, the smaller, the earlier.

Numbers in the comment indicate the evaluation order, the smaller, the earlier.

As the example showed,

As the example showed,

  1. static variable
  2. main
  3. constructor of superclass
  4. instance variable
  5. constructor
  1. static variable
  2. main
  3. constructor of superclass
  4. instance variable
  5. constructor