java中无法自动反射复制不同类的相同属性,但可通过反射+属性名匹配实现字段级拷贝;推荐apache commons beanutils(简单稳妥)或mapstruct(编译期生成、类型安全)。

Java 中无法直接通过反射“自动”复制两个不同类的相同属性,但可以借助反射 + 属性名匹配的方式,快速实现字段级的同名属性拷贝。核心思路是:遍历源对象的可读字段(getter)或所有字段,找到目标类中同名且类型兼容的可写字段(setter),再通过反射调用完成赋值。
使用 Apache Commons BeanUtils(最简单)
这是最常用、最稳妥的方案,内部已处理类型转换、空值、嵌套属性等细节:
- 添加依赖(Maven):注意:BeanUtils 2.x 要求 JDK 8+,推荐用 commons-beanutils:1.9.4
- 确保两个类的属性名完全一致(如
userName↔userName),且有标准 getter/setter - 调用
BeanUtils.copyProperties(target, source)即可
示例:
Person person = new Person("Alice", 30);
UserDto dto = new UserDto();
BeanUtils.copyProperties(dto, person); // userName → userName, age → age
手写轻量反射工具(无依赖,可控性强)
适合不想引入第三方库、或需自定义逻辑(如忽略某些字段、强制类型转换)的场景:
- 获取源对象所有
public字段或通过getDeclaredFields()获取全部字段(设setAccessible(true)) - 对每个字段,检查目标类是否存在同名、可访问的 setter 方法(如
setUserName(String)) - 检查字段类型是否兼容(如
Integer→int可自动拆箱;String→LocalDateTime需额外解析) - 通过
Method.invoke(target, value)赋值
关键点:优先用 getter/setter(符合 JavaBean 规范),比直接操作字段更安全、更通用。
注意事项与避坑指南
反射拷贝不是万能的,这些情况必须手动处理:
-
属性名不一致:如
user_name(DB 字段)→userName(Java 字段),需自定义映射表或用注解(如@AliasFor) -
类型不兼容:如
Date↔LocalDateTime,需注册 Converter 或在拷贝前预处理 -
嵌套对象/集合:BeanUtils 默认只做浅拷贝;深层复制需递归调用或改用
Dozer、MapStruct等框架 - 性能敏感场景:反射开销较大;高频调用建议生成字节码(如 MapStruct 编译期生成)或缓存 Method 对象
进阶建议:用 MapStruct(编译期类型安全)
如果项目允许引入注解处理器,MapStruct 是更优选择:
- 在编译时生成纯 Java 拷贝代码,零反射、零运行时开销
- 支持自定义映射、表达式、日期格式转换、嵌套映射
- IDE 有提示和编译检查,类型错误在编码阶段暴露
只需写一个接口:
@Mapper
public interface UserMapper {
UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);
UserDto personToDto(Person person);
}
不复杂但容易忽略:真正“快速”不只看代码行数,更要看可维护性、健壮性和后续扩展成本。简单场景用 BeanUtils,中大型项目优先考虑 MapStruct。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











