public class test2 {
static class Father {
public int money = 1;
public Father() {
money = 2;
showMeTheMoney();
}
public void showMeTheMoney() {
System.out.println("I am Father, i have $" + money);
}
}
static class Son extends Father {
public int money = 3;
public Son() {
money = 4;
showMeTheMoney();
}
public void showMeTheMoney() {
System.out.println("I am Son, i have $" + money);
}
}
public static void main(String[] args) {
Father guy = new Son();
}
}
这段代码输出为
为什么会是这个输出,我希望大佬们能通过字节码指令的方式教教我。
这是我得到的main方法的字节码指令
《深入理解JAVA虚拟机 第三版》周志明著中写道invokevirtual是调用对象实例的方法,我很想知道在为什么他会调用Son的showMeTheMoney,他传的对象实例都是Son吗?
新的问题补充:
main方法被调用时创建了自己的栈帧,而Son的init方法和Father的init方法被调用时也都有自己栈帧,invokevirtual拿到的栈帧中操作数栈最顶端的对象实例,但是我查看它们的字节码反汇编版本,看到他们的局部变量槽最大数为1,那么也就是说只有this能上到操作数栈中,那么Son的实例是怎么在Father的init方法中被showMeTheMoney方法调用的。
要通过字节码指令的方式修改代码,可以使用 javassist 或 ASM 这样的字节码操作库。以下是使用 javassist 修改代码的示例:
补充
简化的字节码分析:
在 Father 的构造函数中,aload_0 将 this 引用加载到操作数栈顶,invokevirtual 使用这个引用来调用 showMeTheMoney() 方法。由于 this 实际上是 Son 的实例,因此调用的是 Son 的 showMeTheMoney() 方法。