提出问题:上例tune()方法接收一个Instrument引用。那么编译器怎样才能知道这个Instrument引用指向的是Wind对象,而不是Stringed对象或Brass对象呢?
回答问题:编译器无法得知,是“绑定”机制赋予的力量。
方法调用绑定
将一个方法调用和一个方法主体关联起来被称作“绑定”。若在程序执行前进行绑定(由编译器实现),叫做“前期绑定”(这是面向过程语言默认的绑定方式)。上诉程序之所以令人迷惑,主要是因为前期绑定。因为当编译器只有一个Instrument引用时,它无法知道究竟调用哪个方法才对。
解决的方法就是“后期绑定”:在运行时(而不是编译时)根据对象的类型进行绑定。Java中除了static方法和final方法(private方法属于final方法)之外,其他所有的方法都是后期绑定。
产生正确的行为
**一旦知道Java中所有方法都是通过动态绑定实现多态这个事实之后,我们就可以编写只与基类打交道的程序代码了,并且这些代码对所有的导出类都可以正确运行。也就是说,发送消息给某个对象,让该对象去判定应该做什么事。
面向对象程序设计中,有一个经典的例子就是“几何形状”(shape):一个基类Shape和多个导出类Circle、Square、Triangle等。
向上转型可以像下面这条语句这么简单:
Shape shape = new Circle();
这里创建了一个Circle对象,并把得到的引用shape赋值给Shape。这样看似错误(将一种类型赋值给另一种类型),但实际没有问题。假设你调用一个基类方法shape.draw();你可能认为调用的是Shape的draw(),因为这毕竟是一个Shape引用,但由于后期绑定(多态),编译器实际还是正确调用了Circle.draw()方法。








































































可扩展性
现在让我们回到“乐器”(Instrument)示例。由于多态机制,我们可根据自己的需求对系统添加任意多的新类型,而不需要改tune()方法。**在一个设计良好的OOP程序中,大多数甚至所有方法都会遵循tune()的模型,而且只与基类接口通信。这样的程序是“可扩展的”,因为可以从通用的基类继承出新的数据类型,从而新添一些功能。那些操纵基类接口的方法不需要任何改动就可以应用于新类。
提出问题:对于“乐器”例子,如果我们向基类中添加更多的方法,并加入一些新类,将会出现什么情况?
回答问题:不需要改动tune()方法,所有的新类都能和原有类一起正确运行。即使tune()方法是单独存放在某个文件中,并且在Instrument接口中添加了其他的新方法,tune()也不需要再编译就能正确运行。示例见书。
我们所做的代码修改,不会对程序中其他不应受到影响的部分产生破坏。换句话说,多态是一项让程序员“将改变的事物与未变的事物分离开来”的重要技术。
缺陷:“覆盖”私有方法

























我们所期望的输出是“public f()”,但是由于private方法被自动认为是final方法,而且对导出类是屏蔽的。因此,Derived类中的f()方法就是一个全新的方法;基类中的f()方法在子类Derived中不可见,也不能被继承和重载。
结论:只有非private方法才可以被覆盖;但是还需要密切注意覆盖private方法的现象,这时虽然编译器不会报错,但是也不会按照我们所期望的来执行。确切的说,在导出类中,对于基类中的private方法,最好采用不同的名字。