public class Main {
static class Father {
private int money = 1;
public Father() {
this.money = 2;
this.showMoney();
}
public void showMoney() {
System.out.println("I am father, I have $" + this.money + ".");
}
}
static class Son extends Father {
private int money = 3;
public Son() {
this.money = 4;
this.showMoney();
}
@Override
public void showMoney() {
System.out.println("I am son, I have $" + this.money + ".");
}
}
public static void main(String[] args) {
final Son son = new Son();
System.out.println("I am son, I have $" + son.money + ".");
}
}
输出结果
I am son, I have $0.
I am son, I have $4.
I am son, I have $4.
后面两行我都能理解,但是第一次输出时为什么 money 字段是 0 ?
谢谢
1
Hurriance 2021-07-28 09:11:04 +08:00 3
执行子类的初始化函数的时候,先会去执行父类的初始化函数,其中就会执行 showMoney(),其实父类、子类也有 showMoney(),但是因为你是子类调用栈过来的,所以直接调用子类的 showMoney(),但是此时子类的 money 还没初始化,默认值为 0,即输出 0
|
2
qping 2021-07-28 09:14:54 +08:00 4
先初始化父亲, 调用了 showMoney() , showMoney 方法被子类重写了, 调用的是儿子的 showMoney , 儿子的 money 还没赋值,所以是 0
|
3
zhangshine 2021-07-28 09:19:47 +08:00
搜索“Java 类的初始化顺序”
|
4
AlkTTT 2021-07-28 09:22:09 +08:00
你这两个类都是静态的,
执行顺序为: 父类构造方法 -> 父类 showMoney -> 子类重写了 showMoney,所以调用子类的 showMoney(此时子类的参数还没执行构造方法,money 为 0) |
5
dinghmcn 2021-07-28 09:28:26 +08:00
如果子类没有重写 showMoney()输出的是什么?
|
6
Aruforce 2021-07-28 09:32:03 +08:00
尽管 Son 和 Father 都有 money 。。但这是两个 money 。。。
第一个输出的 money 是在 Father 类初始化时尚未初始化的 Son 的 money... 而这个值应该是 0 虽然你直觉可能觉得是 3... 在 Father 的初始话代码执行的时候... 实际上 son 的 money=3 尚未执行。。所以默认值 0 |
7
NeroKamin 2021-07-28 09:34:08 +08:00
第一个 money 是执行 Father 构造方法时打印的 Son 类实例中的 money 字段,此时其值为初始零值
|
8
des 2021-07-28 09:44:21 +08:00 via iPhone
@Aruforce 这个确实是反直觉,除非说是分配成员变量空间和初始化赋值是分两步做的,而且可以被打断,是这样的吗?
|
9
admol 2021-07-28 10:09:05 +08:00
在父类的构造方法、showMoney 方法、子类的构造方法、showMoney 方法里面分别打上断点,可以观察到执行输出顺序;
|
10
songkaizong 2021-07-28 10:22:07 +08:00 3
这道题出自《深入理解 Java 虚拟机》 8.3 小节。
为了加深理解,笔者又编撰了一份“劣质面试题式”的代码片段,请阅读代码清单 8-10,思考运行后会输出什么结果。 输出两句都是“I am Son”,这是因为 Son 类在创建的时候,首先隐式调用了 Father 的构造函数,而 Father 构造函数中对 showMeTheMoney()的调用是一次虚方法调用,实际执行的版本是 Son::showMeTheMoney()方法,所以输出的是“I am Son”,这点经过前面的分析相信读者是没有疑问的 了。而这时候虽然父类的 money 字段已经被初始化成 2 了,但 Son::showMeTheMoney()方法中访问的却 是子类的 money 字段,这时候结果自然还是 0,因为它要到子类的构造函数执行时才会被初始化。 |
11
Cusmate 2021-07-28 14:34:05 +08:00 via Android
楼主所有发的帖子都是在问问题,而且挺频繁的。
|
12
Newyorkcity OP @Hurriance
@qping @songkaizong =2 的那个 this 是谁?是 Father 实例,那接下来那个 showMoney 的调用者也应该是 Father 实例,它却用了重写的函数?那为啥字段赋值的时候它不用重写的字段? |