反射
反射
java反射(Reflection)是一个强大的特性,- 它允许程序在运行时查询、访问和修改类、接口、字段和方法的信息。
- 反射提供了一种动态地操作类的能力,这在很多框架和库中被广泛使用,例如Spring框架的依赖注入。
反射 API
Java的反射API提供了一系列的类和接口来操作Class对象。java.lang.reflect是Java反射机制的核心包,提供了操作类及其成员(字段、方法、构造函数等)的类和接口。通过这些API,开发者可以在运行时动态地查询和修改类的结构。
常用
API | 作用 |
|---|---|
java.lang.Class | 表示类的对象。提供了方法来获取类的字段、方法、构造函数等 |
java.lang.reflect.Field | 表示类的字段(属性)。提供了访问和修改字段的能力。 |
java.lang.reflect.Method | 表示类的方法。提供了调用方法的能力。 |
java.lang.reflect.Constructor | 表示类的构造函数。提供了创建对象的能力。 |
Class类相关
表示类的对象,提供了获取类信息的方法,如字段、方法、构造函数等。
API | 作用 |
|---|---|
getFields() | 获取类的获取所有公共字段。 |
getDeclaredFields() | 获取所有声明的字段,包括私有字段。 |
getField(String name) | 根据名称获取公共字段。 |
getDeclaredField(String name) | 根据名称获取声明的字段,包括私有字段。 |
getMethods() | 获取类的所有公共方法。 |
getDeclaredMethods() | 获取所有声明的方法,包括私有方法。 |
getMethod(String name, Class<?>... parameterTypes) | 根据名称和参数类型获取公共方法。 |
getDeclaredMethod(String name, Class<?>... parameterTypes) | 根据名称和参数类型获取声明的方法,包括私有方法。 |
getConstructors() | 获取类的所有公共构造函数。 |
getDeclaredConstructors() | 获取所有声明的构造函数,包括私有构造函数。 |
getConstructor(Class<?>... parameterTypes) | 根据参数类型获取公共构造函数。 |
getDeclaredConstructor(Class<?>... parameterTypes) | 根据参数类型获取声明的构造函数,包括私有构造函数。 |
getSuperclass() | 获取父类。 |
getInterfaces() | 获取类实现的接口。 |
Field类相关
表示类的字段(属性),提供了访问和修改字段的能力。
api | 作用 |
|---|---|
get(Object obj) | 获取字段的值 |
set(Object obj, Object value) | 设置字段的值 |
getType() | 获取字段的类型 |
getName() | 获取字段的名称 |
Method类相关
表示类的方法,提供了调用方法的能力。
api | 作用 |
|---|---|
invoke(Object obj, Object... args) | 调用方法 |
getParameterTypes() | 获取方法的参数类型 |
getReturnType() | 获取方法的返回类型 |
getName() | 获取方法的名称 |
getModifiers() | 获取方法的修饰符 |
Constructor类相关
表示类的构造函数,提供了创建对象的能力。
api | 作用 |
|---|---|
newInstance(Object... initargs) | 创建一个新实例,使用指定的构造函数参数。 |
getParameterTypes() | 获取构造函数的参数类型 |
getName() | 获取构造函数的名称 |
getModifiers() | 获取构造函数的修饰符 |
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class ReflectionExample {
public static void main(String[] args) throws Exception {
// 获取 Class 对象
Class<?> clazz = Person.class;
// 创建对象
Constructor<?> constructor = clazz.getConstructor(String.class, int.class);
Object person = constructor.newInstance("John", 30);
// 访问字段
Field nameField = clazz.getDeclaredField("name");
nameField.setAccessible(true);
System.out.println("Name: " + nameField.get(person));
// 修改字段
nameField.set(person, "Doe");
System.out.println("Updated Name: " + nameField.get(person));
// 调用方法
Method greetMethod = clazz.getMethod("greet", String.class);
greetMethod.invoke(person, "World");
}
}
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void greet(String message) {
System.out.println(name + " says: " + message);
}
}
工作流程
- 获取
Class对象,首先获取目标类的Class对象。 - 获取
Field对象,通过Class对象,可以获取类的字段、方法、构造函数等信息 - 操作成员:通过反射
API可以读取和修改字段的值、调用方法以及创建对象。
获取 Class 对象
每个类在 JVM 中都有一个与之相关的 Class 对象。可以通过以下方式获取 Class 对象:
通过类字面量获取:
Class<?> clazz = String.class;
通过对象实例获取
String str = "Hello World";
Class<?> clazz = str.getClass();
通过 Class.forName()方法获取
Class<?> clazz = Class.forName("java.lang.String");
创建对象
可以使用反射动态创建对象:
Class<?> clazz = Class.forName("java.lang.String");
Object obj = clazz.getDeclaredConstructor().newInstance();
访问字段
可以通过反射访问和修改类的字段:
Class<?> clazz = Person.class;
Field field = clazz.getDeclaredField("name");
field.setAccessible(true); // 如果字段是私有的,需要设置为可访问
Object value = field.get(personInstance); // 获取字段值
field.set(personInstance, "New Name"); // 设置字段值
调用方法
可以通过反射调用类的方法:
Class<?> clazz = Person.class;
Method method = clazz.getMethod("sayHello");// 获取无参方法
method.invoke(personInstance);// 调用方法
Method methodWithArgs = clazz.getMethod("greet", String.class);// 获取有参方法 String.class 是参数类型
methodWithArgs.invoke(personInstance, "World");// 调用方法,传入参数
获取构造函数
可以通过反射获取类的构造函数:
Class<?> clazz = Person.class;//通过反射获取类
Constructor<?> constructor = clazz.getConstructor(String.class, int.class);//获取构造函数 String.class 是参数类型 int.class 是参数类型
Object obj = constructor.newInstance("John", 30);// 通过构造函数创建对象
获取接口和父类
可以使用反射获取类实现的接口和父类:
Class<?> clazz = Person.class;// 通过反射获取类
Class<?>[] interfaces = clazz.getInterfaces();// 获取所有接口
for (Class<?> i : interfaces) {
System.out.println("Interface: " + i.getName());// 打印接口名称
}
Class<?> superClass = clazz.getSuperclass();// 获取父类
System.out.println("Superclass: " + superClass.getName());// 打印父类名称