Java- 为什么会打印出 null?

5
public class Base {
public Base() {
    x = 0;
    bar();
}

public Base(int x) {
    this.x = x;
    foo();
}

public void foo() {
    System.out.println("Base.foo : " + x);
}

private void bar() {
    System.out.println("Base.bar:" + x.toString());
}

protected Integer x;
}

    public class Derived extends Base {
       public Derived() {
       bar();
       }
       public Derived(int x, int y) {
         super(x);
         this.y = y;
       }
       public void foo() {
         System.out.println("Derived.foo : " + x + ", " + y);
       }
       public void bar() {
         System.out.println("Derived.bar:" + x.toString() + ", " + y.toString());
       }
       private Integer y;


       public static void main(String[] args) {
        Base b = new Derived(10, 20);
      }
}

为什么输出的是 "Derived.foo:10, null" 而不是 20,因为变量 y 是 Derived 的私有变量,被初始化为 20,且在它的作用域内,那么为什么它是 null 呢?
8个回答

7

因为先调用超级构造函数(super(x)),这个超级构造函数会调用方法foo。然后Derived构造函数初始化y为20(this.y = y)。所以当调用foo时,y还没有被初始化。

在构造函数中调用可重写的方法是一种不好的实践,因为正如你刚才注意到的那样,它可能会在部分构造的对象上调用已经被重写的方法。


2
+1,特别是对于不良实践的警告:它可能会在部分构建的对象上调用重写方法。 - Fabian Barney

2
它这样做是因为父类(Base)构造函数在设置y成员变量之前调用了Derived.foo()
因此,以下是基本的操作顺序:
main(...)
Derived(10,20) (start constructor)
Base(10) (start constructor)
this.x = x
foo() (calls Derived.foo() which prints the message you see)

然后在此之后。
this.y = y

2
println 来自于方法 foo,该方法被从 Base 的构造函数调用,而该构造函数又被从 Derived 的构造函数(通过 super)调用,在你初始化 y 之前。因此,null 值是预期的。

2
如果你遵循构造函数的调用,就会更清晰:
  1. 调用Derived(int x, int y)构造函数
  2. 调用超类构造函数Base(int x)
  3. 设置x变量
  4. 调用重写的foo()方法
  5. 执行println()
  6. 然后设置y变量
如你所见,当你尝试打印值时,y变量被设置。这就是你看到未初始化值null的原因。
从构造函数调用可重写方法是一个常见的错误,因为它可以在对象完全构建之前使未初始化的变量逃逸。

1

当你进入超类的构造函数时,y 还没有被实例化。因此对 foo() 的调用将会有一个空的 y


1

这是由超类构造函数调用触发的Derived.foo()打印,此时它还未被初始化为20。因此,在打印时它仍然为null。


1
所有的答案都是正确的,但下次你可以在打印某些东西的函数中设置断点。 然后你可以简单地检查调用栈并通过阅读被调用的部分来跟踪代码。
这样你就可以追踪到 y 没有被初始化的问题了。
祝好运! Roel

1

因为在Base类构造函数中调用foo()时,y尚未初始化。

调用链为 main -> Derived(x,y) -> Base(x) -> 初始化x,foo()。但是,由于您是从Derived内部开始调用的,它覆盖了foo(),因此解释器实际上会执行Derived的foo()。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接