反射实战:对象属性复制工具类

下面将逐步实现一个基于Java反射的简单对象属性复制工具类。该工具类会复制源对象中与目标对象属性名相同且类型兼容的属性值(包括私有属性)。

核心实现步骤
  1. 获取Class对象
    通过getClass()获取源对象和目标对象的Class信息

  2. 获取字段列表
    使用getDeclaredFields()获取所有字段(包括私有字段)

  3. 字段匹配与复制

    • 遍历源对象字段
    • 在目标对象中查找同名字段
    • 检查类型兼容性
    • 通过setAccessible(true)解除访问限制
    • 复制属性值
完整代码实现
import java.lang.reflect.Field;

public class BeanCopyUtil {
    
    /**
     * 复制源对象属性到目标对象(同名且类型兼容的属性)
     * @param source 源对象
     * @param target 目标对象
     */
    public static void copyProperties(Object source, Object target) {
        if (source == null || target == null) return;
        
        Class<?> sourceClass = source.getClass();
        Class<?> targetClass = target.getClass();
        
        // 遍历源对象所有字段
        for (Field sourceField : sourceClass.getDeclaredFields()) {
            try {
                // 获取目标对象同名字段
                Field targetField;
                try {
                    targetField = targetClass.getDeclaredField(sourceField.getName());
                } catch (NoSuchFieldException e) {
                    continue; // 跳过不存在的字段
                }
                
                // 检查类型兼容性(包括自动装箱/拆箱)
                if (!isCompatibleType(sourceField.getType(), targetField.getType())) {
                    continue;
                }
                
                // 解除访问限制
                sourceField.setAccessible(true);
                targetField.setAccessible(true);
                
                // 复制属性值
                Object value = sourceField.get(source);
                targetField.set(target, value);
                
            } catch (IllegalAccessException e) {
                // 处理访问异常
                System.err.println("属性复制失败: " + sourceField.getName());
            }
        }
    }
    
    /**
     * 检查类型兼容性(支持基本类型与包装类)
     * @param sourceType 源类型
     * @param targetType 目标类型
     * @return 是否兼容
     */
    private static boolean isCompatibleType(Class<?> sourceType, Class<?> targetType) {
        // 基本类型与包装类的兼容处理
        if (sourceType.isPrimitive()) {
            sourceType = convertPrimitiveToWrapper(sourceType);
        }
        if (targetType.isPrimitive()) {
            targetType = convertPrimitiveToWrapper(targetType);
        }
        // 检查类型匹配
        return targetType.isAssignableFrom(sourceType);
    }
    
    /**
     * 基本类型转包装类
     */
    private static Class<?> convertPrimitiveToWrapper(Class<?> type) {
        if (!type.isPrimitive()) return type;
        
        return switch (type.getName()) {
            case "int" -> Integer.class;
            case "long" -> Long.class;
            case "double" -> Double.class;
            case "float" -> Float.class;
            case "boolean" -> Boolean.class;
            case "byte" -> Byte.class;
            case "char" -> Character.class;
            case "short" -> Short.class;
            default -> type;
        };
    }
}

使用示例
class User {
    private String name;
    private int age;
    // 构造方法/getter/setter省略
}

class UserDTO {
    private String name;
    private int age;
    // 构造方法/getter/setter省略
}

public class Main {
    public static void main(String[] args) {
        User user = new User("张三", 25);
        UserDTO dto = new UserDTO();
        
        // 复制属性
        BeanCopyUtil.copyProperties(user, dto);
        
        System.out.println(dto.getName()); // 输出: 张三
        System.out.println(dto.getAge());  // 输出: 25
    }
}

关键特性说明
  1. 跨访问权限复制
    通过setAccessible(true)可复制私有字段

  2. 类型兼容处理
    支持以下类型匹配:

    • 相同类型(如StringString
    • 子类到父类(如ArrayListList
    • 基本类型与包装类互转(如intInteger
  3. 安全机制

    • 自动跳过不存在的字段
    • 跳过类型不兼容的字段
    • 异常捕获防止程序中断

注意:实际项目中建议使用成熟的工具库(如Spring的BeanUtils或Apache Commons的PropertyUtils),此示例主要用于理解反射机制。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