在使用继承时,静态块和初始化块以什么顺序执行?

时间:2013-10-24 08:56:08

标签: java inheritance constructor static-block

我有两个班级父母和孩子

public class Parent {    
    public Parent() {
        System.out.println("Parent Constructor");
    }    
    static {
        System.out.println("Parent static block");    
    }    
    {
        System.out.println("Parent initialisation  block");
    }
}

public class Child extends Parent {    
    {
        System.out.println("Child initialisation block");
    }
    static {
        System.out.println("Child static block");
    }

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

上述代码的输出将是

Parent static block
Child static block
Parent initialization  block
Parent Constructor
Child initialization block
Child Constructor

为什么Java按该顺序执行代码?确定执行顺序的规则是什么?

11 个答案:

答案 0 :(得分:49)

有几个规则在起作用

  • 静态块总是在创建对象之前运行,这就是为什么你看到来自父节点和子静态块的打印消息的原因
  • 现在,当您调用子类(子)的构造函数时,此构造函数在执行它自己的构造函数之前隐式调用super();。初始化块甚至在构造函数调用之前就会发挥作用,因此这就是它首先被调用的原因。所以现在创建了父级,程序可以继续创建将经历相同过程的子类。
  

<强>说明:

     
      
  1. 首先执行父块的静态块,因为它首先加载,并且在加载类时调用静态块。
  2.   

答案 1 :(得分:42)

我在视觉上学习,所以这里是一个顺序的直观表示,作为SSCCE

public class Example {

  static {
    step(1);
  }

  public static int step_1 = step(2);
  public int step_6 = step(6);

  public Example() {
    step(8);
  }

  {
    step(7);
  }

  // Just for demonstration purposes:
  public static int step(int step) {
    System.out.println("Step " + step);
    return step;
  }
}

public class ExampleSubclass extends Example {

  {
    step(9);
  }

  public static int step_3 = step(3);
  public int step_10 = step(10);

  static {
    step(4);
  }

  public ExampleSubclass() {
    step(11);
  }

  public static void main(String[] args) {
    step(5);
    new ExampleSubclass();
    step(12);
  }
}

打印:

Step 1
Step 2
Step 3
Step 4
Step 5
Step 6
Step 7
Step 8
Step 9
Step 10
Step 11
Step 12

请记住static部分的顺序很重要;回顾Example的{​​{1}}内容与static的顺序之间的差异。

另请注意,无论顺序如何,实例初始化块始终在构造函数之前执行。但是,顺序在初始化块和字段初始化程序之间确实很重要。

答案 2 :(得分:10)

首先运行子类(注释extend子句)以查看简单流程。

秒 - 转到Static block vs. initializer block in Java?&amp;阅读那里接受的答案。

编辑:

  1. 以SIC方式执行 - 静态,(非静态)初始化器&amp;构造
  2. (非静态)初始化程序被复制到每个构造函数中 - 在TOP! (因此第3/4/5/6行)
  3. 在初始化类之前,必须初始化其直接超类 - http://docs.oracle.com/javase/specs/jls/se7/html/jls-12.html#jls-12.4(因此首先显示父静态块)。

答案 3 :(得分:5)

java中的静态块在main方法之前执行。如果我们在java类中声明一个静态块,它将在类加载时执行。这是使用静态变量初始化的。它主要用于JDBC。每次加载类时都会执行java中的静态块。这也称为静态初始化块。 java中的静态块在类加载到内存时初始化,这意味着当JVM读取字节码时。初始化可以是任何东西;它可以是变量初始化或该类的所有对象应该共享的任何其他内容。静态块是用大括号{}括起来的普通代码块,前面是静态关键字。

首先执行静态块。

实例初始化块:每次创建类的实例时运行。

所以当创建类的实例时执行下一个初始化块。

然后执行构造函数

答案 4 :(得分:5)

  • 静态初始化块在加载类时执行。
  • 在类层次结构中,静态初始化块的执行顺序将从顶级类开始。
  • 在一个类中,执行静态块的顺序是从上到下。
  • 以上规则适用,而不管静态块在类中的什么位置。

(在您的代码中,将首先执行父静态块,然后再执行子类静态块。)

