有 Java 编程相关的问题?

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

Java中的继承超级关键字,有趣的行为,请解释

假设我们有以下代码:

class A {

    public void doLogic() {
        System.out.println("doLogic from A");
    }
}

class B extends A {

    @Override
    public void doLogic() {
        System.out.println("doLogic from B");
    }

    public void doDifferentLogic() {
        System.out.println("doDifferentLogic from B");
        super.doLogic();
    }
}

class C extends B {

    @Override
    public void doLogic() {
        System.out.println("doLogic from C");
    }
}

public class Test {

    public static void main(String[] args) {
        C c = new C();
        c.doDifferentLogic();
    }
}

当我们执行此代码时,预期的行为如下: 由于c持有对类c的对象的引用,当您调用c.doDifferentLogic()方法时,JVM在c类中搜索该方法,并且由于未找到该方法,因此它开始查看继承树。正如所料,doDifferentLogic()方法在超类中找到并执行。但是,构造super.doLogic()应该从当前的引用“Point of View”中查看,它是C类型的。因此C的super应该是B,但是调用了顶级类A中的方法

如果删除super关键字,或者将其替换为this关键字(这与“this”是隐式的相同),则会得到预期的多态行为,并从C类调用doLogic()

所以我的问题是: 对super.doLogic()的调用应该是this.super.doLogic()(2),而不是static.super.doLogic()(1)

两者都是无效的结构,它们在这里只是为了更好地解释我自己

(1)或者换句话说,从对当前对象c的引用中,获取当前对象的超类并调用doLogic()方法,而不是 (2) 从这个类中获取超类并调用它的doLogic()方法


共 (3) 个答案

  1. # 1 楼答案

    在Java中,super关键字总是指使用该关键字的类型的超类,而不是调用该方法的对象的动态类型的超类。换句话说,super是静态解析的,而不是动态解析的。这意味着在类B的上下文中,super关键字始终引用类A,而不管B方法是否使用C对象作为接收器执行。据我所知,没有一种方法可以在不使用反射的情况下动态确定超类类型并使用其方法

    希望这有帮助

  2. # 2 楼答案

    这里是JLS defines this specifically的位置:

    • If the form is super . NonWildTypeArgumentsopt Identifier, then the name of the method is the Identifier and the class to be searched is the superclass of the class whose declaration contains the method invocation.

    因此Java认为super是指包含super.method调用的类的超类,而不是实际的运行时类型

  3. # 3 楼答案

    无论什么时候,超级英雄。如果执行classB中的doLogic(),它将始终引用classB的超类的doLogic()方法,在本例中,它将是classA。这是所需的行为,因此控件不会在同一方法内的类之间保持传递。这是类上下文的概念。一旦您处于一个类的上下文中,您就必须遵循该类建立的规则,而不是在不同的上下文之间传递控制