Posted on 2009-06-07 19:33
eric_xu 阅读(224)
评论(0) 编辑 收藏 所属分类:
Java
运行期类型识别(RTTI,run-time
type identification):当你只有一个指向对象的基类的引用时,RTTI机制可以让你找出这个对象确切的类型。
两种方式:一种是传统的
RTTI,它假定我们在编译期和运行期已经知道了所有的类型;另一种是反射机制(reflection),它允许我们在运行期获得类的信息。
多态机制,Shape对象实际上执行什么样的代码,是由引用指向的具体对象是Circle,Square 或者Triangle而决定的。
类型信息在运行期的表示是由 “Class 对象”的特殊对象完成的,它包含了与类有关的信息。Class 对象正是被用来创建类的“常规”对象的。每个类都有一个 Class 对象。编写并且编译了一个新类,就会产生一个 Class 对象,保存在一个同名的.class 文件中。想生成这个类的一个对象,运行这个程序的 Java 虚拟机首先检查这个类的Class对象是否已经加载。如果尚未加载,JVM 就会根据类名查找.class 文件,并将其载入。Java 程序并不是一开始执行,就被完全加载的。一旦某个类的 Class 对象被载入内存,它就被用来创建这个类的所有对象。
Class.forName("Gum");这是Class类(所有Class对象都属于这个类型)的一个static
成员。Class对象就和其他对象一样,我们可以获取并操作它的引用(这也就是类加载器的工作)。forName()是取得Class 对象的引用的一种方法。对forName()的调用是为了它产生的“副作用”:如果类Gum还没有被加载就加载它。
Gum.class; 在编译期就会受到检查。
TYPE域是一个引用,指向对应的基本数据类型的 Class 对象。
RTTI形式包括:
1. 经典的类型转换,由RTTI确保类型转换的正确性,如果你执行了一个错误的类型转换,就会抛出一个ClassCastException异常。
2. 代表对象类型的Class对象。通过查询Class对象可以获取运行期所需的信息。
Java 是通过Class对象来实现RTTI机制的。
Class.forName()方法,在获取Class的引用时,并不需要生成该Class类型的对象。仅仅是获取引用。而如果你有了一个类型的对象,那么你可以通过调用getClass()来获取Class的引用,这是根类Object提供的方法。它返回Class 的引用,用来表示对象的实际类型。
Class.getInterfaces()方法返回Class对象的数组,这些对象代表的是某个Class对象所包含的接口。
如果你有一个Class对象,可以通过getSuperclass()获取它的直接基类,返回一个Class的引用,这意味着在运行期,你可以找到一个对象完整的类层次结构。
Class的newInstance()方法创建一个新的对象的方法。“尽管我不知道你的准确类型是什么,但还是请正确地创建你自己。”
反射(Reflection)运行期的类信息
在编译期,编译器必须知道你要通过RTTI 来处理的所有类。
java.lang.reflect包含了Field,Method以及Constructor类(每个类都实现了 Member 接口)。这些类型的对象是由JVM在运行期创建的,用以表示未知类里对应的成员。
匿名对象的类信息就能在运行期被完全确定下来,而在编译期不需要知道任何事情。
通过反射与一个未知类型的对象打交道时,JVM只是简单地检查这个对象,看它属于哪个特定的类,在做其它事情之前,必须加载那个类的 Class 对象。那个类的.class 文件对于JVM 来说必须是可获取的,要么在本地机器上,要么可以通过网络取得。
RTTI和反射之间真正的区别只在于,对 RTTI 来说,编译器在编译期打开和检查.class 文件。而对于反射机制来说.class文件在编译期间是不可获取的,所以是在运行期打开和检查.class 文件。
Class的getMethods()和getConstructors()方法分别返回Method 数组和Constructor 数组。