Detecting Types

本章将讨论 Java 是如何允许我们在运行期识别对象和类的信息。主要有两种方式:一种是传统的RTTI,它假定我们在编译期和运行期已经知道了所有的类型;另一种是“反射机制(reflection)”,它允许我们在运行期获得类的信息。

Class对象

每个类都有一个Class对象。换言之,每当你编写并且编译了一个新类,就会产生一个Class对象(更恰当地说,是被保存在一个同名的.class文件中)。在运行期,一旦我们想生成这个类的一个对象,运行这个程序的Java虚拟机(JVM)首先检查这个类的Class对象是否已经加载。如果尚未加载,JVM就会根据类名查找.class文件,并将其载入。所以Java程序并不是一开始执行,就被完全加载的,这一点与许多传统语言都不同。

Class对象仅在需要的时候才被加载,static语句块是在类加载时被执行的。

取得Class对象的引用的方法一

Class对象就和其他对象一样,我们可以获取并操作它的引用(这也就是类加载器的工作)。forName()是取得Class对象的引用的一种方法。它是用一个包含目标类的文本名(注意拼写和大小写)的String作输入参数,返回的是一个Class对象的引用:
Class.forName("Gum");
都可能会抛出异常.

取得Class对象的引用的方法二

类字面常量(Class literal):
Gum.class;
这样做不仅更简单,而且更安全,因为它在编译期就会受到检查(因此,它不会抛出任何异常)。并且它无需方法调用,所以也更高效。


RTTI形式包括

1. 经典的类型转换,如"(Shape)",由RTTI确保类型转换的正确性,如果你执行了一个错误的类型转换,就会抛出一个ClassCastException异常。
2. 代表对象类型的Class对象。通过查询Class对象可以获取运行期所需的信息。
3.关键字instanceof。它返回一个布尔值,告诉我们对象是不是某个特定类型的实例。你可以用提问的方式使用它,就象这样:
if (x  instanceof  Dog)
((Dog)x).bark();

进行向下转型前,如果没有其他信息可以告诉你这个对象是什么类型,那么使用instanceof是非常重要的,否则会得到一个ClassCastException异常。
对instanceof有比较严格的限制:你只可将其与类型的名字进行比较,而不能与Class对象作比较。
,如果程序中编写了许多的instanceof表达式,就说明你的设计可能存在瑕疵。


Class.newInstance()调用缺省的(无参数)构造器生成新的对象.

Class.isInstance方法提供了一种动态地调用instanceof运算符的途径。不再需要instanceof表达式,还可以动态添加新类型。

比较:instanceof vs. Class

instanceof 保持了类型的概念,它指的是“你是这个类吗,或者你是这个类的派生类吗?”
如果你用==比较实际的Class对象,就不包含继承关系,——它或者恰好是这个确切的类型,或者不是。

RTTI语法

首先,你需要获得指向适当的Class对象的引用。
  1. 一种办法是用字符串以及 Class.forName() 方法,获取Class的引用时,并不需要生成该Class类型的对象。
  2. 如果你已经有了一个你感兴趣的类型的对象,那么你就可以通过调用 getClass() 来获取 Class 的引用,这是根类Object提供的方法。它返回Class的引用,用来表示对象的实际类型。
  3. Class.getInterfaces() 方法返回 Class对象的数组,这些对象代表的是某个Class对象所包含的接口。
  4. 如果你有一个Class对象,那么你就可以通过 getSuperclass() 获取它的直接基类。这个方法自然也是返回一个Class的引用,所以你可以进一步查询其基类。这意味着在运行期,你可以找到一个对象完整的类层次结构。
  5. 乍看起来,Class的newInstance()方法似乎只是另一种克隆clone()对象的方法。然而,即使原先没有任何对象存在,你也可以用newInstance()创建一个新的对象。“尽管我不知道你的准确类型是什么,但无论怎样,还是请正确地创建你自己。” 使用 newInstance() 的类必须要有一个缺省构造器。
  6. getName()获取其名字。

你可能感兴趣的:(java,基础)