小熊奶糖(BearCandy)
小熊奶糖(BearCandy)
发布于 2025-10-15 / 0 阅读
0
0

Java 反射详解

Java 反射详解

反射基础概念

什么是反射?

反射(Reflection)是Java在运行时:

  • 检查类、接口、字段和方法的能力
  • 动态创建对象、调用方法、访问和修改字段
  • 绕过访问权限检查(通过setAccessible(true))

反射的核心原理

// Java类加载过程
源代码(.java) → 编译 → 字节码(.class) → 类加载器 → 方法区(存储类信息)
                                                      ↓
                                                反射通过Class对象访问

反射核心API

1. 获取Class对象的三种方式

// 方式1: 类名.class
Class<String> stringClass = String.class;

// 方式2: 对象.getClass()
String str = "hello";
Class<?> clazz = str.getClass();

// 方式3: Class.forName()
Class<?> clazz = Class.forName("java.lang.String");

2. 类信息获取

Class<?> clazz = String.class;

// 获取类名
String className = clazz.getName();      // java.lang.String
String simpleName = clazz.getSimpleName(); // String

// 获取修饰符
int modifiers = clazz.getModifiers();
Modifier.isPublic(modifiers);  // 检查是否为public

// 获取包信息
Package pkg = clazz.getPackage();

// 获取父类
Class<?> superClass = clazz.getSuperclass();

// 获取实现的接口
Class<?>[] interfaces = clazz.getInterfaces();

3. 字段操作

Class<?> clazz = User.class;

// 获取所有公共字段(包括继承的)
Field[] publicFields = clazz.getFields();

// 获取所有字段(不包括继承的)
Field[] allFields = clazz.getDeclaredFields();

// 获取特定字段
Field nameField = clazz.getDeclaredField("name");

// 字段操作
User user = new User();
nameField.setAccessible(true);  // 突破私有访问限制
nameField.set(user, "张三");     // 设置字段值
Object value = nameField.get(user); // 获取字段值

4. 方法操作

Class<?> clazz = User.class;

// 获取所有公共方法
Method[] publicMethods = clazz.getMethods();

// 获取所有声明的方法
Method[] allMethods = clazz.getDeclaredMethods();

// 获取特定方法
Method setNameMethod = clazz.getMethod("setName", String.class);

// 方法调用
User user = new User();
setNameMethod.invoke(user, "李四");  // 调用方法

5. 构造器操作

Class<?> clazz = User.class;

// 获取所有公共构造器
Constructor<?>[] publicConstructors = clazz.getConstructors();

// 获取所有构造器
Constructor<?>[] allConstructors = clazz.getDeclaredConstructors();

// 获取特定构造器
Constructor<?> constructor = clazz.getDeclaredConstructor(String.class, int.class);

// 创建实例
constructor.setAccessible(true);  // 如果是私有构造器
User user = (User) constructor.newInstance("王五", 25);

反射应用场景

1. 框架开发

// Spring-like 依赖注入示例
public class SimpleContainer {
    private Map<String, Object> beans = new HashMap<>();
  
    public void registerBean(String name, Class<?> clazz) throws Exception {
        // 查找@Autowired注解的字段并自动注入
        Object instance = clazz.newInstance();
        Field[] fields = clazz.getDeclaredFields();
      
        for (Field field : fields) {
            if (field.isAnnotationPresent(Autowired.class)) {
                field.setAccessible(true);
                Object dependency = beans.get(field.getType().getSimpleName());
                field.set(instance, dependency);
            }
        }
        beans.put(name, instance);
    }
}

2. 动态代理

public class DynamicProxyHandler implements InvocationHandler {
    private Object target;
  
    public DynamicProxyHandler(Object target) {
        this.target = target;
    }
  
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 前置处理
        System.out.println("Before method: " + method.getName());
      
        // 调用实际方法
        Object result = method.invoke(target, args);
      
        // 后置处理
        System.out.println("After method: " + method.getName());
        return result;
    }
  
    public static Object createProxy(Object target) {
        return Proxy.newProxyInstance(
            target.getClass().getClassLoader(),
            target.getClass().getInterfaces(),
            new DynamicProxyHandler(target)
        );
    }
}

3. 注解处理器

