- 写在前面的话
- 引言
- 第 1 章 对象入门
- 第 2 章 一切都是对象
- 第 3 章 控制程序流程
- 第 4 章 初始化和清除
- 第 5 章 隐藏实施过程
- 第 6 章 类再生
- 第 7 章 多形性
- 第 8 章 对象的容纳
- 第 9 章 违例差错控制
- 第 10 章 Java IO 系统
- 第 11 章 运行期类型鉴定
- 第 12 章 传递和返回对象
- 第 十三 章 创建窗口和程序片
- 第 14 章 多线程
- 第 15 章 网络编程
- 第 16 章 设计范式
- 第 17 章 项目
- 附录 A 使用非 JAVA 代码
- 附录 B 对比 C++和 Java
- 附录 C Java 编程规则
- 附录 D 性能
- 附录 E 关于垃圾收集的一些话
- 附录 F 推荐读物
11.2 RTTI 语法
Java 用 Class 对象实现自己的 RTTI 功能——即便我们要做的只是象造型那样的一些工作。Class 类也提供了其他大量方式,以方便我们使用 RTTI。
首先必须获得指向适当 Class 对象的的一个句柄。就象前例演示的那样,一个办法是用一个字串以及 Class.forName() 方法。这是非常方便的,因为不需要那种类型的一个对象来获取 Class 句柄。然而,对于自己感兴趣的类型,如果已有了它的一个对象,那么为了取得 Class 句柄,可调用属于 Object 根类一部分的一个方法:getClass()。它的作用是返回一个特定的 Class 句柄,用来表示对象的实际类型。Class 提供了几个有趣且较为有用的方法,从下例即可看出:
//: ToyTest.java // Testing class Class interface HasBatteries {} interface Waterproof {} interface ShootsThings {} class Toy { // Comment out the following default // constructor to see // NoSuchMethodError from (*1*) Toy() {} Toy(int i) {} } class FancyToy extends Toy implements HasBatteries, Waterproof, ShootsThings { FancyToy() { super(1); } } public class ToyTest { public static void main(String[] args) { Class c = null; try { c = Class.forName("FancyToy"); } catch(ClassNotFoundException e) {} printInfo(c); Class[] faces = c.getInterfaces(); for(int i = 0; i < faces.length; i++) printInfo(faces[i]); Class cy = c.getSuperclass(); Object o = null; try { // Requires default constructor: o = cy.newInstance(); // (*1*) } catch(InstantiationException e) {} catch(IllegalAccessException e) {} printInfo(o.getClass()); } static void printInfo(Class cc) { System.out.println( "Class name: " + cc.getName() + " is interface? [" + cc.isInterface() + "]"); } } ///:~
从中可以看出,class FancyToy 相当复杂,因为它从 Toy 中继承,并实现了 HasBatteries,Waterproof 以及 ShootsThings 的接口。在 main() 中创建了一个 Class 句柄,并用位于相应 try 块内的 forName() 初始化成 FancyToy。
Class.getInterfaces 方法会返回 Class 对象的一个数组,用于表示包含在 Class 对象内的接口。
若有一个 Class 对象,也可以用 getSuperclass() 查询该对象的直接基础类是什么。当然,这种做会返回一个 Class 句柄,可用它作进一步的查询。这意味着在运行期的时候,完全有机会调查到对象的完整层次结构。
若从表面看,Class 的 newInstance() 方法似乎是克隆(clone())一个对象的另一种手段。但两者是有区别的。利用 newInstance(),我们可在没有现成对象供“克隆”的情况下新建一个对象。就象上面的程序演示的那样,当时没有 Toy 对象,只有 cy——即 y 的 Class 对象的一个句柄。利用它可以实现“虚拟构建器”。换言之,我们表达:“尽管我不知道你的准确类型是什么,但请你无论如何都正确地创建自己。”在上述例子中,cy 只是一个 Class 句柄,编译期间并不知道进一步的类型信息。一旦新建了一个实例后,可以得到 Object 句柄。但那个句柄指向一个 Toy 对象。当然,如果要将除 Object 能够接收的其他任何消息发出去,首先必须进行一些调查研究,再进行造型。除此以外,用 newInstance() 创建的类必须有一个默认构建器。没有办法用 newInstance() 创建拥有非默认构建器的对象,所以在 Java 1.0 中可能存在一些限制。然而,Java 1.1 的“反射”API(下一节讨论)却允许我们动态地使用类里的任何构建器。
程序中的最后一个方法是 printInfo(),它取得一个 Class 句柄,通过 getName() 获得它的名字,并用 interface() 调查它是不是一个接口。
该程序的输出如下:
Class name: FancyToy is interface? [false] Class name: HasBatteries is interface? [true] Class name: Waterproof is interface? [true] Class name: ShootsThings is interface? [true] Class name: Toy is interface? [false]
所以利用 Class 对象,我们几乎能将一个对象的祖宗十八代都调查出来。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论