前言
在 Java 中有两种方式可以让我们在运行时识别对象和类的信息。一种是 RTTI(运行时类型识别:Run-Time Type Identification),它假定了我们在编译时已经知道了所有的类型;另一种是我们本文要说的反射机制,它允许我们在运行时获取和使用类的信息。无论是 RTTI 还是反射,其本质都是一样的,都是去动态的获取类的信息。它们唯一不同的是,RTTI 在编译时期知道要解析的类型,而反射是在运行时才知道要解析的类型。
反射概述
反射就是把 Java 类中的各个部分(属性、方法、构造方法等)映射成一个个对象。Class 类与 java.lang.reflect 类库一起对反射的概念提供了支持,类库中包含了 Field、Method 及 Constructor 类,每个类都实现了 Member 接口。这些类型的对象都是由 JVM 运行时创建的,用来表示未知类里对应的成员。这样我们就可以使用 Constructor 创建新的对象,用 get 和 set 方法读取和修改类中与 Field 对象关联的字段,用 invoke 方法调用类中与 Method 对象关联的方法等。
Java 反射机制是在运行状态中的,对于任意一个类我们可以通过反射获取这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性。重要的是,要认识到反射机制并没有什么特别之处,当我们通过反射和一个未知类型的对象打交道时,JVM 只是简单的对这个对象做检查,看它属于哪个类,在用它做其它事情之前必须先加载那个类 Class 对象。所以那个类的字节码文件对象对于 JVM 来说必须是可获取的,要么在本地机器上,要么通过网络获取。
反射 API 的使用
想要通过反射获取一个类的信息之前,首先要先获取这个类的 Class 对象,在 Java 中所有类型都有与之关联的 Class 对象。
获取类的 Class 对象
在 Java 中获取一个类的 Class 对象有三种方式:
第 ① 种 使用 Class 类的 forName 静态方法,当我们知道一个类的全路径时,可以通过 Class.forName 方法获取类的 Class 对象。
Class stringClass = Class.forName("java.lang.String");
System.out.println(stringClass);
运行结果
class java.lang.String
第 ② 种 使用 .class 获取,这种方式只适合在编译前就已经知道了要操作的 Class。
Class stringClass = String.class;
System.out.println(stringClass);
运行结果
class java.lang.String
第 ③ 种 使用 getClass() 方法获取
Class stringClass = "mghio".getClass();
System.out.println(stringClass);
运行结果
class java.lang.String
通过反射创建类对象
通过反射创建类对象有两种方式:
第 ① 种 通过调用 Class 对象的 newInstance() 方法创建
Class personClass = Person.class;
Person person = personClass.newInstance();
第 ② 种 通过调用 Constructor 对象的 newInstance() 方法创建
Class personClass = Person.class;
Constructor personConstructor = personClass.getConstructor();
Person person = (Person) personConstructor.newInstance();
两者的区别是,通过 Class 的 newInstance 方法只能通过无参构造方法创建,这就要求这个类必须有一个无参的构造方法,而通过 Constructor 的 newInstance 可以指定参数来选择特定的构造方法来创建对象。以下代码就是指定参数然后通过特定的构造方法创建对象的。
Class personClass = Person.class;
Constructor personConstructor = personClass.getConstructor();
Person person = (Person) personConstructor.newInstance("mghio", "中国上海");
通过反射获取类的属性
Class 类提供了两种方式获取一个类的属性,第 ① 种是通过 Class 对象的 getFields 方法获取类的属性,该方法只能获取类的 public 属性。
Class personClass = Person.class;
Field[] fields = personClass.getFields();
System.out.println(Arrays.toString(fields));
运行结果
[public java.lang.String cn.mghio.blogmghiocode.reflect.Person.id,
public java.lang.String cn.mghio.blogmghiocode.reflect.Person.name]
第 ② 种是通过 Class 对象的 getDecl