1. 什么是反射
1.1 定义
反射(Reflection) 是 Java 提供的一种机制,允许程序在运行时检查和操作类、接口、字段、方法等程序结构。
简单来说:
- 编译时 :我们知道要调用哪个类的哪个方法 →
user.getName() - 运行时 :我们不知道具体类型,通过反射动态调用 →
method.invoke(user)
1.2 核心概念
┌─────────────────────────────────────────────┐
│ Java 反射机制 │
├─────────────────────────────────────────────┤
│ │
│ 源代码 (.java) │
│ ↓ 编译 │
│ 字节码 (.class) │
│ ↓ 类加载 │
│ Class 对象 (内存中的类元信息) │
│ ↓ 反射 │
│ 动态获取/调用 类的结构和行为 │
│ │
└─────────────────────────────────────────────┘
关键点:
- 每个类在 JVM 中都有一个对应的
Class对象 Class对象包含了类的所有元信息(字段、方法、构造器等)- 反射就是通过
Class对象来操作类
1.3 反射 vs 正常调用
java
// 正常调用(编译时确定)
User user = new User();
user.setName("张三");
String name = user.getName();
// 反射调用(运行时确定)
Class<?> clazz = Class.forName("com.example.User");
Object user = clazz.newInstance();
Method setName = clazz.getMethod("setName", String.class);
setName.invoke(user, "张三");
Method getName = clazz.getMethod("getName");
String name = (String) getName.invoke(user);
2. 为什么需要反射
2.1 典型应用场景
场景 1:框架开发
Spring IoC 容器:根据配置文件或注解动态创建对象
java
// Spring 容器内部简化实现
public Object getBean(String className) throws Exception {
// 1. 通过类名获取 Class 对象
Class<?> clazz = Class.forName(className);
// 2. 创建实例
Object bean = clazz.newInstance();
// 3. 依赖注入(查找 @Autowired 注解的字段)
for (Field field : clazz.getDeclaredFields()) {
if (field.isAnnotationPresent(Autowired.class)) {
field.setAccessible(true);
Object dependency = getBean(field.getType().getName());
field.set(bean, dependency);
}
}
return bean;
}
场景 2:ORM 框架
MyBatis/Hibernate:将数据库记录映射为 Java 对象
java
// 查询结果映射到对象
public <T> T mapResultToObject(ResultSet rs, Class<T> clazz) throws Exception {
T obj = clazz.newInstance();
// 遍历所有字段
for (Field field : clazz.getDeclaredFields()) {
field.setAccessible(true);
String columnName = field.getName();
Object value = rs.getObject(columnName);
field.set(obj, value);
}
return obj;
}
场景 3:动态代理
AOP 实现:在方法执行前后添加额外逻辑
java
// JDK 动态代理
Object proxy = Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
(proxy, method, args) -> {
System.out.println("方法执行前:" + method.getName());
Object result = method.invoke(target, args);
System.out.println("方法执行后:" + method.getName());
return result;
}
);
场景 4:序列化/反序列化
JSON 工具(Jackson、Gson):将对象转为 JSON 或从 JSON 创建对象
java
// 简化的 JSON 序列化
public String toJson(Object obj) throws Exception {
StringBuilder json = new StringBuilder("{");
Field[] fields = obj.getClass().getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
fields[i].setAccessible(true);
String name = fields[i].getName();
Object value = fields[i].get(obj);
json.append("\"").append(name).append("\":\"").append(value).append("\"");
if (i < fields.length - 1) json.append(",");
}
json.append("}");
return json.toString();
}
场景 5:插件化架构
动态加载插件:运行时加载 JAR 包中的类
java
// 插件加载器
public void loadPlugin(String jarPath, String className) throws Exception {
URLClassLoader classLoader = new URLClassLoader(
new URL[]{new File(jarPath).toURI().toURL()}
);
Class<?> pluginClass = classLoader.loadClass(className);
Object plugin = pluginClass.newInstance();
Method execute = pluginClass.getMethod("execute");
execute.invoke(plugin);
}
2.2 反射的核心价值
| 价值 | 说明 | 示例 |
|---|---|---|
| 动态性 | 运行时决定要操作的类 | 根据配置文件加载不同实现类 |
| 灵活性 | 无需修改代码即可改变行为 | 插件系统、热更新 |
| 通用性 | 编写通用框架和工具 | ORM、依赖注入、序列化 |
| 解耦性 | 降低模块间的耦合 | 面向接口编程 + 反射创建实例 |
3. 反射的核心 API
3.1 获取 Class 对象的三种方式
java
// 方式 1:通过类名.class(编译时已知类型)
Class<User> clazz1 = User.class;
// 方式 2:通过对象.getClass()(已有实例)
User user = new User();
Class<? extends User> clazz2 = user.getClass();
// 方式 3:通过 Class.forName()(运行时动态获取)
Class<?> clazz3 = Class.forName("com.example.User");
使用场景对比:
User.class:编译时确定,最快,用于泛型object.getClass():已有对象实例Class.forName():完全动态,最常用(配置文件、数据库驱动加载)
3.2 Class 类的核心方法
3.2.1 获取类信息
java
Class<?> clazz = User.class;
// 类名相关
String simpleName = clazz.getSimpleName(); // "User"
String name = clazz.getName(); // "com.example.User"
String canonicalName = clazz.getCanonicalName(); // "com.example.User"
// 包信息
Package pkg = clazz.getPackage();
String packageName = pkg.getName(); // "com.example"
// 修饰符
int modifiers = clazz.getModifiers();
boolean isPublic = Modifier.isPublic(modifiers);
boolean isAbstract = Modifier.isAbstract(modifiers);
// 父类和接口
Class<?> superClass = clazz.getSuperclass();
Class<?>[] interfaces = clazz.getInterfaces();
// 注解
Annotation[] annotations = clazz.getAnnotations();
boolean hasAnnotation = clazz.isAnnotationPresent(Entity.class);
3.2.2 获取构造器
java
// 获取所有 public 构造器
Constructor<?>[] constructors = clazz.getConstructors();
// 获取所有构造器(包括 private)
Constructor<?>[] allConstructors = clazz.getDeclaredConstructors();
// 获取指定参数的 public 构造器
Constructor<?> constructor = clazz.getConstructor(String.class, Integer.class);
// 获取指定参数的构造器(包括 private)
Constructor<?> declaredConstructor = clazz.getDeclaredConstructor(String.class);
// 创建实例
Object instance = constructor.newInstance("张三", 25);
getConstructors() vs getDeclaredConstructors():
getConstructors():只返回public构造器getDeclaredConstructors():返回所有构造器(包括private、protected、default)
3.2.3 获取字段
java
// 获取所有 public 字段(包括继承的)
Field[] fields = clazz.getFields();
// 获取所有字段(不包括继承的)
Field[] declaredFields = clazz.getDeclaredFields();
// 获取指定名称的 public 字段
Field field = clazz.getField("name");
// 获取指定名称的字段(包括 private)
Field declaredField = clazz.getDeclaredField("age");
// 操作字段
Object user = clazz.newInstance();
declaredField.setAccessible(true); // 关键:打破封装
declaredField.set(user, 25); // 设置值
Object age = declaredField.get(user); // 获取值
关键点:
setAccessible(true):绕过访问权限检查,可以访问private字段- 性能影响:会增加首次访问开销,但后续访问无影响
3.2.4 获取方法
java
// 获取所有 public 方法(包括继承的)
Method[] methods = clazz.getMethods();
// 获取所有方法(不包括继承的)
Method[] declaredMethods = clazz.getDeclaredMethods();
// 获取指定名称和参数的 public 方法
Method method = clazz.getMethod("setName", String.class);
// 获取指定名称和参数的方法(包括 private)
Method declaredMethod = clazz.getDeclaredMethod("calculateBonus", double.class);
// 调用方法
Object user = clazz.newInstance();
declaredMethod.setAccessible(true);
Object result = declaredMethod.invoke(user, 1000.0);
方法信息:
java
Method method = clazz.getMethod("login", String.class, String.class);
// 方法名
String methodName = method.getName();
// 返回类型
Class<?> returnType = method.getReturnType();
// 参数类型
Class<?>[] parameterTypes = method.getParameterTypes();
// 异常类型
Class<?>[] exceptionTypes = method.getExceptionTypes();
// 修饰符
int modifiers = method.getModifiers();
3.3 完整示例:反射操作类
java
public class User {
private Long id;
private String name;
private Integer age;
public User() {}
private User(String name) {
this.name = name;
}
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
private String getSecretInfo() {
return "这是私有方法";
}
// Getters and Setters...
}
// 反射操作
public class ReflectionDemo {
public static void main(String[] args) throws Exception {
// 1. 获取 Class 对象
Class<?> clazz = Class.forName("com.example.User");
// 2. 创建实例(调用无参构造器)
Object user1 = clazz.newInstance();
// 3. 调用私有构造器
Constructor<?> constructor = clazz.getDeclaredConstructor(String.class);
constructor.setAccessible(true);
Object user2 = constructor.newInstance("李四");
// 4. 设置私有字段
Field nameField = clazz.getDeclaredField("name");
nameField.setAccessible(true);
nameField.set(user1, "张三");
// 5. 调用公共方法
Method setAge = clazz.getMethod("setAge", Integer.class);
setAge.invoke(user1, 25);
// 6. 调用私有方法
Method getSecretInfo = clazz.getDeclaredMethod("getSecretInfo");
getSecretInfo.setAccessible(true);
String secret = (String) getSecretInfo.invoke(user1);
System.out.println("Secret: " + secret);
}
}
4. 反射的常见用法
4.1 动态创建对象
4.1.1 使用 newInstance()(已过时)
java
// JDK 9 之前
Class<?> clazz = User.class;
User user = (User) clazz.newInstance(); // 已过时,只能调用无参构造器
缺点:
- 只能调用无参构造器
- 如果无参构造器是私有的,会抛异常
- 无法传递构造参数
4.1.2 使用 Constructor(推荐)
java
// 推荐方式
Class<?> clazz = User.class;
// 调用指定参数的构造器
Constructor<?> constructor = clazz.getConstructor(String.class, Integer.class);
User user = (User) constructor.newInstance("张三", 25);
// 调用无参构造器
Constructor<?> noArgConstructor = clazz.getConstructor();
User user2 = (User) noArgConstructor.newInstance();
4.2 动态调用方法
java
public class MethodInvokeDemo {
public static void main(String[] args) throws Exception {
User user = new User("张三", 25);
Class<?> clazz = user.getClass();
// 1. 调用无参方法
Method getName = clazz.getMethod("getName");
String name = (String) getName.invoke(user);
// 2. 调用有参方法
Method setAge = clazz.getMethod("setAge", Integer.class);
setAge.invoke(user, 30);
// 3. 调用静态方法
Method staticMethod = clazz.getMethod("staticMethod", String.class);
staticMethod.invoke(null, "参数"); // 静态方法,第一个参数传 null
// 4. 调用私有方法
Method privateMethod = clazz.getDeclaredMethod("privateMethod");
privateMethod.setAccessible(true);
privateMethod.invoke(user);
}
}
4.3 动态访问字段
java
public class FieldAccessDemo {
public static void main(String[] args) throws Exception {
User user = new User();
Class<?> clazz = user.getClass();
// 1. 访问公共字段
Field publicField = clazz.getField("publicField");
publicField.set(user, "公共字段值");
Object value = publicField.get(user);
// 2. 访问私有字段
Field privateField = clazz.getDeclaredField("name");
privateField.setAccessible(true);
privateField.set(user, "张三");
String name = (String) privateField.get(user);
// 3. 访问静态字段
Field staticField = clazz.getDeclaredField("count");
staticField.setAccessible(true);
staticField.set(null, 100); // 静态字段,第一个参数传 null
}
}
4.4 获取泛型信息
java
public class GenericDemo {
private List<String> stringList;
private Map<String, User> userMap;
public static void main(String[] args) throws Exception {
Field stringListField = GenericDemo.class.getDeclaredField("stringList");
// 获取字段的泛型类型
Type genericType = stringListField.getGenericType();
if (genericType instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) genericType;
// 获取原始类型(List)
Type rawType = parameterizedType.getRawType();
System.out.println("Raw Type: " + rawType); // interface java.util.List
// 获取泛型参数(String)
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
for (Type typeArgument : actualTypeArguments) {
System.out.println("Type Argument: " + typeArgument); // class java.lang.String
}
}
// Map 的泛型
Field userMapField = GenericDemo.class.getDeclaredField("userMap");
Type mapGenericType = userMapField.getGenericType();
if (mapGenericType instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) mapGenericType;
Type[] typeArguments = parameterizedType.getActualTypeArguments();
System.out.println("Key Type: " + typeArguments[0]); // class java.lang.String
System.out.println("Value Type: " + typeArguments[1]); // class com.example.User
}
}
}
4.5 获取和处理注解
java
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Column {
String name() default "";
int length() default 255;
}
public class User {
@Column(name = "user_id", length = 20)
private Long id;
@Column(name = "user_name", length = 50)
private String name;
}
// 解析注解
public class AnnotationDemo {
public static void main(String[] args) throws Exception {
Class<?> clazz = User.class;
for (Field field : clazz.getDeclaredFields()) {
if (field.isAnnotationPresent(Column.class)) {
Column column = field.getAnnotation(Column.class);
String fieldName = field.getName();
String columnName = column.name();
int length = column.length();
System.out.println(fieldName + " -> " + columnName + " (" + length + ")");
}
}
}
}
// 输出:
// id -> user_id (20)
// name -> user_name (50)
4.6 数组操作
java
import java.lang.reflect.Array;
public class ArrayDemo {
public static void main(String[] args) {
// 1. 创建数组
Object array = Array.newInstance(String.class, 5);
// 2. 设置元素
Array.set(array, 0, "第一个元素");
Array.set(array, 1, "第二个元素");
// 3. 获取元素
String element = (String) Array.get(array, 0);
// 4. 获取数组长度
int length = Array.getLength(array);
// 5. 创建多维数组
Object multiArray = Array.newInstance(int.class, 3, 4);
System.out.println("Length: " + length);
System.out.println("Element: " + element);
}
}
5. 反射的底层原理
5.1 Class 对象的加载
┌─────────────────────────────────────────────────┐
│ JVM 类加载过程 │
├─────────────────────────────────────────────────┤
│ │
│ 1. 加载 (Loading) │
│ └─ 通过类加载器读取 .class 字节码 │
│ └─ 在堆中创建 java.lang.Class 对象 │
│ │
│ 2. 连接 (Linking) │
│ ├─ 验证:检查字节码格式和语义 │
│ ├─ 准备:为静态变量分配内存并设置默认值 │
│ └─ 解析:将符号引用转换为直接引用 │
│ │
│ 3. 初始化 (Initialization) │
│ └─ 执行静态初始化块和静态变量赋值 │
│ │
└─────────────────────────────────────────────────┘
Class 对象的特点:
- 每个类只有一个
Class对象(单例) Class对象存储在方法区(JDK 8+ 在元空间)- 包含类的所有元信息:字段、方法、构造器、注解等
5.2 反射调用的底层实现
5.2.1 Method.invoke() 的执行流程
java
// 用户代码
Method method = clazz.getMethod("sayHello", String.class);
method.invoke(obj, "World");
// Method.invoke() 内部实现(简化版)
public Object invoke(Object obj, Object... args) {
// 1. 权限检查
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
checkAccess(...);
}
// 2. 获取 MethodAccessor
MethodAccessor ma = methodAccessor;
if (ma == null) {
ma = acquireMethodAccessor(); // 首次调用,创建 Accessor
}
// 3. 委托给 MethodAccessor 执行
return ma.invoke(obj, args);
}
5.2.2 MethodAccessor 的两种实现
1. NativeMethodAccessorImpl(本地实现)
java
// 前 15 次调用使用 JNI(Java Native Interface)
class NativeMethodAccessorImpl extends MethodAccessorImpl {
public Object invoke(Object obj, Object[] args) {
// 调用 native 方法
return invoke0(method, obj, args);
}
private static native Object invoke0(Method m, Object obj, Object[] args);
}
特点:
- 直接调用 JVM 底层 C++ 代码
- 启动快,但执行慢(需要跨越 Java/Native 边界)
- 默认前 15 次调用使用
2. GeneratedMethodAccessor(动态生成)
java
// 第 16 次调用后,动态生成字节码
class GeneratedMethodAccessorXXX extends MethodAccessorImpl {
public Object invoke(Object obj, Object[] args) {
// 动态生成的字节码,直接调用目标方法
User target = (User) obj;
String arg0 = (String) args[0];
return target.sayHello(arg0); // 直接调用,无需 JNI
}
}
特点:
- 通过 ASM 等字节码工具动态生成
- 启动慢(生成字节码需要时间),但执行快
- 默认第 16 次调用后生成
5.2.3 为什么使用两种实现?
调用次数 | 实现方式 | 原因
---------|----------------------|------------------
1-15次 | NativeMethodAccessor | 避免字节码生成开销
16+次 | GeneratedMethodAccessor | 高频调用,字节码更快
Inflation 机制(膨胀机制):
- JVM 参数:
-Dsun.reflect.inflationThreshold=15(默认 15) - 设置为 0:立即生成字节码
- 设置为 Integer.MAX_VALUE:始终使用 Native 实现
5.3 反射性能分析
5.3.1 性能测试
java
public class ReflectionPerformanceTest {
public static void main(String[] args) throws Exception {
User user = new User();
Method method = User.class.getMethod("getName");
// 预热(触发字节码生成)
for (int i = 0; i < 20; i++) {
method.invoke(user);
}
int iterations = 10_000_000;
// 1. 直接调用
long start1 = System.nanoTime();
for (int i = 0; i < iterations; i++) {
String name = user.getName();
}
long time1 = System.nanoTime() - start1;
// 2. 反射调用(已生成字节码)
long start2 = System.nanoTime();
for (int i = 0; i < iterations; i++) {
method.invoke(user);
}
long time2 = System.nanoTime() - start2;
// 3. 反射调用(每次都 getMethod)
long start3 = System.nanoTime();
for (int i = 0; i < iterations; i++) {
Method m = User.class.getMethod("getName");
m.invoke(user);
}
long time3 = System.nanoTime() - start3;
System.out.println("直接调用:" + time1 / 1_000_000 + " ms");
System.out.println("反射调用(缓存):" + time2 / 1_000_000 + " ms");
System.out.println("反射调用(无缓存):" + time3 / 1_000_000 + " ms");
}
}
// 输出示例:
// 直接调用:3 ms
// 反射调用(缓存):15 ms (约 5 倍)
// 反射调用(无缓存):850 ms (约 280 倍)
5.3.2 性能开销来源
| 开销项 | 说明 | 优化方法 |
|---|---|---|
| 权限检查 | 每次调用都检查访问权限 | setAccessible(true) |
| 参数校验 | 检查参数类型和数量 | 无法优化 |
| 装箱/拆箱 | 基本类型需要装箱为 Object | 使用对象类型 |
| 方法查找 | getMethod() 查找方法 |
缓存 Method 对象 |
| 动态分派 | 无法内联优化 | 无法优化 |
5.4 setAccessible(true) 的原理
java
public class AccessibleDemo {
private String secretField = "机密";
public static void main(String[] args) throws Exception {
AccessibleDemo obj = new AccessibleDemo();
Field field = AccessibleDemo.class.getDeclaredField("secretField");
// 未设置 accessible,抛出 IllegalAccessException
// field.get(obj); // 报错
// 设置 accessible
field.setAccessible(true);
String value = (String) field.get(obj); // 成功
System.out.println(value);
}
}
setAccessible(true) 做了什么?
java
// AccessibleObject.java(Method、Field、Constructor 的父类)
public void setAccessible(boolean flag) {
// 1. 安全检查(SecurityManager)
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(ACCESS_PERMISSION);
}
// 2. 设置 override 标志
this.override = flag;
}
// 访问时检查
private void checkAccess(...) {
if (override) {
return; // 跳过权限检查
}
// 正常权限检查...
}
注意:
- JDK 9+:默认禁止反射访问 JDK 内部 API
- 启动参数:
--add-opens java.base/java.lang=ALL-UNNAMED
6. 实战案例
6.1 案例 1:简易 ORM 框架
需求
实现一个简单的 ORM 框架,能够:
- 将数据库查询结果映射为 Java 对象
- 将 Java 对象保存到数据库
实现
java
// 1. 自定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Table {
String value(); // 表名
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Column {
String value(); // 列名
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Id {
}
// 2. 实体类
@Table("tb_user")
public class User {
@Id
@Column("id")
private Long id;
@Column("user_name")
private String name;
@Column("age")
private Integer age;
@Column("email")
private String email;
// Getters and Setters...
}
// 3. ORM 核心实现
public class SimpleORM {
private DataSource dataSource;
public SimpleORM(DataSource dataSource) {
this.dataSource = dataSource;
}
/**
* 根据 ID 查询对象
*/
public <T> T findById(Class<T> clazz, Object id) throws Exception {
// 1. 获取表名
Table tableAnnotation = clazz.getAnnotation(Table.class);
if (tableAnnotation == null) {
throw new RuntimeException("实体类未标注 @Table 注解");
}
String tableName = tableAnnotation.value();
// 2. 找到主键字段
String idColumn = null;
for (Field field : clazz.getDeclaredFields()) {
if (field.isAnnotationPresent(Id.class)) {
Column column = field.getAnnotation(Column.class);
idColumn = column.value();
break;
}
}
if (idColumn == null) {
throw new RuntimeException("未找到 @Id 注解的字段");
}
// 3. 构建 SQL
String sql = "SELECT * FROM " + tableName + " WHERE " + idColumn + " = ?";
// 4. 执行查询
try (Connection conn = dataSource.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setObject(1, id);
try (ResultSet rs = pstmt.executeQuery()) {
if (rs.next()) {
return mapResultSetToObject(rs, clazz);
}
}
}
return null;
}
/**
* 将 ResultSet 映射为对象
*/
private <T> T mapResultSetToObject(ResultSet rs, Class<T> clazz) throws Exception {
// 1. 创建对象实例
T instance = clazz.getDeclaredConstructor().newInstance();
// 2. 遍历所有字段
for (Field field : clazz.getDeclaredFields()) {
if (field.isAnnotationPresent(Column.class)) {
Column column = field.getAnnotation(Column.class);
String columnName = column.value();
// 3. 从 ResultSet 获取值
Object value = rs.getObject(columnName);
// 4. 设置字段值
field.setAccessible(true);
field.set(instance, value);
}
}
return instance;
}
/**
* 插入对象
*/
public <T> int insert(T entity) throws Exception {
Class<?> clazz = entity.getClass();
// 1. 获取表名
Table tableAnnotation = clazz.getAnnotation(Table.class);
String tableName = tableAnnotation.value();
// 2. 收集字段和值
List<String> columns = new ArrayList<>();
List<Object> values = new ArrayList<>();
for (Field field : clazz.getDeclaredFields()) {
if (field.isAnnotationPresent(Column.class)) {
// 跳过自增主键
if (field.isAnnotationPresent(Id.class)) {
continue;
}
Column column = field.getAnnotation(Column.class);
columns.add(column.value());
field.setAccessible(true);
values.add(field.get(entity));
}
}
// 3. 构建 SQL
String columnStr = String.join(", ", columns);
String placeholders = String.join(", ", Collections.nCopies(columns.size(), "?"));
String sql = "INSERT INTO " + tableName + " (" + columnStr + ") VALUES (" + placeholders + ")";
// 4. 执行插入
try (Connection conn = dataSource.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
for (int i = 0; i < values.size(); i++) {
pstmt.setObject(i + 1, values.get(i));
}
return pstmt.executeUpdate();
}
}
/**
* 更新对象
*/
public <T> int update(T entity) throws Exception {
Class<?> clazz = entity.getClass();
// 1. 获取表名
Table tableAnnotation = clazz.getAnnotation(Table.class);
String tableName = tableAnnotation.value();
// 2. 收集字段、值和主键
List<String> setClauses = new ArrayList<>();
List<Object> values = new ArrayList<>();
Object idValue = null;
String idColumn = null;
for (Field field : clazz.getDeclaredFields()) {
if (field.isAnnotationPresent(Column.class)) {
Column column = field.getAnnotation(Column.class);
field.setAccessible(true);
Object value = field.get(entity);
if (field.isAnnotationPresent(Id.class)) {
idColumn = column.value();
idValue = value;
} else {
setClauses.add(column.value() + " = ?");
values.add(value);
}
}
}
// 3. 构建 SQL
String setClause = String.join(", ", setClauses);
String sql = "UPDATE " + tableName + " SET " + setClause + " WHERE " + idColumn + " = ?";
// 4. 执行更新
try (Connection conn = dataSource.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
for (int i = 0; i < values.size(); i++) {
pstmt.setObject(i + 1, values.get(i));
}
pstmt.setObject(values.size() + 1, idValue);
return pstmt.executeUpdate();
}
}
}
// 4. 使用示例
public class ORMTest {
public static void main(String[] args) throws Exception {
// 配置数据源
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/test");
config.setUsername("root");
config.setPassword("password");
DataSource dataSource = new HikariDataSource(config);
SimpleORM orm = new SimpleORM(dataSource);
// 查询
User user = orm.findById(User.class, 1L);
System.out.println("查询到用户:" + user.getName());
// 插入
User newUser = new User();
newUser.setName("李四");
newUser.setAge(30);
newUser.setEmail("lisi@example.com");
orm.insert(newUser);
// 更新
user.setAge(26);
orm.update(user);
}
}
关键技术点:
- 注解解析:通过反射获取类和字段上的注解
- 动态对象创建 :
clazz.getDeclaredConstructor().newInstance() - 字段赋值 :
field.set(instance, value) - SQL 生成:根据注解动态构建 SQL 语句
6.2 案例 2:通用 JSON 序列化工具
需求
实现一个简单的 JSON 序列化/反序列化工具
实现
java
public class SimpleJSON {
/**
* 对象转 JSON 字符串
*/
public static String toJson(Object obj) throws Exception {
if (obj == null) {
return "null";
}
Class<?> clazz = obj.getClass();
// 基本类型和包装类
if (clazz.isPrimitive() || obj instanceof Number || obj instanceof Boolean) {
return obj.toString();
}
// 字符串
if (obj instanceof String) {
return "\"" + escapeJson((String) obj) + "\"";
}
// 数组
if (clazz.isArray()) {
return arrayToJson(obj);
}
// 集合
if (obj instanceof Collection) {
return collectionToJson((Collection<?>) obj);
}
// Map
if (obj instanceof Map) {
return mapToJson((Map<?, ?>) obj);
}
// 普通对象
return objectToJson(obj);
}
/**
* 普通对象转 JSON
*/
private static String objectToJson(Object obj) throws Exception {
StringBuilder json = new StringBuilder("{");
Class<?> clazz = obj.getClass();
Field[] fields = clazz.getDeclaredFields();
boolean first = true;
for (Field field : fields) {
// 跳过静态字段
if (Modifier.isStatic(field.getModifiers())) {
continue;
}
field.setAccessible(true);
Object value = field.get(obj);
if (!first) {
json.append(",");
}
first = false;
json.append("\"").append(field.getName()).append("\":");
json.append(toJson(value));
}
json.append("}");
return json.toString();
}
/**
* 数组转 JSON
*/
private static String arrayToJson(Object array) throws Exception {
StringBuilder json = new StringBuilder("[");
int length = Array.getLength(array);
for (int i = 0; i < length; i++) {
if (i > 0) {
json.append(",");
}
Object element = Array.get(array, i);
json.append(toJson(element));
}
json.append("]");
return json.toString();
}
/**
* 集合转 JSON
*/
private static String collectionToJson(Collection<?> collection) throws Exception {
StringBuilder json = new StringBuilder("[");
boolean first = true;
for (Object element : collection) {
if (!first) {
json.append(",");
}
first = false;
json.append(toJson(element));
}
json.append("]");
return json.toString();
}
/**
* Map 转 JSON
*/
private static String mapToJson(Map<?, ?> map) throws Exception {
StringBuilder json = new StringBuilder("{");
boolean first = true;
for (Map.Entry<?, ?> entry : map.entrySet()) {
if (!first) {
json.append(",");
}
first = false;
json.append("\"").append(entry.getKey()).append("\":");
json.append(toJson(entry.getValue()));
}
json.append("}");
return json.toString();
}
/**
* JSON 字符串转对象
*/
public static <T> T fromJson(String json, Class<T> clazz) throws Exception {
// 简化实现:只处理对象(不处理数组、集合等)
json = json.trim();
if (!json.startsWith("{") || !json.endsWith("}")) {
throw new IllegalArgumentException("非法 JSON 格式");
}
// 创建对象实例
T instance = clazz.getDeclaredConstructor().newInstance();
// 去掉首尾的 {}
json = json.substring(1, json.length() - 1).trim();
if (json.isEmpty()) {
return instance;
}
// 简单解析(不考虑嵌套对象)
String[] pairs = json.split(",");
for (String pair : pairs) {
String[] kv = pair.split(":");
if (kv.length != 2) {
continue;
}
String key = kv[0].trim().replaceAll("\"", "");
String value = kv[1].trim().replaceAll("\"", "");
// 查找对应字段
try {
Field field = clazz.getDeclaredField(key);
field.setAccessible(true);
// 类型转换
Object convertedValue = convertValue(value, field.getType());
field.set(instance, convertedValue);
} catch (NoSuchFieldException e) {
// 忽略不存在的字段
}
}
return instance;
}
/**
* 值类型转换
*/
private static Object convertValue(String value, Class<?> targetType) {
if (targetType == String.class) {
return value;
} else if (targetType == Integer.class || targetType == int.class) {
return Integer.parseInt(value);
} else if (targetType == Long.class || targetType == long.class) {
return Long.parseLong(value);
} else if (targetType == Double.class || targetType == double.class) {
return Double.parseDouble(value);
} else if (targetType == Boolean.class || targetType == boolean.class) {
return Boolean.parseBoolean(value);
}
return value;
}
/**
* 转义 JSON 字符串
*/
private static String escapeJson(String str) {
return str.replace("\\", "\\\\")
.replace("\"", "\\\"")
.replace("\n", "\\n")
.replace("\r", "\\r")
.replace("\t", "\\t");
}
}
// 使用示例
public class JSONTest {
public static void main(String[] args) throws Exception {
User user = new User();
user.setId(1L);
user.setName("张三");
user.setAge(25);
user.setEmail("zhangsan@example.com");
// 序列化
String json = SimpleJSON.toJson(user);
System.out.println("JSON: " + json);
// 输出:{"id":1,"name":"张三","age":25,"email":"zhangsan@example.com"}
// 反序列化
User deserialized = SimpleJSON.fromJson(json, User.class);
System.out.println("Name: " + deserialized.getName());
}
}
关键技术点:
- 类型判断 :
clazz.isPrimitive()、instanceof、clazz.isArray() - 字段遍历 :
clazz.getDeclaredFields() - 跳过静态字段 :
Modifier.isStatic(field.getModifiers()) - 数组操作 :
Array.getLength()、Array.get() - 类型转换:根据字段类型转换字符串值
6.3 案例 3:依赖注入容器(简易版 Spring IoC)
需求
实现一个简单的依赖注入容器,支持:
- 自动扫描带
@Component注解的类 - 自动注入带
@Autowired注解的字段
实现
java
// 1. 自定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Component {
String value() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Autowired {
}
// 2. 示例服务类
@Component
public class UserService {
@Autowired
private UserRepository userRepository;
public void saveUser(User user) {
System.out.println("UserService.saveUser()");
userRepository.save(user);
}
}
@Component
public class UserRepository {
public void save(User user) {
System.out.println("UserRepository.save(): " + user.getName());
}
}
// 3. IoC 容器实现
public class SimpleIoCContainer {
// Bean 容器(单例)
private Map<Class<?>, Object> beans = new ConcurrentHashMap<>();
/**
* 扫描包下的所有类,创建 Bean
*/
public void scanPackage(String packageName) throws Exception {
// 1. 获取包路径
String packagePath = packageName.replace(".", "/");
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Enumeration<URL> resources = classLoader.getResources(packagePath);
// 2. 扫描所有类文件
while (resources.hasMoreElements()) {
URL resource = resources.nextElement();
File directory = new File(resource.getFile());
if (directory.exists()) {
scanDirectory(directory, packageName);
}
}
// 3. 依赖注入
injectDependencies();
}
/**
* 递归扫描目录
*/
private void scanDirectory(File directory, String packageName) throws Exception {
File[] files = directory.listFiles();
if (files == null) {
return;
}
for (File file : files) {
if (file.isDirectory()) {
scanDirectory(file, packageName + "." + file.getName());
} else if (file.getName().endsWith(".class")) {
// 类名
String className = packageName + "." + file.getName().replace(".class", "");
// 加载类
Class<?> clazz = Class.forName(className);
// 如果有 @Component 注解,创建实例
if (clazz.isAnnotationPresent(Component.class)) {
Object instance = clazz.getDeclaredConstructor().newInstance();
beans.put(clazz, instance);
System.out.println("创建 Bean: " + clazz.getSimpleName());
}
}
}
}
/**
* 依赖注入
*/
private void injectDependencies() throws Exception {
for (Object bean : beans.values()) {
Class<?> clazz = bean.getClass();
// 遍历所有字段
for (Field field : clazz.getDeclaredFields()) {
if (field.isAnnotationPresent(Autowired.class)) {
// 获取字段类型
Class<?> fieldType = field.getType();
// 从容器中查找依赖
Object dependency = getBean(fieldType);
if (dependency == null) {
throw new RuntimeException("找不到依赖: " + fieldType.getName());
}
// 注入依赖
field.setAccessible(true);
field.set(bean, dependency);
System.out.println("注入依赖: " + clazz.getSimpleName() + "." + field.getName()
+ " <- " + dependency.getClass().getSimpleName());
}
}
}
}
/**
* 获取 Bean
*/
@SuppressWarnings("unchecked")
public <T> T getBean(Class<T> clazz) {
return (T) beans.get(clazz);
}
}
// 4. 使用示例
public class IoCTest {
public static void main(String[] args) throws Exception {
// 创建容器
SimpleIoCContainer container = new SimpleIoCContainer();
// 扫描包
container.scanPackage("com.example.service");
// 获取 Bean
UserService userService = container.getBean(UserService.class);
// 调用方法
User user = new User();
user.setName("张三");
userService.saveUser(user);
}
}
// 输出:
// 创建 Bean: UserRepository
// 创建 Bean: UserService
// 注入依赖: UserService.userRepository <- UserRepository
// UserService.saveUser()
// UserRepository.save(): 张三
关键技术点:
- 包扫描 :通过
ClassLoader.getResources()获取包路径 - 类加载 :
Class.forName(className)动态加载类 - 注解检查 :
clazz.isAnnotationPresent(Component.class) - 对象创建 :
clazz.getDeclaredConstructor().newInstance() - 依赖注入 :查找
@Autowired字段并设置值
6.4 案例 4:动态代理实现 AOP
需求
实现一个简单的 AOP 框架,在方法执行前后添加日志
实现
java
// 1. 定义接口
public interface UserService {
void saveUser(User user);
User findUser(Long id);
}
// 2. 实现类
public class UserServiceImpl implements UserService {
@Override
public void saveUser(User user) {
System.out.println("保存用户: " + user.getName());
}
@Override
public User findUser(Long id) {
System.out.println("查询用户: " + id);
User user = new User();
user.setId(id);
user.setName("张三");
return user;
}
}
// 3. 方法拦截器接口
public interface MethodInterceptor {
Object intercept(Object target, Method method, Object[] args) throws Throwable;
}
// 4. 日志拦截器
public class LogInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object target, Method method, Object[] args) throws Throwable {
// 前置通知
System.out.println("[前置] 方法: " + method.getName() + ", 参数: " + Arrays.toString(args));
long start = System.currentTimeMillis();
Object result = null;
try {
// 执行目标方法
result = method.invoke(target, args);
// 返回通知
System.out.println("[返回] 方法: " + method.getName() + ", 返回值: " + result);
} catch (Exception e) {
// 异常通知
System.out.println("[异常] 方法: " + method.getName() + ", 异常: " + e.getMessage());
throw e;
} finally {
// 后置通知
long end = System.currentTimeMillis();
System.out.println("[后置] 方法: " + method.getName() + ", 耗时: " + (end - start) + "ms");
}
return result;
}
}
// 5. 代理工厂
public class ProxyFactory {
/**
* 创建代理对象(JDK 动态代理)
*/
public static <T> T createProxy(T target, MethodInterceptor interceptor) {
return (T) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
(proxy, method, args) -> interceptor.intercept(target, method, args)
);
}
}
// 6. 使用示例
public class AOPTest {
public static void main(String[] args) {
// 创建目标对象
UserService target = new UserServiceImpl();
// 创建代理对象
UserService proxy = ProxyFactory.createProxy(target, new LogInterceptor());
// 调用代理方法
User user = new User();
user.setName("李四");
proxy.saveUser(user);
System.out.println("=================");
User foundUser = proxy.findUser(1L);
System.out.println("Found: " + foundUser.getName());
}
}
// 输出:
// [前置] 方法: saveUser, 参数: [User{name='李四'}]
// 保存用户: 李四
// [返回] 方法: saveUser, 返回值: null
// [后置] 方法: saveUser, 耗时: 1ms
// =================
// [前置] 方法: findUser, 参数: [1]
// 查询用户: 1
// [返回] 方法: findUser, 返回值: User{id=1, name='张三'}
// [后置] 方法: findUser, 耗时: 0ms
// Found: 张三
进阶:支持多个拦截器(责任链模式)
java
public class InterceptorChain {
private List<MethodInterceptor> interceptors = new ArrayList<>();
private int currentIndex = 0;
private Object target;
private Method method;
private Object[] args;
public InterceptorChain(Object target, Method method, Object[] args) {
this.target = target;
this.method = method;
this.args = args;
}
public void addInterceptor(MethodInterceptor interceptor) {
interceptors.add(interceptor);
}
public Object proceed() throws Throwable {
if (currentIndex < interceptors.size()) {
// 执行下一个拦截器
MethodInterceptor interceptor = interceptors.get(currentIndex++);
return interceptor.intercept(target, method, args);
} else {
// 所有拦截器执行完毕,调用目标方法
return method.invoke(target, args);
}
}
}
// 修改拦截器接口
public interface MethodInterceptor {
Object intercept(InterceptorChain chain) throws Throwable;
}
// 日志拦截器
public class LogInterceptor implements MethodInterceptor {
@Override
public Object intercept(InterceptorChain chain) throws Throwable {
System.out.println("[日志] 前置");
Object result = chain.proceed(); // 继续执行链
System.out.println("[日志] 后置");
return result;
}
}
// 性能监控拦截器
public class PerformanceInterceptor implements MethodInterceptor {
@Override
public Object intercept(InterceptorChain chain) throws Throwable {
long start = System.currentTimeMillis();
Object result = chain.proceed();
long end = System.currentTimeMillis();
System.out.println("[性能] 耗时: " + (end - start) + "ms");
return result;
}
}
关键技术点:
- 动态代理 :
Proxy.newProxyInstance() - 反射调用 :
method.invoke(target, args) - 责任链模式:多个拦截器依次执行
7. 性能优化
7.1 缓存 Class、Method、Field 对象
java
// 不推荐:每次都查找
for (int i = 0; i < 10000; i++) {
Method method = clazz.getMethod("getName");
method.invoke(obj);
}
// 推荐:缓存 Method 对象
Method method = clazz.getMethod("getName");
for (int i = 0; i < 10000; i++) {
method.invoke(obj);
}
// 更推荐:使用缓存容器
public class ReflectionCache {
private static final Map<String, Method> methodCache = new ConcurrentHashMap<>();
public static Method getMethod(Class<?> clazz, String methodName, Class<?>... parameterTypes)
throws NoSuchMethodException {
String key = clazz.getName() + "#" + methodName + "#" + Arrays.toString(parameterTypes);
return methodCache.computeIfAbsent(key, k -> {
try {
return clazz.getMethod(methodName, parameterTypes);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
});
}
}
7.2 使用 setAccessible(true)
java
// 性能测试
Field field = clazz.getDeclaredField("name");
// 未设置 accessible
long start1 = System.nanoTime();
for (int i = 0; i < 100000; i++) {
try {
field.get(obj); // 每次都检查权限
} catch (IllegalAccessException e) {
// 忽略
}
}
long time1 = System.nanoTime() - start1;
// 设置 accessible
field.setAccessible(true);
long start2 = System.nanoTime();
for (int i = 0; i < 100000; i++) {
field.get(obj); // 跳过权限检查
}
long time2 = System.nanoTime() - start2;
System.out.println("未设置: " + time1 / 1_000_000 + "ms");
System.out.println("已设置: " + time2 / 1_000_000 + "ms");
7.3 使用 MethodHandle(JDK 7+)
MethodHandle 是比反射更快的方法调用方式
java
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
public class MethodHandleDemo {
public static void main(String[] args) throws Throwable {
User user = new User();
user.setName("张三");
// 1. 获取 MethodHandle
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodType methodType = MethodType.methodType(String.class);
MethodHandle getName = lookup.findVirtual(User.class, "getName", methodType);
// 2. 调用方法
String name = (String) getName.invoke(user);
System.out.println("Name: " + name);
// 性能测试
int iterations = 1_000_000;
// 直接调用
long start1 = System.nanoTime();
for (int i = 0; i < iterations; i++) {
String n = user.getName();
}
long time1 = System.nanoTime() - start1;
// 反射调用
Method method = User.class.getMethod("getName");
long start2 = System.nanoTime();
for (int i = 0; i < iterations; i++) {
method.invoke(user);
}
long time2 = System.nanoTime() - start2;
// MethodHandle 调用
long start3 = System.nanoTime();
for (int i = 0; i < iterations; i++) {
getName.invoke(user);
}
long time3 = System.nanoTime() - start3;
System.out.println("直接调用: " + time1 / 1_000_000 + "ms");
System.out.println("反射调用: " + time2 / 1_000_000 + "ms");
System.out.println("MethodHandle: " + time3 / 1_000_000 + "ms");
}
}
// 输出示例:
// 直接调用: 2ms
// 反射调用: 10ms
// MethodHandle: 5ms
MethodHandle vs 反射:
| 特性 | Method.invoke() | MethodHandle.invoke() |
|---|---|---|
| 性能 | 慢(约 5-10 倍) | 快(约 2-3 倍) |
| 类型检查 | 运行时 | 编译时 |
| 权限检查 | 每次调用 | 创建时一次 |
| JVM 优化 | 难以内联 | 可以内联 |
7.4 避免不必要的装箱/拆箱
java
// 不推荐:频繁装箱/拆箱
Method method = clazz.getMethod("setAge", Integer.class);
for (int i = 0; i < 100000; i++) {
method.invoke(obj, i); // int 自动装箱为 Integer
}
// 推荐:使用对象类型
Integer age = 25;
for (int i = 0; i < 100000; i++) {
method.invoke(obj, age);
}
7.5 使用并发容器缓存反射对象
java
public class OptimizedReflectionCache {
// 使用 ConcurrentHashMap 避免同步开销
private static final ConcurrentHashMap<String, Method> methodCache = new ConcurrentHashMap<>();
private static final ConcurrentHashMap<String, Field> fieldCache = new ConcurrentHashMap<>();
public static Method getCachedMethod(Class<?> clazz, String methodName, Class<?>... parameterTypes) {
String key = generateKey(clazz, methodName, parameterTypes);
return methodCache.computeIfAbsent(key, k -> {
try {
Method method = clazz.getMethod(methodName, parameterTypes);
method.setAccessible(true); // 提前设置
return method;
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
});
}
public static Field getCachedField(Class<?> clazz, String fieldName) {
String key = clazz.getName() + "#" + fieldName;
return fieldCache.computeIfAbsent(key, k -> {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true); // 提前设置
return field;
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
}
});
}
private static String generateKey(Class<?> clazz, String methodName, Class<?>... parameterTypes) {
return clazz.getName() + "#" + methodName + "#" + Arrays.toString(parameterTypes);
}
}
8. 最佳实践
8.1 谨慎使用 setAccessible(true)
风险:
- 破坏封装性
- 可能导致内部状态不一致
- JDK 9+ 模块化系统限制
建议:
java
// 1. 仅在必要时使用
if (field.isAccessible()) {
field.get(obj);
} else {
field.setAccessible(true);
try {
field.get(obj);
} finally {
field.setAccessible(false); // 恢复访问权限
}
}
// 2. JDK 9+ 处理模块化限制
try {
field.setAccessible(true);
} catch (InaccessibleObjectException e) {
// 提示用户添加 --add-opens 参数
System.err.println("请添加 JVM 参数: --add-opens " +
clazz.getModule().getName() + "/" +
clazz.getPackageName() + "=ALL-UNNAMED");
}
8.2 异常处理
java
// 不推荐:吞掉异常
try {
Method method = clazz.getMethod("getName");
method.invoke(obj);
} catch (Exception e) {
// 什么都不做
}
// 推荐:明确处理各种异常
try {
Method method = clazz.getMethod("getName");
return method.invoke(obj);
} catch (NoSuchMethodException e) {
throw new RuntimeException("方法不存在: getName", e);
} catch (IllegalAccessException e) {
throw new RuntimeException("无法访问方法: getName", e);
} catch (InvocationTargetException e) {
// 获取目标方法抛出的真实异常
Throwable targetException = e.getTargetException();
throw new RuntimeException("方法执行失败: " + targetException.getMessage(), targetException);
}
8.3 性能敏感场景避免反射
java
// 不推荐:高频调用使用反射
for (int i = 0; i < 1_000_000; i++) {
Method method = obj.getClass().getMethod("process");
method.invoke(obj);
}
// 推荐:使用接口或抽象类
interface Processor {
void process();
}
for (int i = 0; i < 1_000_000; i++) {
processor.process(); // 直接调用,JVM 可以内联优化
}
8.4 使用工具类库
Apache Commons BeanUtils:
java
// 简化属性操作
BeanUtils.setProperty(user, "name", "张三");
String name = BeanUtils.getProperty(user, "name");
// 对象克隆
User clonedUser = (User) BeanUtils.cloneBean(user);
// 属性复制
BeanUtils.copyProperties(dest, src);
Spring ReflectionUtils:
java
// 查找方法
Method method = ReflectionUtils.findMethod(User.class, "getName");
// 调用方法
ReflectionUtils.invokeMethod(method, user);
// 查找字段
Field field = ReflectionUtils.findField(User.class, "name");
// 设置字段
ReflectionUtils.setField(field, user, "张三");
// 遍历字段
ReflectionUtils.doWithFields(User.class, field -> {
System.out.println(field.getName());
});
8.5 线程安全
java
// 反射对象本身是线程安全的
private static final Method METHOD = User.class.getMethod("getName");
// 多线程调用同一个 Method 对象是安全的
public void threadSafeCall(User user) throws Exception {
String name = (String) METHOD.invoke(user); // 线程安全
}
// 但要注意缓存容器的线程安全
private static final Map<String, Method> cache = new ConcurrentHashMap<>(); // 推荐
// private static final Map<String, Method> cache = new HashMap<>(); // 不安全
9. 常见问题与解决方案
9.1 NoSuchMethodException
原因:方法不存在或参数类型不匹配
java
// 错误示例
Method method = clazz.getMethod("setAge", int.class); // 报错:找不到方法
// 正确示例
Method method = clazz.getMethod("setAge", Integer.class); // 使用包装类型
// 或者处理基本类型
Class<?>[] paramTypes = {int.class};
Method method = clazz.getMethod("setAge", paramTypes);
解决方案:
java
public Method findMethod(Class<?> clazz, String methodName, Class<?>... parameterTypes) {
try {
// 先尝试精确匹配
return clazz.getMethod(methodName, parameterTypes);
} catch (NoSuchMethodException e) {
// 遍历所有方法,模糊匹配
for (Method method : clazz.getMethods()) {
if (method.getName().equals(methodName) &&
isAssignable(method.getParameterTypes(), parameterTypes)) {
return method;
}
}
throw new RuntimeException("找不到方法: " + methodName);
}
}
private boolean isAssignable(Class<?>[] declaredTypes, Class<?>[] actualTypes) {
if (declaredTypes.length != actualTypes.length) {
return false;
}
for (int i = 0; i < declaredTypes.length; i++) {
if (!declaredTypes[i].isAssignableFrom(actualTypes[i])) {
return false;
}
}
return true;
}
9.2 IllegalAccessException
原因:访问权限不足(如访问 private 成员)
java
// 错误示例
Field field = clazz.getDeclaredField("privateField");
field.get(obj); // 报错:无法访问
// 解决方案
Field field = clazz.getDeclaredField("privateField");
field.setAccessible(true); // 关键:打破封装
field.get(obj); // 成功
9.3 InvocationTargetException
原因:目标方法内部抛出异常
java
public class User {
public void throwException() {
throw new RuntimeException("业务异常");
}
}
// 错误处理
try {
Method method = User.class.getMethod("throwException");
method.invoke(user);
} catch (Exception e) {
e.printStackTrace(); // 打印的是 InvocationTargetException
}
// 正确处理
try {
Method method = User.class.getMethod("throwException");
method.invoke(user);
} catch (InvocationTargetException e) {
Throwable cause = e.getCause(); // 获取真实异常
System.out.println("真实异常: " + cause.getMessage()); // "业务异常"
throw new RuntimeException(cause);
}
9.4 泛型擦除问题
问题:运行时无法获取泛型的具体类型
java
public class GenericClass<T> {
private T data;
// 错误:无法在运行时获取 T 的具体类型
public void wrongWay() {
// Class<T> clazz = T.class; // 编译错误
}
// 正确:通过字段的泛型签名获取
public Class<?> getGenericType() throws Exception {
Field field = this.getClass().getDeclaredField("data");
Type genericType = field.getGenericType();
if (genericType instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) genericType;
return (Class<?>) parameterizedType.getActualTypeArguments()[0];
}
return Object.class;
}
}
// 或者在构造时传入 Class 对象
public class GenericClass<T> {
private Class<T> type;
public GenericClass(Class<T> type) {
this.type = type;
}
public T createInstance() throws Exception {
return type.getDeclaredConstructor().newInstance();
}
}
// 使用
GenericClass<User> gc = new GenericClass<>(User.class);
User user = gc.createInstance();
9.5 性能问题
问题:反射调用比直接调用慢 5-10 倍
解决方案:
- 缓存反射对象
java
// 避免重复查找
private static final Map<String, Method> METHOD_CACHE = new ConcurrentHashMap<>();
- 使用 MethodHandle
java
// JDK 7+ 的高性能替代方案
MethodHandle handle = MethodHandles.lookup()
.findVirtual(User.class, "getName", MethodType.methodType(String.class));
- 预热
java
// 触发字节码生成
for (int i = 0; i < 20; i++) {
method.invoke(obj);
}
- 启动参数优化
bash
# 立即生成字节码
-Dsun.reflect.inflationThreshold=0
# 禁用权限检查(不推荐)
-Djava.security.manager=allow
9.6 JDK 9+ 模块化限制
问题:JDK 9+ 默认禁止反射访问 JDK 内部 API
java
// 错误示例
Field field = String.class.getDeclaredField("value");
field.setAccessible(true); // JDK 9+ 抛出 InaccessibleObjectException
解决方案:
- 添加 JVM 参数
bash
--add-opens java.base/java.lang=ALL-UNNAMED
--add-opens java.base/java.util=ALL-UNNAMED
- 代码处理
java
try {
field.setAccessible(true);
} catch (InaccessibleObjectException e) {
System.err.println("模块化限制,请添加 --add-opens 参数");
}
- 使用 VarHandle(JDK 9+)
java
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
VarHandle valueHandle = MethodHandles
.privateLookupIn(String.class, MethodHandles.lookup())
.findVarHandle(String.class, "value", byte[].class);
byte[] value = (byte[]) valueHandle.get(str);