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

时间:2014-02-26 17:22:58

标签: java inheritance super

让我们说我们有以下代码:

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的超级应该是B,但是调用顶级A的方法。

如果删除super关键字,或将其替换为this关键字(与“this”隐含相同),则会获得预期的多态行为和{{1}从C类调用。

所以我的问题是: 应该致电doLogic() super.doLogic()(2),而不是this.super.doLogic()(1)?

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

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

3 个答案:

答案 0 :(得分:50)

在Java中,super关键字始终引用使用关键字的类型的超类,而不是调用方法的对象的动态类型的超类。换句话说,super是静态解决的,而不是动态解析的。这意味着在类B的上下文中,super关键字始终引用类A,无论B方法是否使用C执行对象作为接收者。据我所知,没有办法动态确定超类类型并使用它的方法而不使用反射。

希望这有帮助!

答案 1 :(得分:4)

以下是JLS defines this specifically

的位置
  
      
  • 如果表格是超级的。 NonWildTypeArguments opt Identifier ,然后方法的名称是 Identifier ,要搜索的类是类的超类,其声明包含方法调用。
  •   

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

答案 2 :(得分:1)

每当执行classB的super.doLogic()时,它总是引用classB的超类的doLogic()方法,在本例中是classA。这是所需的行为,因此控件不会在同一方法中的类之间传递。这是类上下文的概念。一旦你进入一个类的上下文,你将必须遵循该类建立的规则,而不是在不同的上下文之间传递控制。