这个简单程序的输出是This is base
。
public class mainApp{
private void func(){
System.out.println("This is base");
}
public static void main(String[] args){
mainApp newObj = new derived();
newObj.func();
}
}
class derived extends mainApp{
public void func(){
System.out.println("This is derived");
}
}
我的问题是当我们使用这一行时mainApp newObj = new derived();
我们实际上并没有使用基类 mainApp 派生类的对象>。所以,当我使用该对象调用它的方法时,为什么我不从派生类中获取方法?为什么我从基类中获取方法。
使用此行mainApp newObj = new derived();
,我们正在使用 mainApp 的引用,或者我们正在使用派生类的对象。哪一个是正确的?
答案 0 :(得分:8)
您获得基类方法的原因是func
的基类版本声明为private
,而Java不允许子类重写私有方法。这意味着如果扩展基类并且纯粹巧合决定将私有成员函数命名为与基类中的私有成员函数相同的名称,则不会意外地更改基类的成员函数的行为。您确实使用的是derived
类型的对象,但由于该引用是静态类型为mainApp
,因此调用func
会将其解释为调用私有方法func
中的mainApp
而不是func
中的公开方法derived
。将代码更改为
derived d = new derived();
d.func();
解决了这个问题,因为d
的静态类型现在是derived
,而func
的调用具有不同的含义。
在JVM字节码级别,用于调用私有成员函数的指令是invokespecial
,而用于调用普通,可覆盖成员函数的指令是invokevirtual
。两者的语义完全不同; invokespecial
开始查看当前类(或类似构造函数的某些基类),而invokevirtual
在运行时查找对应于对象类型的类。
答案 1 :(得分:0)
您正在使用derived
课程。对该对象的引用是mainApp
。这意味着其他人将其视为mainApp
,但它是作为派生类实现的。