你能分析一下关于继承的 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构造顺序为:
- 变量声明和初始化
- 实例构造函数块
- 构造函数
如果 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
。
我已经在代码的注释中添加了我的问题。
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构造顺序为:
- 变量声明和初始化
- 实例构造函数块
- 构造函数
如果 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
。