有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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在执行该类的方法时设置并获取值时尊重这一点

但覆盖方法似乎也是如此,我没有找到解决算法来讨论“当前对象类”与“实现对象类”等。我找错地方了吗?有人能为我介绍一下设计/实施吗?谢谢


共 (2) 个答案

  1. # 1 楼答案

    这在JLS的第15.12节“方法调用表达式”中有记录:

    Resolving a method name at compile time is more complicated than resolving a field name because of the possibility of method overloading. Invoking a method at run time is also more complicated than accessing a field because of the possibility of instance method overriding.

    这只是一个注释,方法调用的实际规则非常详细,您需要的部分是15.12.4.4。找到要调用的方法

    If the method m of class or interface C is private, then it is the method to be invoked.

    Otherwise, overriding may occur. A dynamic method lookup, specified below, is used to locate the method to invoke. The lookup procedure starts from class R, the actual run-time class of the target object.

    https://docs.oracle.com/javase/specs/jls/se15/html/jls-15.html#jls-15.12

  2. # 2 楼答案

    我看不出你的困惑,它输出的正是我所期望的

    main calls
    CB.one which sets CB.ivar to 10, then calls
    CA.two which sets CA.ivar to 20, then calls
    CB.three which prints CB.ivar (10), then calls
    CA.three which prints CA.ivar (20)