// 自定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface JsonField {
    String value() default "";
}

// 注解处理器
public class JsonSerializer {
    public static String toJson(Object obj) throws Exception {
        StringBuilder json = new StringBuilder("{");
        Class<?> clazz = obj.getClass();
        Field[] fields = clazz.getDeclaredFields();
      
        for (Field field : fields) {
            if (field.isAnnotationPresent(JsonField.class)) {
                field.setAccessible(true);
                JsonField annotation = field.getAnnotation(JsonField.class);
                String fieldName = annotation.value().isEmpty() ? 
                    field.getName() : annotation.value();
              
                Object value = field.get(obj);
                json.append(String.format("\"%s\":\"%s\",", fieldName, value));
            }
        }
      
        if (json.charAt(json.length()-1) == ',') {
            json.deleteCharAt(json.length()-1);
        }
        json.append("}");
        return json.toString();
    }
}

4. 数据库ORM框架

// 简单的ORM映射
public class SimpleORM {
    public static <T> T mapResultSetToObject(ResultSet rs, Class<T> clazz) throws Exception {
        T instance = clazz.newInstance();
        ResultSetMetaData metaData = rs.getMetaData();
        int columnCount = metaData.getColumnCount();
      
        for (int i = 1; i <= columnCount; i++) {
            String columnName = metaData.getColumnName(i);
            Object columnValue = rs.getObject(i);
          
            // 根据列名找到对应字段
            Field field = findField(clazz, columnName);
            if (field != null) {
                field.setAccessible(true);
                field.set(instance, columnValue);
            }
        }
        return instance;
    }
  
    private static Field findField(Class<?> clazz, String columnName) {
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            if (field.getName().equalsIgnoreCase(columnName)) {
                return field;
            }
        }
        return null;
    }
}

代码示例

完整示例:反射工具类

public class ReflectionUtils {
  
    /**
     * 创建对象实例
     */
    public static Object newInstance(Class<?> clazz, Object... args) throws Exception {
        if (args == null || args.length == 0) {
            return clazz.newInstance();
        }
      
        Class<?>[] parameterTypes = new Class[args.length];
        for (int i = 0; i < args.length; i++) {
            parameterTypes[i] = args[i].getClass();
        }
      
        Constructor<?> constructor = clazz.getDeclaredConstructor(parameterTypes);
        constructor.setAccessible(true);
        return constructor.newInstance(args);
    }
  
    /**
     * 调用方法
     */
    public static Object invokeMethod(Object obj, String methodName, Object... args) throws Exception {
        Class<?>[] parameterTypes = new Class[args.length];
        for (int i = 0; i < args.length; i++) {
            parameterTypes[i] = args[i].getClass();
        }
      
        Method method = obj.getClass().getDeclaredMethod(methodName, parameterTypes);
        method.setAccessible(true);
        return method.invoke(obj, args);
    }
  
    /**
     * 设置字段值
     */
    public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
        Field field = obj.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(obj, value);
    }
  
    /**
     * 获取字段值
     */
    public static Object getFieldValue(Object obj, String fieldName) throws Exception {
        Field field = obj.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        return field.get(obj);
    }
  
    /**
     * 获取所有字段信息(包括父类)
     */
    public static List<Field> getAllFields(Class<?> clazz) {
        List<Field> fields = new ArrayList<>();
        Class<?> currentClass = clazz;
      
        while (currentClass != null && currentClass != Object.class) {
            fields.addAll(Arrays.asList(currentClass.getDeclaredFields()));
            currentClass = currentClass.getSuperclass();
        }
        return fields;
    }
}

// 测试类
class User {
    private String name;
    private int age;
  
    public User() {}
  
    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }
  
    private String getInfo() {
        return "User: " + name + ", Age: " + age;
    }
  
    // getter/setter省略
}

// 测试代码
public class ReflectionTest {
    public static void main(String[] args) throws Exception {
        // 创建实例
        User user = (User) ReflectionUtils.newInstance(User.class, "张三", 25);
      
        // 调用私有方法
        String info = (String) ReflectionUtils.invokeMethod(user, "getInfo");
        System.out.println(info);
      
        // 访问私有字段
        ReflectionUtils.setFieldValue(user, "name", "李四");
        String name = (String) ReflectionUtils.getFieldValue(user, "name");
        System.out.println("修改后的名字: " + name);
    }
}

