RTTI

RTTI(RunTime Type Information)运行时类型信息,能够在程序运行时发现和使用类型信息,把我们从只能在编译期知晓类型信息并操作的局限中解脱出来。

Class 对象

当我们编写并编译了一个新类,就会产生一个 Class 对象,它包含了与类有关的信息。我们可以使用 Class 对象来实现 RTTI,一旦某个类的 Class 对象被载入内存,它就可以用来创建这个类的所有对象。

Class 对象都属于 Class 类型,既然它也是对象,那我们就可以获取和操控它的引用。

获取 Class 对象

3 种获取 Class 对象的方式:

// 类 的class属性
Class cl=Stu.class;
// 对象的 getClass()方法
Class cl=obj.getClass();
// Class类 的静态方法
Class cl=Class.forName("com.learnjava.reflection.Stu");

通过类字面常量方式 类名.class 直接获取目标类型的 Class 对象引用。不仅可以用于普通类,也可以用于接口、数组以及基本数据类型,这种方式不会触发类的加载。

如果持有目标类型的对象 obj,通过调用 obj.getClass() 方法来获取 Class 对象引用,这个方法来自根类 Object,它将返回表示该对象实际类型的 Class 对象的引用

Class.forName() 是 Class 类的一个静态方法,可以根据**目标类的全限定名(包含包名)**得到该类的 Class 对象。该方法的副作用:如果这个类没有被加载就会加载它,而在加载的过程中,这个类的 static 初始块会被执行。当找不到要加载的类,就会抛出异常 ClassNotFoundException。

此外,可以调用 Class 对象的 getSuperclass() 方法来得到父类的 class 对象,再用父类的 Class 对象调用该方法,重复多次,你就可以得到一个完整的类继承结构。

(Class 对象的 newInstance() 方法可以创建这个类的对象,使用 newInstance() 创建对象,该类型必须带有无参数的构造器;推荐使用 clazz.getDeclaredConstructor().newInstance() 代替)

通过 Class 对象获取类型信息

方法 说明
asSubclass(Class clazz) 用于将 Class 对象安全转换为其子类类型(会抛出异常)
cast(Object obj) 把对象 obj 转换成代表类或是接口的对象
getClassLoader() 获得类的加载器
getClasses() 返回一个数组,数组中包含该类中所有公共类和接口类的 Class 对象(包括自己内声明的,以及从父类中继承的公有类型)
getDeclaredClasses() 返回一个数组,数组中包含该类中所有类和接口类的 Class 对象(类自己声明的所有权限的类型)
forName(String className) 等效于静态方法 Class.forName(className)
getName() 获得类的完整路径名字
getSimpleName() 获得类的名字
getPackage() 获得类的包
getSuperclass() 返回当前类的直接父类的 Class 对象
如果此 Class 代表 Object 类、接口、基本类型或 void,则返回 null。如果此 Class 对象表示数组类,则返回表示 Object 类的 Class 对象。
getInterfaces() 返回当前类或接口直接实现的接口
如果此 Class 对象表示一个类,则返回值是一个包含表示该类直接实现的所有接口的对象数组;
如果此 Class 对象表示一个接口,则返回值是一个包含表示该接口直接扩展的所有接口的对象数组

除了上面的类型信息,还有关于该类本身的相关类型信息,具体看反射机制。

反射机制

类 Class 支持反射的概念,java.lang.reflect 库中支持类 Field、Method、Constructor(每一个都实现了 Member 接口),这些类型的对象由 JVM 运行时创建,以表示未知类中的对应成员。

总的来说,反射机制是在运行状态中,动态地获取类型信息以及动态调用对象方法的功能。