Java-为什么它打印 null?

发布于 2024-12-03 04:50:36 字数 940 浏览 0 评论 0原文

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, nulll 而不是 20 而不是 null? y 是 Derived 的私有变量,它被初始化为 20。它在它的范围内。那么为什么它是 null 呢?

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);
      }
}

Why does it print "Derived.foo:" 10, nulll and not 20 instead of the null?
y is a private variable of Derived, and it was initialized with 20. it's in its scope.. so why is it null?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

笑看君怀她人 2024-12-10 04:50:36

因为超级构造函数首先被调用(super(x))。这个超级构造函数调用方法 foo。然后 Derived 构造函数将 y 初始化为 20 (this.y = y)。因此,当调用 foo 时,y 尚未初始化。

在构造函数中调用可重写方法是一种不好的做法,因为正如您刚刚注意到的,它可以在部分构造的对象上调用重写方法。

Because the super constructor is first called (super(x)). This super constructor calls the method foo. Then the Derived constructor initializes y to 20 (this.y = y). So when foo is called, y is not initialized yet.

It's a bad practice to call overridable methods in constructors, because, as you just noticed, it can call overridden methods on partially constructed objects.

静若繁花 2024-12-10 04:50:36

println 来自方法 foo,该方法是从 Base 的构造函数调用的,而该构造函数是从 Derived 的构造函数调用的构造函数(通过 super初始化 y 之前。所以空值是预期的。

The println comes from method foo which is called from Base's constructor, which is called from Derived's constructor (via super) before you initialize y. So the null value is expected.

最单纯的乌龟 2024-12-10 04:50:36

这样做是因为超类 (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

It does that because the superclass (Base) constructor calls Derived.foo() before the y member variable has been set.

So here is the basic order of operations:

main(...)
Derived(10,20) (start constructor)
Base(10) (start constructor)
this.x = x
foo() (calls Derived.foo() which prints the message you see)

Then after that

this.y = y
巾帼英雄 2024-12-10 04:50:36

如果您跟踪构造函数的调用,就会更清楚:

  1. 调用 Derived(int x, int y) 构造函数
  2. 调用超级构造函数 Base(int x)
  3. 设置 < code>x 变量
  4. 调用重写的 foo() 方法
  5. 执行 println()
  6. Then 设置y 变量

As您可以看到,在您尝试打印出该值后,y 变量就被设置了。这就是为什么您会看到 null 的未初始化值。

从构造函数调用可重写的方法是一个常见的错误,因为它可能允许未初始化的变量在对象完全构造之前转义。

If you follow the calls from the constructor it makes it clearer:

  1. Calls the Derived(int x, int y) constructor
  2. Calls the super constructor Base(int x)
  3. Sets the x variable
  4. Calls the overridden foo() method
  5. Performs the println()
  6. Then sets the y variable

As you can see, the y variable is getting set after you try to print out the value. That is why you are seeing the uninitialized value of null.

Calling overridable methods from a constructor is a common mistake, as it can allow uninitialized variables to escape before the object is fully constructed.

偏爱自由 2024-12-10 04:50:36

当您进入超类的构造函数时,y 尚未实例化。因此,对 foo() 的调用将有一个 null y

When you get into the constructor of the super class y is not yet instantiated yet. So the call to foo() will have a null y.

只有一腔孤勇 2024-12-10 04:50:36

它由超级构造函数调用触发的 Derived.foo() 打印出来,然后用 20 进行初始化。所以在打印时它仍然为空。

It is printed by Derived.foo() triggered by Super-Constructor call before it is initialized with 20 afterwards. So while printing it is still null.

内心荒芜 2024-12-10 04:50:36

所有答案确实都是正确的,但下次您可以在打印某些内容的函数中放置一个断点。
然后,您可以简单地检查调用堆栈并通过阅读正在调用的部分来跟踪代码。

这样您就可以发现 y 不会被初始化。

祝你好运!
罗尔

All the answers are indeed correct but next time you can maybe put a breakpoint in the function where you are printing something.
Then you can simply examine the call stack and folow the code by reading the parts that are being called.

This way you could have traced that y would not be initialized.

Good luck!
Roel

素染倾城色 2024-12-10 04:50:36

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

链条消失了
主要->导出(x,y) ->基数(x) ->初始化 x, foo()。但是,因为您在 Derived 内部启动调用,该调用会覆盖 foo(),所以衍生的 foo() 实际上是由解释器执行的。

because y has not been initialised when foo() is called in the Base class constructor.

the chain goes
main -> Derived(x,y) -> Base(x) -> initialise x, foo(). However, because you're starting the call inside Derived, which overrides foo(), derived's foo() is actually executed by the interpreter.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文