RTTI(RunTime Type Information)运行时类型信息,能够在程序运行时发现和使用类型信息,把我们从只能在编译期知晓类型信息并操作的局限中解脱出来。
当我们编写并编译了一个新类,就会产生一个 Class 对象,它包含了与类有关的信息。我们可以使用 Class 对象来实现 RTTI,一旦某个类的 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()
代替)
方法 | 说明 |
---|---|
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 运行时创建,以表示未知类中的对应成员。
总的来说,反射机制是在运行状态中,动态地获取类型信息以及动态调用对象方法的功能。