第十一章 运行期类型鉴定.pdf
文本预览下载声明
第 11章 运行期类型鉴定
运行期类型鉴定(RTTI)的概念初看非常简单——手上只有基础类型的一个句柄时,利用它判断一个对象的
正确类型。
然而,对RTTI的需要暴露出了面向对象设计许多有趣(而且经常是令人困惑的)的问题,并把程序的构造问
题正式摆上了桌面。
本章将讨论如何利用Java在运行期间查找对象和类信息。这主要采取两种形式:一种是“传统”RTTI,它假
定我们已在编译和运行期拥有所有类型;另一种是Java1.1特有的“反射”机制,利用它可在运行期独立查
找类信息。首先讨论“传统”的RTTI,再讨论反射问题。
11.1对 RTTI的需要
请考虑下面这个熟悉的类结构例子,它利用了多形性。常规类型是Shape类,而特别衍生出来的类型是
Circle,Square和Triangle。
这是一个典型的类结构示意图,基础类位于顶部,衍生类向下延展。面向对象编程的基本目标是用大量代码
控制基础类型(这里是Shape)的句柄,所以假如决定添加一个新类(比如Rhomboid,从Shape衍生),从
而对程序进行扩展,那么不会影响到原来的代码。在这个例子中,Shape接口中的动态绑定方法是draw(),
所以客户程序员要做的是通过一个普通Shape句柄调用draw()。draw()在所有衍生类里都会被覆盖。而且由
于它是一个动态绑定方法,所以即使通过一个普通的Shape句柄调用它,也有表现出正确的行为。这正是多
形性的作用。
所以,我们一般创建一个特定的对象(Circle,Square,或者Triangle),把它上溯造型到一个Shape(忽
略对象的特殊类型),以后便在程序的剩余部分使用匿名Shape句柄。
作为对多形性和上溯造型的一个简要回顾,可以象下面这样为上述例子编码(若执行这个程序时出现困难,
请参考第3章3.1.2小节“赋值”):
//: Shapes.java
package c11;
importjava.util.*;
interface Shape {
void draw();
}
class Circle implements Shape {
public void draw() {
System.out.println(Circle.draw());
}
}
class Square implements Shape {
333
public void draw() {
System.out.println(Square.draw());
}
}
class Triangle implements Shape {
public void draw() {
System.out.println(Triangle.draw());
}
}
public class Shapes {
public static void main(String[] args) {
Vector s = new Vector();
s.addElement(new Circle());
s.addElement(new Square());
s.addElement(new Triangle());
Enumeration e = s.elements();
while(e.hasMoreElements())
((Shape)e.nextElement()).draw();
}
} ///:~
基础类可编码成一个interface(接口)、一个abstract(抽象)类或者一个普通类。由于Shape没有真正
的成员(亦即有定义的成员),而且并不在意我们创建了一个纯粹的Shape对象,所以最适合和最灵活的表
达方式便是用一个接口。而且由于不必设置所有那些abstract关键字,所以整个代码也显得更为清爽。
每个衍生类都覆盖了基础类draw方法,所以具有不同的行为。在main()中创建了特定类型的Shape,然后将
其添加到一个Vector。这里正是上溯造型发生的地方,因为Vector只容纳了对象。由于Java中的所有东西
(除基本数据类型外)都是对象,所以Vector也能容纳Shape对象。但在上溯造型至Object的过程中,任
何特殊
显示全部