2011-07-21 124 views
2

这个简单的程序的输出是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的参考工作OR我们正在与衍生类的对象工作。哪一个是正确的?

回答

8

您得到基类方法的原因是func的基类版本被声明为private,并且Java不允许私有方法被子类覆盖。这意味着如果你扩展一个基类并且纯粹的巧合决定将一个私有成员函数命名为一个基类中的私有成员函数,那么你不会意外地改变基类成员函数的行为。您确实有derived类型的对象的工作,但由于基准静态类型为mainApp,呼吁func被解释为derived调用私人方法funcmainApp而非公众方法func。更改代码读取

derived d = new derived(); 
d.func(); 

修复了这个,因为静态类型的d现在是derived和调用func具有不同的含义。

在JVM字节码级别,用于调用私有成员函数的指令为invokespecial,而用于调用普通的可重写成员函数的指令为invokevirtual。两者有完全不同的语义; invokespecial开始寻找在当前类(或之类的东西的构造一些基类),而invokevirtual看起来在对应于该对象的运行时类型的类。

+0

哇,优良的答案,你打我一拳。 @iamcreasy在[Java和多态性](http://home.cogeco.ca/~ve3ll/jatutor5.htm)上为您阅读了一些内容,希望能够澄清关于您的问题的混乱情况。 – Grambot

+0

我不习惯Java中出现的静态和动态类型之间的区别!当我看到这个时,我真的很惊讶。好东西,我先学习了C++。 :-) – templatetypedef

+0

@templatetypedef所以,当我将使用的任何参考后点符号,我将使用该特定参考的方法无论所述参考所指向的对象。这是对的吗? &什么意思是“参考是静态类型的”? –

0

您正在使用derived类。该对象的引用是mainApp。这意味着其他人将其视为mainApp,但它被实现为派生类。