Java 反射
目录
- 什么是反射
- 反射的核心类
- Class 类
- 简介
- 获取 Class 对象
- 常用方法
- Constructor 类
- 简介
- 常用方法
- 示例
- 获取 public 无参构造器
- 获取 private 有参构造器
- 获取所有构造器
- Field 类
- 简介
- 获取 Field 对象
- 常用方法
- 示例
- 操作静态字段
- Method 类
- 作用
- 获取 Method 对象的方式
- 常用方法
- 示例
- Modifier 类
- 作用
- 常见修饰符
- 常用方法
- 示例
- Array 类
- 作用
- 常用方法
- 使用示例
- 反射的性能影响
- 反射的底层实现机制
- 反射实战
- 框架实现 IOC 容器
- 实现 ORM 框架的实体与数据库映射
- 通用 Bean 属性拷贝工具
- 动态调用插件类(插件机制、热加载)
- JDK 动态代理(AOP、事务、日志)
- 实现通用 JSON 序列化工具
- 反射操作数组(不确定类型的数组操作)
什么是反射
反射是 Java 提供的一种强大机制,允许在运行时动态获取类的信息、动态创建对象、调用方法、访问字段等
反射的核心类
Class 类
简介
Java 一切类在 JVM 中都是 Class
类的实例
作用:获取类的所有信息(字段、方法、构造器、注解、父类、接口等)
获取 Class 对象
Class<?> clazz = Class.forName("com.example.User");
常用方法
// 获取类的完全限定名(包含包名)
clazz.getName();
// 例:com.example.User// 获取类的简单名(不包含包名)
clazz.getSimpleName();
// 例:User// 获取类的包名(Java 9 以后推荐用 getPackageName)
clazz.getPackageName();
// 例:com.example// 获取类中所有 public 的成员变量(包括继承自父类的 public 成员)
clazz.getFields(); // 获取类中声明的所有成员变量(不论权限,private、protected、public、default),但不包括继承自父类的
clazz.getDeclaredFields();// 获取类中所有 public 的方法(包括继承自父类的 public 方法)
clazz.getMethods(); // 获取类中声明的所有方法(不论权限,private、protected、public、default),但不包括继承的
clazz.getDeclaredMethods(); // 获取类中所有 public 的构造方法
clazz.getConstructors(); // 获取类的直接父类(如果没有则返回 null,像 Object)
clazz.getSuperclass(); // 获取类实现的所有接口(不包括父类实现的接口)
clazz.getInterfaces();
Constructor 类
简介
- 代表类的构造方法
- 用于获取、操作类的构造器,动态创建实例
- 即使构造器是私有的,也可以通过反射访问
常用方法
方法 | 说明 |
---|---|
getConstructor(参数类型...) | 获取 public 构造器 |
getDeclaredConstructor(参数类型...) | 获取指定参数的构造器(包括 private ) |
getConstructors() | 获取所有 public 构造器 |
getDeclaredConstructors() | 获取所有构造器(包括 private ) |
示例
class User {private String name;private int age;// 无参构造public User() {this.name = "默认名";}// 有参构造private User(String name, int age) {this.name = name;this.age = age;}public void show() {System.out.println("User{name='" + name + "', age=" + age + "}");}
}
获取 public 无参构造器
Class<User> clazz = User.class;
Constructor<User> constructor = clazz.getConstructor();
User user = constructor.newInstance();
user.show();
获取 private 有参构造器
Constructor<User> privateConstructor = clazz.getDeclaredConstructor(String.class, int.class);
privateConstructor.setAccessible(true);
User user2 = privateConstructor.newInstance("张三", 20);
user2.show();
获取所有构造器
Constructor<?>[] constructors = clazz.getDeclaredConstructors();
for (Constructor<?> cons : constructors) {System.out.println(cons);
}
Field 类
简介
- 用于表示并操作类的成员变量(包括
public
、private
、protected
、static
等) - 支持对字段进行 动态获取、读取、修改、访问控制破坏
获取 Field 对象
方法 | 说明 |
---|---|
getField(String name) | 获取 public 字段 |
getDeclaredField(String name) | 获取任意字段(包括 private 、protected ) |
getFields() | 获取所有 public 字段 |
getDeclaredFields() | 获取所有字段(包括 private 、protected ) |
常用方法
方法 | 说明 |
---|---|
get(Object obj) | 获取字段值 |
set(Object obj, Object value) | 设置字段值 |
getType() | 获取字段类型 |
getModifiers() | 获取字段修饰符 |
setAccessible(true) | 破坏封装,允许访问 private 字段 |
getName() | 获取字段名 |
isAnnotationPresent() | 判断字段上是否有某个注解 |
示例
class User {public String username;private int age;@Deprecatedprivate String secret = "秘密";
}
获取并操作public
字段
Class<User> clazz = User.class;
Field field = clazz.getField("username");User user = new User();
field.set(user, "张三");
String value = (String) field.get(user);System.out.println("用户名: " + value);
获取并操作private
字段
Field privateField = clazz.getDeclaredField("age");
privateField.setAccessible(true); // 破坏封装
privateField.set(user, 20);
int age = (int) privateField.get(user);System.out.println("年龄: " + age);
获取字段信息
Field field = clazz.getDeclaredField("secret");
System.out.println("字段名: " + field.getName());
System.out.println("字段类型: " + field.getType());
System.out.println("修饰符: " + Modifier.toString(field.getModifiers()));
判断注解
if (field.isAnnotationPresent(Deprecated.class)) {System.out.println("该字段已被标记为 Deprecated");
}
操作静态字段
Field staticField = MyClass.class.getDeclaredField("STATIC_FIELD");
staticField.setAccessible(true);
staticField.set(null, "新值"); // 静态字段 obj 传 null
Method 类
作用
Method
是 java.lang.reflect
包中的类
表示类中的一个成员方法(实例方法、静态方法)
可以通过 Method
类动态调用对象的方法,即使是私有方法
获取 Method 对象的方式
方法 | 说明 |
---|---|
getMethod(String name, Class<?>... parameterTypes) | 获取 public 方法(包括父类方法) |
getDeclaredMethod(String name, Class<?>... parameterTypes) | 获取当前类声明的方法(包括 private ) |
getMethods() | 获取所有 public 方法(包括继承自父类) |
getDeclaredMethods() | 获取当前类声明的所有方法(包括 private ) |
常用方法
方法 | 说明 |
---|---|
invoke(Object obj, Object... args) | 调用该方法 |
getName() | 获取方法名 |
getReturnType() | 获取返回类型 |
getParameterTypes() | 获取参数类型数组 |
getModifiers() | 获取方法修饰符 |
setAccessible(true) | 破坏封装,允许访问 private 方法 |
isAnnotationPresent() | 判断方法上是否存在指定注解 |
示例
class User {public void sayHello(String name) {System.out.println("Hello, " + name);}private int add(int a, int b) {return a + b;}
}
获取并调用 public
方法
Class<User> clazz = User.class;
Method method = clazz.getMethod("sayHello", String.class);User user = new User();
method.invoke(user, "张三");
获取并调用 private
方法
Method privateMethod = clazz.getDeclaredMethod("add", int.class, int.class);
privateMethod.setAccessible(true);
int result = (int) privateMethod.invoke(user, 5, 3);System.out.println("加法结果: " + result);
获取方法信息
Method method = clazz.getDeclaredMethod("add", int.class, int.class);
System.out.println("方法名: " + method.getName());
System.out.println("返回类型: " + method.getReturnType());
System.out.println("参数类型: " + Arrays.toString(method.getParameterTypes()));
System.out.println("修饰符: " + Modifier.toString(method.getModifiers()));
判断注解
if (method.isAnnotationPresent(Deprecated.class)) {System.out.println("该方法已过时");
}
Modifier 类
作用
位于 java.lang.reflect
包。
用于解析类、方法、字段、构造器等的访问修饰符(例如 public
、private
、static
、final
、abstract
等)。
通过该类可以将修饰符的 int 值转换为可读的字符串,并进行修饰符检查。
常见修饰符
常量 | 十进制值 | 说明 |
---|---|---|
Modifier.PUBLIC | 1 | public |
Modifier.PRIVATE | 2 | private |
Modifier.PROTECTED | 4 | protected |
Modifier.STATIC | 8 | static |
Modifier.FINAL | 16 | final |
Modifier.SYNCHRONIZED | 32 | synchronized |
Modifier.VOLATILE | 64 | volatile |
Modifier.TRANSIENT | 128 | transient |
Modifier.ABSTRACT | 1024 | abstract |
Modifier.INTERFACE | 512 | interface |
Modifier.NATIVE | 256 | native |
常用方法
方法 | 说明 |
---|---|
toString(int mod) | 将修饰符 int 值转为字符串 |
isPublic(int mod) | 判断是否是 public |
isPrivate(int mod) | 判断是否是 private |
isProtected(int mod) | 判断是否是 protected |
isStatic(int mod) | 判断是否是 static |
isFinal(int mod) | 判断是否是 final |
isAbstract(int mod) | 判断是否是 abstract |
isSynchronized(int mod) | 判断是否是 synchronized |
isNative(int mod) | 判断是否是 native |
isVolatile(int mod) | 判断是否是 volatile |
isTransient(int mod) | 判断是否是 transient |
isInterface(int mod) | 判断是否是接口 |
示例
public class User {private static final String NAME = "张三";public void sayHello() {}
}
示例代码
Class<User> clazz = User.class;// 获取字段修饰符
Field field = clazz.getDeclaredField("NAME");
int fieldModifiers = field.getModifiers();
System.out.println("字段修饰符: " + Modifier.toString(fieldModifiers));
System.out.println("是否是 static: " + Modifier.isStatic(fieldModifiers));
System.out.println("是否是 final: " + Modifier.isFinal(fieldModifiers));// 获取方法修饰符
Method method = clazz.getMethod("sayHello");
int methodModifiers = method.getModifiers();
System.out.println("方法修饰符: " + Modifier.toString(methodModifiers));
System.out.println("是否是 public: " + Modifier.isPublic(methodModifiers));
输出
字段修饰符: private static final
是否是 static: true
是否是 final: true
方法修饰符: public
是否是 public: true
Array 类
作用
- 提供在运行时动态创建、访问、修改数组的方法
- 支持任意类型、任意维度的数组操作
- 解决反射场景下无法直接操作数组的问题
常用方法
方法 | 说明 |
---|---|
newInstance(Class<?> componentType, int length) | 创建一维数组 |
newInstance(Class<?> componentType, int... dimensions) | 创建多维数组 |
get(Object array, int index) | 获取数组中的元素 |
set(Object array, int index, Object value) | 设置数组中的元素 |
getLength(Object array) | 获取数组长度 |
使用示例
动态创建一维数组
int[] intArray = (int[]) Array.newInstance(int.class, 5);Array.set(intArray, 0, 10);
Array.set(intArray, 1, 20);System.out.println(Array.get(intArray, 0)); // 10
System.out.println(Array.get(intArray, 1)); // 20
System.out.println("数组长度: " + Array.getLength(intArray)); // 5
动态创建多维数组
int[][] matrix = (int[][]) Array.newInstance(int.class, 3, 3);Array.set(Array.get(matrix, 0), 0, 100);
System.out.println(((int[]) Array.get(matrix, 0))[0]); // 100
获取数组信息
String[] strs = new String[]{"A", "B", "C"};
System.out.println("数组类型: " + strs.getClass().getName());
System.out.println("数组长度: " + Array.getLength(strs));
反射的性能影响
- 反射比直接调用慢(通常慢 10-20 倍),但合理使用影响可以接受
- 使用缓存可以降低反射带来的性能损耗
MethodHandle
、LambdaMetafactory
可替代部分反射,性能更优
反射的底层实现机制
- 反射通过 JVM 提供的元数据实现(类的元信息、方法表、字段表)
- 访问字段、方法底层通过
Unsafe
、JNI 实现直接操作内存 Class
类是所有类的元数据载体
反射实战
框架实现 IOC 容器
- 反射用于根据配置或注解,动态创建对象并注入到容器
示例:
public class BeanFactory {public static Object createBean(String className) throws Exception {Class<?> clazz = Class.forName(className);return clazz.getDeclaredConstructor().newInstance();}public static void main(String[] args) throws Exception {Object obj = createBean("java.util.ArrayList");System.out.println(obj.getClass().getName()); // java.util.ArrayList}
}
实现 ORM 框架的实体与数据库映射
- 反射读取实体类字段,自动生成 SQL 语句,自动赋值
示例
public static void printInsertSQL(Object obj) throws Exception {Class<?> clazz = obj.getClass();StringBuilder sb = new StringBuilder("INSERT INTO ");sb.append(clazz.getSimpleName()).append(" VALUES(");Field[] fields = clazz.getDeclaredFields();for (Field field : fields) {field.setAccessible(true);sb.append("'").append(field.get(obj)).append("', ");}sb.setLength(sb.length() - 2); // 移除最后的逗号sb.append(")");System.out.println(sb);
}class User {private String name = "张三";private int age = 20;
}printInsertSQL(new User());
// INSERT INTO User VALUES('张三', '20')
通用 Bean 属性拷贝工具
- 反射实现对象属性值的动态拷贝
示例
public static void copyProperties(Object source, Object target) throws Exception {Class<?> clazz = source.getClass();for (Field field : clazz.getDeclaredFields()) {field.setAccessible(true);Object value = field.get(source);field.set(target, value);}
}class Person {private String name = "李四";private int age = 30;
}Person p1 = new Person();
Person p2 = new Person();
copyProperties(p1, p2);
动态调用插件类(插件机制、热加载)
- 反射动态加载指定类并调用其方法,不需要预编译绑定
示例:
public static void executePlugin(String className, String methodName) throws Exception {Class<?> clazz = Class.forName(className);Object obj = clazz.getDeclaredConstructor().newInstance();Method method = clazz.getDeclaredMethod(methodName);method.invoke(obj);
}class MyPlugin {public void run() {System.out.println("插件启动");}
}executePlugin("MyPlugin", "run");
// 插件启动
JDK 动态代理(AOP、事务、日志)
- 反射是动态代理的基础,动态创建代理对象
示例(简化版):
import java.lang.reflect.*;interface Service {void doSomething();
}class ServiceImpl implements Service {public void doSomething() {System.out.println("执行业务逻辑");}
}Service proxy = (Service) Proxy.newProxyInstance(ServiceImpl.class.getClassLoader(),new Class[]{Service.class},(proxyObj, method, args1) -> {System.out.println("开始事务");Object result = method.invoke(new ServiceImpl(), args1);System.out.println("提交事务");return result;}
);proxy.doSomething();
// 开始事务
// 执行业务逻辑
// 提交事务
实现通用 JSON 序列化工具
- 反射获取字段并转成 JSON
示例:
public static String toJson(Object obj) throws Exception {Class<?> clazz = obj.getClass();StringBuilder sb = new StringBuilder("{");for (Field field : clazz.getDeclaredFields()) {field.setAccessible(true);sb.append("\"").append(field.getName()).append("\":\"").append(field.get(obj)).append("\",");}sb.setLength(sb.length() - 1);sb.append("}");return sb.toString();
}class Book {private String title = "Java核心技术";private double price = 99.9;
}System.out.println(toJson(new Book()));
// {"title":"Java核心技术","price":"99.9"}
反射操作数组(不确定类型的数组操作)
- 例如构建任意类型、任意长度的数组
示例:
Object array = Array.newInstance(String.class, 5);
Array.set(array, 0, "Hello");
System.out.println(Array.get(array, 0)); // Hello