注意事项

1. 性能问题

// 错误的用法 - 重复获取Method对象
for (int i = 0; i < 1000; i++) {
    Method method = clazz.getMethod("methodName");
    method.invoke(obj);
}

// 正确的用法 - 缓存Method对象
Method method = clazz.getMethod("methodName");
for (int i = 0; i < 1000; i++) {
    method.invoke(obj);
}

2. 安全限制

// 安全检查会降低性能
Method method = clazz.getDeclaredMethod("privateMethod");
method.setAccessible(true);  // 关闭安全检查可提升性能

// 但要注意:这会破坏封装性,应谨慎使用

3. 类型安全

// 反射绕过了编译期类型检查
Method method = clazz.getMethod("setName", String.class);
method.invoke(obj, 123);  // 运行时错误:参数类型不匹配

// 建议:进行参数类型验证
Object[] args = {123};
Class<?>[] parameterTypes = method.getParameterTypes();
if (!parameterTypes[0].isInstance(args[0])) {
    throw new IllegalArgumentException("参数类型不匹配");
}

4. 异常处理

try {
    Method method = clazz.getDeclaredMethod("methodName");
    method.invoke(obj);
} catch (NoSuchMethodException e) {
    // 方法不存在
    System.err.println("方法不存在: " + e.getMessage());
} catch (IllegalAccessException e) {
    // 访问权限不足
    System.err.println("访问被拒绝: " + e.getMessage());
} catch (InvocationTargetException e) {
    // 被调用方法抛出异常
    Throwable targetException = e.getTargetException();
    System.err.println("方法执行异常: " + targetException.getMessage());
}

性能优化

1. 缓存反射对象

public class ReflectionCache {
    private static final Map<String, Method> METHOD_CACHE = new ConcurrentHashMap<>();
    private static final Map<String, Field> FIELD_CACHE = new ConcurrentHashMap<>();
    private static final Map<String, Constructor<?>> CONSTRUCTOR_CACHE = new ConcurrentHashMap<>();
  
    public static Method getMethod(Class<?> clazz, String methodName, Class<?>... parameterTypes) 
            throws NoSuchMethodException {
        String key = generateKey(clazz, methodName, parameterTypes);
        return METHOD_CACHE.computeIfAbsent(key, k -> {
            try {
                Method method = clazz.getDeclaredMethod(methodName, parameterTypes);
                method.setAccessible(true);
                return method;
            } catch (NoSuchMethodException e) {
                throw new RuntimeException(e);
            }
        });
    }
  
    private static String generateKey(Class<?> clazz, String name, Class<?>... parameterTypes) {
        StringBuilder key = new StringBuilder(clazz.getName()).append(".").append(name);
        for (Class<?> paramType : parameterTypes) {
            key.append("_").append(paramType.getName());
        }
        return key.toString();
    }
}

2. 使用MethodHandle(Java 7+)

public class MethodHandleDemo {
    public static void methodHandleCall() throws Throwable {
        MethodHandles.Lookup lookup = MethodHandles.lookup();
        MethodType methodType = MethodType.methodType(String.class, String.class);
      
        MethodHandle methodHandle = lookup.findVirtual(String.class, "concat", methodType);
        String result = (String) methodHandle.invokeExact("Hello", " World");
        System.out.println(result);  // 输出: Hello World
    }
}

总结

反射的优点

  1. 灵活性:运行时动态操作类
  2. 通用性:编写通用框架和工具
  3. 扩展性:支持插件架构和动态加载

反射的缺点

  1. 性能开销:比直接调用慢
  2. 安全限制:可能破坏封装性
  3. 复杂度高:代码难以理解和维护
  4. 类型安全:绕过了编译期检查

最佳实践

  1. 尽量避免在性能敏感的代码中使用反射
  2. 缓存反射对象以提高性能
  3. 做好异常处理和边界检查
  4. 考虑使用替代方案(如MethodHandle)
  5. 明确使用反射的目的,不要滥用

重要提醒:反射是强大的工具,但应该谨慎使用。在大多数业务开发中,应优先考虑面向接口编程和其他设计模式,而不是过度依赖反射。


评论