  • 实例初始化块将在调用super()之后执行;在构造函数中。
    • 始终为super();是默认构造函数中的第一条语句。

在代码中创建子对象时:

  • 将执行Child类的默认构造函数。
  • 它将调用super();构造函数。
  • 然后执行超类构造函数。
  • Parent类将执行其super();呼叫。
  • 之后,执行Parent类中的实例初始化块。(从上到下)。
  • 然后执行构造函数中的代码(如果有)。
  • 然后它将返回Child类并执行Child类实例的init块。
  • 最后,执行子构造函数中的代码(如果存在)。

答案 5 :(得分:3)

通过一步一步的debuger来结束对象构建过程将非常有帮助,其中有一个视图,您可以在其中查看对象如何在阶段中进行操作。我发现这对于从更高的角度清除视角非常有用。 Eclipse可以通过它的调试器步骤来帮助您实现这一功能。

答案 6 :(得分:3)

只是想分享我的发现。 我在另一个线程中的一个答案中读到静态块首先在静态字段之前执行,这是不正确的。这取决于哪个是第一个,静态字段或静态块。看看下面的代码。它会试图把事情放在眼里。

  1. JVM查找具有public static void main(String args [])的类,以便它可以加载该类。
  2. 然后初始化此类的静态字段(如果它们出现在静态块之前)。这些字段可以调用此类或其他类的静态方法。如果他们调用此类的静态方法,那么该方法将被提供。如果他们调用另一个类的静态方法,那么该类的静态字段或块(取决于哪个首先)首先被初始化,然后提供此方法调用。
  3. 然后,它移动到静态块。
  4. 回到主要方法。

    class TestLab {
    static int method(String a) {
        System.out.println("in static method of TestLab" + " Coming from " + a);
        System.out.println("b is " + b);
        return 6;
    }
    
    static int a = method("Line 11");
    static int b = 7;
    
    TestLab() {
        System.out.println("Inside test lab constructor");
    }
    
    static {
        System.out.println("In static block of TestLab");
    }
    
    }
    
    public class Test1 {
    public static void main(String[] args) {
        System.out.println("inside main method of Test 1");
        int a = TestLab.method("Line 26");
    }
    
    // static Test ref=new Test();
    Test1() {
        System.out.println("Default Constructor of Test1");
    }
    
    {
        System.out.println("In instance block of Test1");
    }
    static int d = TestLab.method("Line 37");
    static int e = methodOfTest1();
    static {
        System.out.println("In Static Block of Test1");
    }
    
    static int methodOfTest1() {
        System.out.println("inside static method:mehtodOfTest1()");
        return 3;
    }
    }
    
  5. 这是输出:

    in static method of TestLab Coming from Line 11
    b is 0
    In static block of TestLab
    in static method of TestLab Coming from Line 37
    b is 7
    inside static method:mehtodOfTest1()
    In Static Block of Test1
    inside main method of Test 1
    in static method of TestLab Coming from Line 26
    b is 7
    

答案 7 :(得分:3)

这是我在准备认证时发现的。

当我们运行一个类时,首先发生静态块/静态变量初始化。如果有多个静态块,它将按照它出现的顺序执行它,

然后它将执行init blocks / instance variable initialisation。如果存在多个init块/变量初始化,它将按照它出现的顺序执行它,

之后它会查看构造函数。

答案 8 :(得分:1)

控制流程是 -

静态阻止 - &gt;初始化块 - &gt;最后是构造函数。

静态块 - &gt;当控件进入类时,此静态块将仅执行 。(JVM加载此类)

初始化块 - &gt;只要为类 创建一个新对象,就会执行此初始化块(它将从构造函数的第二个语句执行,然后执行构造函数语句 - 记住构造函数的第一个语句将是Super()/ this ())

构造函数 - &gt;每当创建一个新对象时都会得到它。

答案 9 :(得分:0)

将类加载到JVM中时会执行静态块。当init块被复制到构造函数中时,它将创建对象并在创建对象之前运行。

答案 10 :(得分:0)

1。静态初始化块仅在类加载时执行。 2.Init块每次在创建类的对象之前执行。

链接:-https://www.youtube.com/watch?v=6qG3JE0FbgA&t=2s