【问题标题】:Why the following result is the output? Are class fields don't get initalized before the constructor?为什么下面的结果是输出?类字段在构造函数之前没有被初始化吗?
【发布时间】:2021-09-21 19:24:49
【问题描述】:

我想了解为什么会出现以下代码的结果:

public class Base {
    private int member1 = 1;
    private int member2 = 2;

    public Base() {
        System.out.println("base ctor");
        print();
    }

    public void print() {
        System.out.println(member1 + "" + member2);
    }
}

class Derived extends Base {
    private int member3 = 3;
    private int member4 = 4;

    public Derived() {
        System.out.println("derived ctor");
        print();
    }

    public void print() {
        System.out.println(member3 + "" + member4);
    }
}

class Test{
    public static void main(String[] args) {
        Derived d = new Derived();
    }
}

是:

base ctor
00
derived ctor
34
  • 派生类的构造函数隐式调用它的父类

  • 构造函数。 super 的(基类)构造函数打印“base ctor”

super 的构造函数调用print() - 打印member 1 , member 2 我认为 member1 和 member2 已经初始化,因为我认为我知道,当我们创建一个对象时,事物的顺序是 静态字段和块先行(如果它是类的第一次加载) 然后实例事物(如字段和成员)按顺序排列,这意味着按代码顺序排列。

这里 - 字段在构造函数之前,这意味着它应该运行并且在它到达打印之前已经初始化了 member1 和 member2。

为什么打印0 0

它甚至会打印到Base 还是打印到Derived?因为它是从Base 的构造函数中调用的,所以我不明白。

谢谢。

【问题讨论】:

    标签: java inheritance constructor initialization overriding


    【解决方案1】:

    您在Derived 中调用了print 方法两次——一次在Base 构造函数期间,一次在Derived 构造函数期间。那是因为Derived.print() 覆盖了Base.print()

    所以这个期望:

    super 的构造函数调用 print() - 打印 member 1 , member 2

    ... 不正确。它在Derived 中调用print() 实现,它打印member3member4。那些还没有被初始化。

    执行顺序为:

    • 基类字段初始化器
    • 基类构造函数体
    • 派生类字段初始值设定项
    • 派生类构造函数体

    如果您只是将您的两个 print 方法更改为 print1print2(并适当地更改调用代码)然后它会打印:

    base ctor
    12
    derived ctor
    34
    

    ...如你所料。

    【讨论】:

    • 问题是为什么,为什么Base 构造函数中的print() 调用实际上运行print(),它在Derived 类中?我知道该对象是new Derived,但这是否意味着即使来自超级构造函数的调用也会到达 Derived 实现?
    • 因为您已经覆盖了 Derived 类中的 print 方法(与 Base 类中的方法签名相同)。如果您将@JonSkeet 建议的方法重命名为print1print2,则不会出现此类问题。
    • @NoobCoder:是的,使用的方法实现在对象的生命周期内不会改变。它从一开始就是一个Derived 对象,所以任何对print 的调用都会调用Derived.print,即使在Base 构造函数中也是如此。
    • @JonSkeet 不知道,谢谢。如果我们将对象声明为Base obj = new Derived 并在基本构造函数中调用print() 会怎样?我觉得如果我们在 X 类 constructor 中调用 print() (我认为这是“神圣的”,因为这实际上是创建对象),那么实际的 print() 将被执行是其他的。
    • @NoobCoder:你自己测试会很容易——但不,你分配的变量的类型没有区别。负责确定使用哪种方法实现的对象类型在其整个生命周期内保持不变。
    猜你喜欢
    • 2015-02-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-15
    相关资源
    最近更新 更多