1

我找到了这个例子,我想了解它背后的逻辑?构造函数和静态块以及初始化块如何在继承中工作?每个人在哪个阶段被调用?

public class Parent {

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

    {
        System.out.println("i am parent 2");
    }

    public Parent() {
        System.out.println("i am parent 1");
    }

}

public class Son extends Parent {

    static {System.out.println("i am son 3");}
    {System.out.println("i am son 2");}

    public Son() {
        System.out.println("i am son 1");
    }

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

输出是:

i am Parent 3
i am son 3
i am parent 2
i am parent 1
i am son 2
i am son 1
4

4 回答 4

13

你需要知道

  1. 构造函数中的第一条指令是调用其父类的构造函数,super(params)或者如果您想使用默认构造函数super()。在默认构造函数的情况下,您不必显式编写它。
  2. 初始化块中的代码在super(...)调用后立即移动到每个构造函数
  3. 静态块在初始化类时执行,这是在 JVM 完全加载(及其父类)后完成的。

所以类被编译成类似这样的类。

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

    public Parent() {
        super();
        {
            System.out.println("Parent initializer block");
        }
        System.out.println("Parent constructor");
    }

}

public class Son extends Parent {

    static {
        System.out.println("Son static block");
    }

    public Son() {
        super();
        {
            System.out.println("Son initializer block");
        }
        System.out.println("Son constructor");
    }

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

为了能够main从类 JVM 中执行方法,Son需要加载这个类(以及它扩展的类)的代码。类完全加载后,JVM初始化其静态内容,其中涉及执行静态块(是的,一个类中可以有多个静态块)。要完全加载Son类,JVM 需要了解其父类的详细信息,因此它将Parent在之前完全加载类,Son这意味着它还将在Son类中的静态块之前执行其静态块。

所以输出看起来像:

  • Parent static block
  • Son static block

现在在main方法中,您正在调用Son类构造函数new Son(),代码看起来像

super();
{
    System.out.println("Son initializer block");
}
System.out.println("Son constructor");

由于它super()引用Parent类构造函数,即

super();// this will invoke Object constructor since Parent 
        // doesn't extend anything (which means it extends Object class)
{
    System.out.println("Parent initializer block");
}
System.out.println("Parent constructor");

结果你会看到

  • Parent initializer block
  • Parent constructor

这个句柄Parent#constructor()执行,super()所以接下来你会看到来自 Son 构造函数的代码,之后super()将生成

  • Son initializer block
  • Son constructor

Son要查看甚至在您使用构造函数甚至方法之前加载类,main您可以在使用构造函数之前打印一些东西,Son例如

System.out.println("ABC                      // before new Son()");
new Son();

这将导致

Parent static block
Son static block
ABC                      // before new Son()
Parent initializer block
Parent constructor
Son initializer block
Son constructor
于 2014-02-01T23:25:56.920 回答
9

当类被 JVM 加载和初始化时,静态块被调用一次。实例初始化程序在构造类的实例时执行,就像构造函数一样。

Java 语言规范中描述了静态和实例初始化器

于 2014-02-01T22:57:09.230 回答
2

加载类时调用的静态块,并且类首先由 jvm 中的类加载器加载,因此首先执行它们

然后你创建对象,所以你的父初始化块被调用然后你的父构造函数由于java中的构造函数链接然后派生类初始化块然后派生类构造函数

于 2014-02-01T23:00:04.463 回答
1

静态块在类加载到 JVM 时执行,而构造函数块在创建实例时执行。

静态初始化器相当于静态上下文中的构造器。你肯定会比实例初始化器更频繁地看到它。

于 2014-02-01T22:58:37.957 回答