Java反射机制
反射
-
类的反射机制(Reflection)是 Java 提供的一种强大的功能,允许程序在运行时动态地获取类的信息并操作类的属性、方法和构造器。通过反射,程序可以在运行时分析类、接口、字段和方法,甚至可以调用方法、构造对象、修改字段值等
-
反射机制的核心类是 java.lang.Class,它是反射的入口点。通过 Class 对象,可以获取类的所有信息
-
Class类也是类,继承Obejct
-
一个类的Class对象内存中存在一份,由系统创建,有加锁机制
-
Class对象存储在堆中,类的元数据类名、父类名、接口列表、字段信息、方法信息、常量池等存放在方法区中
反射的主要功能
- 获取类的信息
- 获取类的名称、修饰符、父类、接口、注解等
- 操作类的字段
- 获取类的字段(成员变量),包括字段的名称、类型、修饰符等。
- 动态读取或修改字段的值
- 调用类的方法
- 获取类的方法,包括方法的名称、参数类型、返回类型、修饰符等
- 动态调用方法
- 操作类的构造器
- 获取类的构造器,包括构造器的参数类型、修饰符等。
- 动态创建对象
- 动态代理
- 通过反射实现动态代理,用于 AOP(面向切面编程)等场景
反射的核心类
java.lang.Class- 表示一个类或接口的元数据。
- 通过 Class 对象可以获取类的所有信息
java.lang.reflect.Field- 表示类的字段(成员变量)。
- 可以获取或修改字段的值
java.lang.reflect.Method- 表示类的方法。
- 可以调用方法
java.lang.reflect.Constructor- 表示类的构造器。
- 可以创建对象
反射的使用
获取class对象
Class 对象是反射的入口,获取 Class 对象的方式有以下几种
-
Class.forName("全限定类名")Class<?> clazz = Class.forName("com.example.Person"); -
类名.classClass<?> clazz = Person.class; -
对象.getClass()Person person = new Person(); Class<?> clazz = person.getClass();
获取类的相关信息
通过 Class 对象可以获取类的名称、修饰符、父类、接口等信息
Class<?> clazz = Person.class;
// 获取类名
String className = clazz.getName(); // 全限定类名
String simpleName = clazz.getSimpleName(); // 简单类名
// 获取修饰符
int modifiers = clazz.getModifiers(); // 返回修饰符的整型值
String modifierStr = Modifier.toString(modifiers); // 转换为字符串
// 获取父类
Class<?> superClass = clazz.getSuperclass();
// 获取实现的接口
Class<?>[] interfaces = clazz.getInterfaces();
操作字段
通过 Class 对象可以获取类的字段,并动态读取或修改字段的值
Class<?> clazz = Person.class;
// 获取公共字段(包括从父类继承的字段)
Field[] publicFields = clazz.getFields();
// 返回类中声明的所有字段(包括私有字段,但不包括从父类继承的字段)
Field[] fields = clazz.getDeclaredFields();
// 获取指定字段
Field nameField = clazz.getDeclaredField("name");
// 如果字段是私有的,需要先调用 setAccessible(true) 来绕过访问控制检查
nameField.setAccessible(true);
// 获取字段值
Person person = new Person();
Object value = nameField.get(person); // 获取 person 对象的 name 字段值
// 修改字段值
nameField.set(person, "Alice"); // 将 person 对象的 name 字段值设置为 "Alice"
可以遍历得到的fields数组来得到每个fields的具体信息,如字段的具体名称与类型、修饰符
// 获取字段名称
String fieldName = field.getName();
// 获取字段类型
Class<?> fieldType = field.getType();
// 获取字段修饰符
//返回字段修饰符(整型值)
int modifiers = field.getModifiers();
String modifierStr = Modifier.toString(modifiers);
调用方法
通过 Class 对象可以获取类的方法,并动态调用方法
Class<?> clazz = Person.class;
// 返回类中所有 公共方法(包括从父类继承的方法)
Method[] publicMethods = clazz.getMethods();
// 返回类中声明的所有方法(包括私有方法,但不包括从父类继承的方法)
Method[] methods = clazz.getDeclaredMethods();
// 获取指定参数类型的方法
Method sayHelloMethod = clazz.getDeclaredMethod("sayHello", String.class);
// 如果方法是私有的,需要先调用 setAccessible(true) 来绕过访问控制检查
sayHelloMethod.setAccessible(true);
// 调用方法
Person person = new Person();
Object result = sayHelloMethod.invoke(person, "World"); // 调用 person 对象的 sayHello 方法
可以遍历得到的methods数组来得到每个method的具体信息,如返回值或者参数类型等
// 获取返回类型
Class<?> returnType = method.getReturnType();
// 获取参数类型
Class<?>[] parameterTypes = method.getParameterTypes();
// 获取修饰符
//返回方法的修饰符(整型值)
int modifiers = method.getModifiers();
String modifierStr = Modifier.toString(modifiers);
-
如果字段或者方法为静态的,则可以使用null作为传入对象
Object value = field.get(null); // 获取静态字段的值 field.set(null, "Bob"); // 修改为 Bob method.invoke(null); // 调用无参方法 method.invoke(null, "Alice"); // 调用带参方法
操作构造器
通过 Class 对象可以获取类的构造器,并动态创建对象
Class<?> clazz = Person.class;
// 获取所有构造器
Constructor<?>[] constructors = clazz.getDeclaredConstructors();
// 获取指定构造器
Constructor<?> constructor = clazz.getDeclaredConstructor(String.class);
// 如果构造器是私有的,需要先调用 setAccessible(true) 来绕过访问控制检查
constructor.setAccessible(true);
// 创建对象
Person person = (Person) constructor.newInstance("Alice");
可以遍历得到的constructors数组来得到每个constructor的具体信息,如构造器名称或者参数类型等
// 获取构造器名称
String constructorName = constructor.getName();
// 获取参数类型
Class<?>[] parameterTypes = constructor.getParameterTypes();
// 获取修饰符
int modifiers = constructor.getModifiers();
String modifierStr = Modifier.toString(modifiers);
反射的优缺点
- 优点
- 动态性:反射允许程序在运行时动态地加载类、调用方法、操作字段,提高了程序的灵活性。
- 通用性:反射可以编写通用的工具类,例如 JSON 序列化/反序列化工具、ORM 框架等。
- 扩展性:反射可以加载外部类或插件,实现程序的扩展
- 缺点
- 性能开销:反射操作比直接调用方法或访问字段慢,因为 JVM 无法优化反射调用。
- 安全性问题:反射可以访问私有字段和方法,破坏了封装性,可能导致安全问题。
- 代码可读性差:反射代码通常比较复杂,可读性和可维护性较差。

浙公网安备 33010602011771号