产生正确的行为
来源:互联网 发布:四灵进阶数据 编辑:程序博客网 时间:2024/04/29 05:17
一旦知道Java 中所有方法都是通过动态绑定实现多态这个事实之后,我们就可以编写只与
基类打交道的程序代码了,并且这些代码对所有的导出类都可以正确运行。或者换种说法,
发送消息给某个对象,让该对象去断定应该做什么事。
面向对象程序设计中,有一个最经典的“几何形状(shape)”例子。因为它很容易被可
视化,所以经常用到;但不幸的是,它可能使初学者认为面向对象程序设计仅适用于图形
化程序设计,实际当然不是这种情形了。
在“几何形状”这个例子中,包含一个 Shape 基类和多个导出类,如:Circle,Square,
Triangle 等。这个例子之所以好用,是因为我们可以说“圆是一种形状”,这种说法也很
容易被理解。下面的继承图展示了它们之间的关系:
向上转型可以像下面这条语句这么简单:
Shapes = new Circle();
这里,创建了一个Circle 对象,并把得到的引用立即赋值给 Shape,这样做看似错误(将
一种类型赋值给另一类型);但实际上是没问题的,因为通过继承, Circle 就是一种
Shape。因此,编译器认可这条语句,也就不会产生错误信息。
假设我们调用某个基类方法(已被导出类所重载):
s.draw();
同样地,我们可能会认为调用的是 shape 的 draw(),因为这毕竟是一个shape 引用,
那么编译器是怎样知道去做其他的事情呢?由于后期绑定(多态),程序还是正确调用了
Circle.draw( )方法。
下面的例子稍微有所不同:
//:c07:Shapes.java
// Polymorphismin Java.
import com.bruceeckel.simpletest.*;
import java.util.*;
class Shape {
void draw() {}
void erase() {}
}
class Circle extends Shape {
void draw() {
System.out.println("Circle.draw()");
}
void erase() {
System.out.println("Circle.erase()");
}
}
class Square extends Shape {
void draw() {
System.out.println("Square.draw()");
}
void erase() {
System.out.println("Square.erase()");
}
}
class Triangle extends Shape {
void draw() {
System.out.println("Triangle.draw()");
}
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();
}
}
}
public class Shapes {
private static Test monitor =new Test();
private static RandomShapeGenerator gen =
new RandomShapeGenerator();
public static void main(String[] args) {
Shape[] s = new Shape[9];
// Fill up thearray with shapes:
for(int i = 0; i < s.length; i++)
s[i] = gen.next();
// Makepolymorphic method calls:
for(int i = 0; i < s.length; i++)
s[i].draw();
monitor.expect(new Object[] {
new TestExpression("%%(Circle|Square|Triangle)"
+ "\\.draw\\(\\)", s.length)
});
}
} ///:~
Shape 基类为自它那里继承而来的所有导出类,建立了一个通用接口——也就是说,所有
形状都可以描绘和擦除。导出类重载了这些定义,以便为每种特殊类型的几何形状提供独特
的行为。
RandomShapeGenerator是一种“工厂(factory)”,在我们每次调用 next()方法
时,它可以为随机选择的 shape 对象产生一个引用。请注意向上转型是在 return 语句里
发生的。每个return 语句取得一个指向某个 Circle、Square 或者 Triangle 的句柄,并将
其以 Shape 类型从 next()方法中发送出去。所以无论我们在什么时候调用 next()方
法时,是绝对没有可能知道它所获的具体类型到底是什么,因为我们总是只能获得一个通用
的 Shape 引用。
main()包含了 Shape 句柄的一个数组,通过调用 RandomShapeGenerator.next( )来
填入数据。此时,我们只知道自己拥有一些 Shape,不会知道除此之外的更具体情况(编
译器一样不知)。然而,当我们遍历这个数组,并为每个数组元素调用 draw()方法时,与
各类型有关的专属行为竟会神奇般地正确发生,我们可以从运行该程序时,产生的输出结果
中发现这一点。
随机选择几何形状是为了让大家理解:在编译期间,编译器不需要获得任何特殊的信息,就
能进行正确的调用。对 draw()方法的所有调用都是通过动态绑定进行的。
- 产生正确的行为
- 正确的 send & recv 行为
- 产生随机数的正确方法
- sqlite 产生正确的 row_number
- 爱,产生在正确的时间
- 计划生育在基层会产生的一些不人道行为
- 针对不遵守GPL行为的正确做法
- matlab的rand()函数产生均匀分布函数的正确用法
- CC2541 Timer1 不能正常分频产生正确的 PWM
- AppWizard向导产生的MFC框架中文件菜单项动作的缺省处理行为
- EntityFramework6中管理DbContext的正确方式(二)【DbContext的默认行为】
- matlab的rand()函数产生均匀分布函数的正确用法 / matlab 中如何产生0-1上均匀分布的随机数
- (三十)信号——信号产生原因以及信号处理行为的简介
- SQL MD5 算法对中文字符串不能产生正确的 MD5 码 的解决办法
- 让用户输入一个整数,与产生的随机数做比较,提示用户输入的正确与否。
- 为什么我自定义的shader在实时光下能产生正确的镂空阴影,而烘焙却不能
- WXY的行为和ZP的行为
- 子类重载父类的非虚成员函数是否对从父类中继承且使用该成员函数的方法的行为产生影响
- shap
- wikioi p1501 二叉树最大宽度和高度
- Cross origin requests are only supported for HTTP
- 微软CEO史蒂夫·鲍尔默(Steve Ballmer)在12个月内退休
- 常用的函数:atoi,itoa,atof,_ttoi等
- 产生正确的行为
- 使用Virtual Box安装双节点Oracle 11gR2 RAC
- iOS UI控件的圆角设置,layer属性简单使用
- 红黑树源码实现
- wikioi p1842 递归第一次
- 缺陷:“重载”私有方法
- wikioi p3038 3n+1问题
- 编译avPlayer过程中遇到的问题
- 抽象类和抽象方法