我的理解是,子类型转换为父类型(如Super sc = new Child();)将调用父类的静态方法,并访问父类的非隐藏字段,但会使用子类的实例方法.
对于私有实例方法(由于父方法是私有的,实际上不会发生覆盖的情况),这似乎不适用.)
我理解没有覆盖的事实(私有父方法对于孩子是不可见的,因此它们只能被隐藏.)意味着孩子不会查找层次结构以查看父方法的方法版本.从子进程调用实例方法.
然而,正如我所期望的那样(正在调用的孩子中出现的版本)正好相反.调用私有方法的父版本.
如果通常调用子项的实例方法,为什么会发生这种情况,并且在子项中,有一个方法具有相同的签名(method2()在这种情况下是完全匹配),在父项中隐藏相同的方法类?
package whatever;
public class A {
public void method1(){
System.out.println("A method1().");
}
//using "final" here to emphasize that this is a hiding, not an override.
private final void method2(){
System.out.println("A private method2().");
}
public static void main(String[] args)
{
A a = new A().new B();
a.method1(); //calls B method 1
((A.B)a).method1(); //calls B method 1
a.method2(); //calls A private method 2 **I expected it to call B private method 2
((A.B)a).method2(); //calls B private method 2
}
public class B extends A {
public void method1(){
System.out.println("B method1().");
}
private final void method2(){
System.out.println("B private method2().");
}
}
}
Run Code Online (Sandbox Code Playgroud)
首先,B 实际上是一个嵌套类,奇怪的是,嵌套类的私有成员可以被外部类访问。否则,这样做甚至不合法((A.B)a).method2();(反之亦然。B 也可以访问 A 中的私有成员。)
也就是说,为了回答您的实际问题,a.method2();调用 A 中的私有方法的原因是私有方法不是虚拟的,因为它们根本不能被重写。(如果继承类根本不应该知道它们,它们怎么可能是这样?)因此,它们在编译时绑定,这意味着使用变量的声明类型。A a声明为 A,但在编译时(A.B)a强制转换为 B。因此,您的第一次调用使用 A 中的私有方法,第二次调用使用 B 中的私有方法。
奇怪的是,这两段中的事实并不相互影响。可以合理地预期,由于嵌套类“知道”外部类的私有成员,因此可能会进行覆盖。但事实并非如此。私有函数永远不会出现在 vTable 中,也永远不会被覆盖。