Java 反射完全指南 - 原理与实战

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():返回所有构造器(包括 privateprotecteddefault
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);
    }
}

关键技术点

  1. 注解解析:通过反射获取类和字段上的注解
  2. 动态对象创建clazz.getDeclaredConstructor().newInstance()
  3. 字段赋值field.set(instance, value)
  4. 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());
    }
}

关键技术点

  1. 类型判断clazz.isPrimitive()instanceofclazz.isArray()
  2. 字段遍历clazz.getDeclaredFields()
  3. 跳过静态字段Modifier.isStatic(field.getModifiers())
  4. 数组操作Array.getLength()Array.get()
  5. 类型转换:根据字段类型转换字符串值

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(): 张三

关键技术点

  1. 包扫描 :通过 ClassLoader.getResources() 获取包路径
  2. 类加载Class.forName(className) 动态加载类
  3. 注解检查clazz.isAnnotationPresent(Component.class)
  4. 对象创建clazz.getDeclaredConstructor().newInstance()
  5. 依赖注入 :查找 @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;
    }
}

关键技术点

  1. 动态代理Proxy.newProxyInstance()
  2. 反射调用method.invoke(target, args)
  3. 责任链模式:多个拦截器依次执行

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 倍

解决方案

  1. 缓存反射对象
java 复制代码
// 避免重复查找
private static final Map<String, Method> METHOD_CACHE = new ConcurrentHashMap<>();
  1. 使用 MethodHandle
java 复制代码
// JDK 7+ 的高性能替代方案
MethodHandle handle = MethodHandles.lookup()
    .findVirtual(User.class, "getName", MethodType.methodType(String.class));
  1. 预热
java 复制代码
// 触发字节码生成
for (int i = 0; i < 20; i++) {
    method.invoke(obj);
}
  1. 启动参数优化
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

解决方案

  1. 添加 JVM 参数
bash 复制代码
--add-opens java.base/java.lang=ALL-UNNAMED
--add-opens java.base/java.util=ALL-UNNAMED
  1. 代码处理
java 复制代码
try {
    field.setAccessible(true);
} catch (InaccessibleObjectException e) {
    System.err.println("模块化限制,请添加 --add-opens 参数");
}
  1. 使用 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);
相关推荐
我居然是兔子3 小时前
基于字符串的专项实验:解锁Java String类的隐藏细节
java·开发语言
Alice4 小时前
FVCOM Debug
开发语言·javascript·ecmascript
Mongnewer4 小时前
JAVA从0到1走过的小路
java·java从0到1
qq_433554544 小时前
C++状压DP
开发语言·c++
XXYBMOOO4 小时前
全面解析 Qt `QMessageBox` 类及其常用方法
开发语言·qt·microsoft
知行合一。。。4 小时前
Python--02--流程控制语句
开发语言·python
朝花不迟暮4 小时前
go的文件操作
开发语言·后端·golang
西西学代码4 小时前
Flutter---类
java·开发语言
码农小卡拉4 小时前
Java多线程:CompletableFuture使用详解(超详细)
java·开发语言·spring boot·python·spring·spring cloud