我的理解是,子类转换为父类(如 Super sc = new Child();
)会调用父类的静态方法,并访问父类的非隐藏方法字段,但会使用子类的实例方法。
这似乎不适用于私有(private)实例方法的情况(因为父方法是私有(private)的,所以实际上不会发生覆盖。)
我知道没有覆盖的事实(私有(private)父方法对 child 不可见,所以它们只能被隐藏。)这意味着 child 不会查找层次结构来查看父的版本从子调用实例方法时的方法。
然而,与我所期望的完全相反(被调用的 child 中存在的版本)正在发生。私有(private)方法的父版本被调用。
如果通常调用子对象的实例方法,并且在子对象中有一个具有相同签名的方法(与调用 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().");
}
}
}
最佳答案
首先,B 实际上是一个嵌套类,奇怪的是,嵌套类的私有(private)成员可以被外部类访问。否则,执行 ((A.B)a).method2();
甚至是不合法的(反之亦然。B 也可以访问 A 中的私有(private)成员。)
也就是说,为了回答您的实际问题,a.method2();
调用 A 中的私有(private)方法的原因是私有(private)方法不是虚拟的,因为它们根本无法被覆盖。 (如果继承类甚至不应该知道它们,它们怎么可能呢?)因此,它们在编译时被绑定(bind),这意味着使用变量的声明类型。 A a
被声明为 A,但是 (A.B)a
在编译时被转换为 B。因此,您的第一个调用使用私有(private)方法来自 A,您的第二次调用使用来自 B 的私有(private)方法。
奇怪的是,这两段中的事实并不相互影响。可以合理地期望,因为嵌套类“知道”外部类的私有(private)成员,所以覆盖是可能的。但事实并非如此。私有(private)函数永远不会出现在 vTable 中,也永远不会被覆盖。
关于java - 为什么子类转换为父类型默认为私有(private)实例方法的父版本,而不是其他实例方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25805076/