我正在寻找以下行为的解释:
- 我有6个类,{a.A,b.B,c.C,a.D,b.E,c.F},每个类都有一个包可见的m()方法,该方法会输出类名。
- 我有一个a.Main类,其中包含一个主方法,用于对这些类进行一些测试。
- 输出结果似乎不遵循正确的继承规则。
以下是这些类:
package a;
public class A {
void m() { System.out.println("A"); }
}
// ------
package b;
import a.A;
public class B extends A {
void m() { System.out.println("B"); }
}
// ------
package c;
import b.B;
public class C extends B {
void m() { System.out.println("C"); }
}
// ------
package a;
import c.C;
public class D extends C {
void m() { System.out.println("D"); }
}
// ------
package b;
import a.D;
public class E extends D {
void m() { System.out.println("E"); }
}
// ------
package c;
import b.E;
public class F extends E {
void m() { System.out.println("F"); }
}
主类在a
包中:
package a;
import b.B;
import b.E;
import c.C;
import c.F;
public class Main {
public static void main(String[] args) {
A a = new A();
B b = new B();
C c = new C();
D d = new D();
E e = new E();
F f = new F();
System.out.println("((A)a).m();"); ((A)a).m();
System.out.println("((A)b).m();"); ((A)b).m();
System.out.println("((A)c).m();"); ((A)c).m();
System.out.println("((A)d).m();"); ((A)d).m();
System.out.println("((A)e).m();"); ((A)e).m();
System.out.println("((A)f).m();"); ((A)f).m();
System.out.println("((D)d).m();"); ((D)d).m();
System.out.println("((D)e).m();"); ((D)e).m();
System.out.println("((D)f).m();"); ((D)f).m();
}
}
这里是输出结果:
((A)a).m();
A
((A)b).m();
A
((A)c).m();
A
((A)d).m();
D
((A)e).m();
E
((A)f).m();
F
((D)d).m();
D
((D)e).m();
D
((D)f).m();
D
以下是我的问题:
1) 我理解 D.m()
隐藏了 A.m()
,但是强制转换为 A
应该会暴露被隐藏的 m()
方法,这是正确的吗?还是说 D.m()
覆盖了 A.m()
,尽管 B.m()
和 C.m()
打破了继承链?
((A)d).m();
D
2) 更糟糕的是,下面的代码表现出覆盖效果,为什么?
((A)e).m();
E
((A)f).m();
F
为什么不在这部分呢:
((A)a).m();
A
((A)b).m();
A
((A)c).m();
A
这个呢?
((D)d).m();
D
((D)e).m();
D
((D)f).m();
D
我正在使用OpenJDK javac 11.0.2。
编辑:第一个问题已经在如何覆盖具有默认(包)可见性范围的方法?中得到解答。
如果D类中声明或继承的实例方法mD覆盖了A类中声明的另一个方法mA,则必须满足以下所有条件:
- A是D的超类。
- D没有继承mA(因为跨越包边界)。
- mD的签名是mA的子签名(§8.4.2)。
- 以下两者之一为真: [...]
- 在与D相同的包中以包访问权限声明mA(此情况下),并且D声明了mD,或mA是D直接超类的成员。 [...]
但是:第二个问题仍未解决。
List
强制转换为一个Object并调用它的toString方法,你不会调用Object的默认toString方法。在我看来,你的第二个问题揭示了Java的一个bug。在另一个包中调用包私有功能是不可能的。 - VGR