你能分析一下关于继承的 JAVA 代码的输出吗

Could you please analyze the output of that JAVA code about inheritance

我已经在代码的注释中添加了我的问题。

class Parent{
    int num =9; //I think num in Parent class is overrided by the num in Child class. why is the num in the first line of output is still 9?
    { //code block
        System.out.println("Parent constructor code..."+num);
    }

    Parent(){
        System.out.println("Parent constructor run"); 
        show(); //why does this method here invoke the show() method in Child class?
    }

    void show() {
        System.out.println("Parent show..."+num);
    }
}

class Child extends Parent{
    int num = 8; 
    {
        System.out.println("Child constructor code..."+num);
        num = 10;
    }

    Child(){ 
        System.out.println("Child constructor run"); 
        show(); 
    }

    void show() {
        System.out.println("Child show..."+num);
    }
}

public class Test {

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

}

输出是:

Parent constructor code...9
Parent constructor run
Child show...0
Child constructor code...8
Child constructor run
Child show...10

谢谢大家!我发现这是一个可变的阴影和隐藏问题。

我认为这是因为你的构造函数会自动调用超级 class 构造函数。 (对于我们的第一个问题。)尽管如此,你重写了 show 所以当它遇到这个方法时,它调用子方法

当 java 创建 child class、it has to call super() to initialize the parent class - 这样它就可以在超级 class 或其他活动中实例化私有字段. (这不会创建 parent class 的 object。)这就是您看到 Parent constructor code...9 的原因 - 它正在调用 parent 代码,并打印 parent的num

因为你创建了一个childclass,child的show()在parent构造函数中被调用。这就是 it's dangerous to call non-final methods in a constructor 的原因 - 如果 child 覆盖它们,则会调用 child 的方法。

child 的 num 为 0,因为 Java initializes member variables to default values,而您的代码还没有机会将其设置为 10。

至于您的 child 代码,the num is not being overridden, it is being hidden - 只能覆盖方法。这就是为什么 child 的 show() 在正确初始化后将其显示为 10 的原因。如果你想访问 parent 的变量,你可以用 super.num 来实现,但这通常被认为是不好的做法,因为它会引起混淆。

object构造顺序为:

  1. 变量声明和初始化
  2. 实例构造函数块
  3. 构造函数

如果 class 有一个 parent class,在 parent 实际 [=82] 之前执行相同的顺序=].

parent先

int num = 9

先求值,num设置为9(parent的1)

Parent constructor code...9

实例初始化程序块在构造函数之前执行(parent 的 2.)

Parent constructor run

调用构造函数(parent的3.)

Child show...0

Parent 的构造函数调用 show()show() 被覆盖,因此 Child 被调用。

Child 的 1. 和 2. 还没有被调用,因此 Child 中的覆盖 num 仍然是 0. *1

然后child

int num = 8

Child的1.被评价

Child constructor code...8

Child的2。num在此之后设置为10。

Child constructor run

Child 的 3.

Child show...10

Child 的构造函数调用 show().

*1:

这就是为什么在构造函数中调用非 final 方法非常危险的原因。方法往往依赖于被初始化的成员变量;他们现在还没有。

如果这是一个 non-primitive 变量,如果您的方法试图访问它,您很可能 运行 进入 NullPointerException