java为什么JVM中相对于超类的字段和方法分辨率不同?
研究JVM内部,我对这个示例有点困惑,它的特点是子类中的重写方法和被隐藏的实例变量:
class CA extends Object {
public int ivar;
public void two() {
ivar = 20;
this.three();
}
public void three() {
System.out.println("three called in CA");
System.out.println(ivar);
}
}
class CB extends CA {
public int ivar;
public void one() {
ivar = 10;
two();
}
public void three() {
System.out.println("three called in CB");
System.out.println(ivar);
super.three();
}
public static void main(String[] args) {
CB cb = new CB();
cb.one();
}
}
这将产生以下输出:
three called in CB
10
three called in CA
20
方法调用完全是预期的,但我观察到实例变量的行为不同——当它在超类的实现中被设置和访问时,它正在访问“shadowd”值
在JVM规范第5.4.3.2节和第5.4.3.3节(分别是字段和方法)中,我似乎找不到关于这些行为如何工作的讨论。这两部分的措辞非常相似:
If
C
declares a field with the name and descriptor specified by the field reference, field lookup succeeds. [...]
及
[...] if
C
declares a method with the name and descriptor specified by the method reference, method lookup succeeds.
这向我表明,上面示例中的ivar行为是合理的,CA
的类文件不知道CB
,因此它的字段ref指向它自己的ivar
版本,JVM在执行该类的方法时设置并获取值时尊重这一点
但覆盖方法似乎也是如此,我没有找到解决算法来讨论“当前对象类”与“实现对象类”等。我找错地方了吗?有人能为我介绍一下设计/实施吗?谢谢
# 1 楼答案
这在JLS的第15.12节“方法调用表达式”中有记录:
这只是一个注释,方法调用的实际规则非常详细,您需要的部分是15.12.4.4。找到要调用的方法
https://docs.oracle.com/javase/specs/jls/se15/html/jls-15.html#jls-15.12
# 2 楼答案
我看不出你的困惑,它输出的正是我所期望的