Java-polymorphism-02
来源:互联网 发布:数据控制报警 编辑:程序博客网 时间:2024/05/14 09:42
提出问题:上例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()方法。
* Title: polymorphism in Java<br>
* Description: 此例解释"多态"概念, 无任何功能接口<br>
* Company: Augmentum Inc<br>
* Copyright: (c) 2008 Thinking in Java<br>
* @author Forest He
* @version 1.0
*/
package com.augmentum.foresthe;
import java.util.Random;
public class Shapes ...{
private static RandomShapeGenerator gen = new RandomShapeGenerator();
public static void main(String[] args) ...{
Shape[] shape = new Shape[10];
for(int i = 0; i < 10; i++) shape[i] = gen.next();
for(int i = 0; i < 10; i++) shape[i].draw();
}
}
class Shape ...{
public void draw() ...{}
public void erase() ...{}
}
class Circle extends Shape ...{
public void draw() ...{ System.out.println("Circle.draw()"); }
public void erase() ...{ System.out.println("Circle.erase()"); }
}
class Square extends Shape ...{
public void draw() ...{ System.out.println("Square.draw()"); }
public void erase() ...{ System.out.println("Square.erase()"); }
}
class Triangle extends Shape ...{
public void draw() ...{ System.out.println("Triangle.draw()"); }
public void erase() ...{ System.out.println("Triangle.erase()"); }
}
/**//* A factory that randomly creates shapes.*/
class RandomShapeGenerator ...{
private Random rand = new Random();
public Shape next() ...{
switch(rand.nextInt(3)) ...{
default:
case 0: return new Circle();
case 1: return new Square();
case 2: return new Triangle();
}
}
}
/**//*
* RandomShapeGenerator是一种工厂(factory), 每次调用next(), 它可以为随机选择的Shape对象产生一个引用. 请注意向上转型是在return语句里发生的. 每个return语句取得一个指向某个Circle、Square or Triangle的引用, 并将其以Shape类型从next()方法中发送出去.
* 随机选择几何形状是为了让大家理解: 在编译时, 编译器不需要获得任何特殊信息就能进行正确的调用. 对draw()方法的所有调用都是通过动态绑定进行的.
*/
可扩展性
现在让我们回到“乐器”(Instrument)示例。由于多态机制,我们可根据自己的需求对系统添加任意多的新类型,而不需要改tune()方法。**在一个设计良好的OOP程序中,大多数甚至所有方法都会遵循tune()的模型,而且只与基类接口通信。这样的程序是“可扩展的”,因为可以从通用的基类继承出新的数据类型,从而新添一些功能。那些操纵基类接口的方法不需要任何改动就可以应用于新类。
提出问题:对于“乐器”例子,如果我们向基类中添加更多的方法,并加入一些新类,将会出现什么情况?
回答问题:不需要改动tune()方法,所有的新类都能和原有类一起正确运行。即使tune()方法是单独存放在某个文件中,并且在Instrument接口中添加了其他的新方法,tune()也不需要再编译就能正确运行。示例见书。
我们所做的代码修改,不会对程序中其他不应受到影响的部分产生破坏。换句话说,多态是一项让程序员“将改变的事物与未变的事物分离开来”的重要技术。
缺陷:“覆盖”私有方法
* Title: private method in override<br>
* Description: 此例解释"多态"概念, 无任何功能接口<br>
* Company: Augmentum Inc<br>
* Copyright: (c) 2008 Thinking in Java<br>
* @author Forest He
* @version 1.0
*/
package com.augmentum.foresthe;
public class PrivateOverride ...{
private void f() ...{ System.out.println("private f()"); }
public static void main(String[] args) ...{
PrivateOverride po = new Derived();
po.f();
}
}
class Derived extends PrivateOverride ...{
public void f() ...{ System.out.println("public f()"); }
}
我们所期望的输出是“public f()”,但是由于private方法被自动认为是final方法,而且对导出类是屏蔽的。因此,Derived类中的f()方法就是一个全新的方法;基类中的f()方法在子类Derived中不可见,也不能被继承和重载。
结论:只有非private方法才可以被覆盖;但是还需要密切注意覆盖private方法的现象,这时虽然编译器不会报错,但是也不会按照我们所期望的来执行。确切的说,在导出类中,对于基类中的private方法,最好采用不同的名字。
- Java-polymorphism-02
- Java Polymorphism
- Java-polymorphism-01
- Java - Constructors and Polymorphism
- 【Java】多态性Polymorphism
- Java 基础 polymorphism(多态)
- Thinking in java : polymorphism
- java info polymorphism
- Java implement polymorphism
- C++.Homework.Polymorphism.02
- C++ Note-Polymorphism-02
- Polymorphism
- Polymorphism
- polymorphism
- Polymorphism
- Polymorphism
- Polymorphism
- Polymorphism
- Java-polymorphism-01
- Vss2005源代码管理使用帮助
- C#实现数据库的备份与还原
- VC++对象模型
- WORD自动引用参考文献
- Java-polymorphism-02
- 进程管理对象器的实现,数据结构为链表
- 建立正则表达式
- Firefox中的XPath
- 0420 测试记录 gcc 编译时 库文件 头文件问题及其解决方案
- 使用XPath查找XML文档中的信息
- 男人感悟100条
- SQL字符串函数
- csdn里的小窝~~~