让我们说我们有以下代码:
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()
方法?
答案 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。这是所需的行为,因此控件不会在同一方法中的类之间传递。这是类上下文的概念。一旦你进入一个类的上下文,你将必须遵循该类建立的规则,而不是在不同的上下文之间传递控制。