java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java Bean所有拷贝方式使用

Java Bean所有拷贝方式使用方法及性能比较详解

作者:猩火燎猿

在Java开发中,常常需要将一个对象的属性值拷贝到另一个对象中,下面这篇文章主要介绍了Java Bean所有拷贝方式使用方法及性能比较的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下

一、总体概述及比较

1. 手动拷贝

方式说明最原始也最灵活的方法,直接通过setter和getter手动赋值。

示例代码

TargetBean target = new TargetBean();
target.setName(source.getName());
target.setAge(source.getAge());

优点

缺点

适用场景

2. Java BeanUtils 工具类

2.1 Apache Commons BeanUtils

方式说明使用 org.apache.commons.beanutils.BeanUtils 进行属性拷贝。

示例代码

import org.apache.commons.beanutils.BeanUtils;
BeanUtils.copyProperties(target, source);

优点

缺点

适用场景

2.2 Spring BeanUtils

方式说明使用 org.springframework.beans.BeanUtils 进行属性拷贝。

示例代码

import org.springframework.beans.BeanUtils;
BeanUtils.copyProperties(source, target);

优点

缺点

适用场景

3. CGLIB BeanCopier

方式说明使用 CGLIB 的 BeanCopier,通过动态生成字节码实现高性能拷贝。

示例代码

import net.sf.cglib.beans.BeanCopier;
BeanCopier copier = BeanCopier.create(Source.class, Target.class, false);
copier.copy(source, target, null);

优点

缺点

适用场景

4. MapStruct

方式说明MapStruct 是编译期代码生成的Bean拷贝工具,支持复杂映射和自定义转换。

示例代码

@Mapper
public interface UserMapper {
    UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);
    TargetBean toTargetBean(SourceBean source);
}

使用:

TargetBean target = UserMapper.INSTANCE.toTargetBean(source);

优点

缺点

适用场景

5. Dozer

方式说明Dozer 是一个支持深度拷贝的 Java Bean 到 Java Bean 的映射工具。

示例代码

Mapper mapper = new DozerBeanMapper();
TargetBean target = mapper.map(source, TargetBean.class);

优点

缺点

适用场景

6. ModelMapper

方式说明ModelMapper 也是一个Java Bean映射工具,支持复杂映射和类型转换。

示例代码

ModelMapper modelMapper = new ModelMapper();
TargetBean target = modelMapper.map(source, TargetBean.class);

优点

缺点

适用场景

7. Lombok @Builder/@Data + 构造方法

方式说明利用 Lombok 注解简化代码,通过构造方法或Builder模式实现对象转换。

示例代码

TargetBean target = TargetBean.builder()
    .name(source.getName())
    .age(source.getAge())
    .build();

优点

缺点

8. JSON序列化反序列化

方式说明通过Jackson、Gson等将对象转为JSON再反序列化为目标类型。

示例代码

ObjectMapper mapper = new ObjectMapper();
TargetBean target = mapper.readValue(mapper.writeValueAsString(source), TargetBean.class);

优点

缺点

9. 总结对比表

方式性能深拷贝复杂映射依赖库适用场景
手动拷贝支持支持灵活性强、属性少
BeanUtilscommons/spring简单Bean拷贝
CGLIB BeanCopiercglib大批量拷贝
MapStruct极高支持支持mapstruct大型项目、复杂转换
Dozer一般支持支持dozer深拷贝、复杂映射
ModelMapper一般支持支持modelmapper灵活映射
Lombok Builder支持lombok属性少、代码简洁
JSON序列化支持支持jackson/gson临时、简单深拷贝

10. 选择建议

二、使用详解

1、Spring BeanUtils 详细用法

1.1. 基本用法

import org.springframework.beans.BeanUtils;

SourceBean source = new SourceBean();
TargetBean target = new TargetBean();
BeanUtils.copyProperties(source, target);

注意:属性名和类型需完全一致,且只做浅拷贝(即对象属性只拷贝引用)。

1.2. 拷贝部分属性

可以指定忽略某些属性:

BeanUtils.copyProperties(source, target, "password", "id");

1.3. 常见问题

2、Apache Commons BeanUtils 详细用法

2.1. 基本用法

import org.apache.commons.beanutils.BeanUtils;

BeanUtils.copyProperties(target, source);

2.2. 类型转换

BeanUtils会自动做一些类型转换(如 String 转 int),但不支持复杂类型。

2.3. 性能问题

BeanUtils 采用反射,性能较低,不推荐在高频场景下使用

3、CGLIB BeanCopier 进阶用法

3.1. 基本用法

BeanCopier copier = BeanCopier.create(SourceBean.class, TargetBean.class, false);
copier.copy(source, target, null);

3.2. 支持自定义转换

BeanCopier copier = BeanCopier.create(SourceBean.class, TargetBean.class, true);
copier.copy(source, target, (value, targetType, context) -> {
    // 自定义转换逻辑
    if (value instanceof String && targetType == Integer.class) {
        return Integer.valueOf((String)value);
    }
    return value;
});

3.3. 性能优势

BeanCopier会动态生成字节码,性能极高,适合大批量拷贝。

4、MapStruct 进阶用法

4.1. 基本映射

@Mapper
public interface UserMapper {
    UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);
    TargetBean toTargetBean(SourceBean source);
}

4.2. 字段名不一致映射

@Mapper
public interface UserMapper {
    @Mapping(source = "username", target = "name")
    TargetBean toTargetBean(SourceBean source);
}

4.3. 自定义类型转换

@Mapper
public interface UserMapper {
    @Mapping(source = "age", target = "ageStr")
    TargetBean toTargetBean(SourceBean source);

    default String intToString(int age) {
        return String.valueOf(age);
    }
}

4.4. 集合转换

List<TargetBean> toTargetBeanList(List<SourceBean> sourceList);

4.5. 注意事项

5、Dozer/ModelMapper 进阶用法

5.1. Dozer XML 配置

<mapping>
    <class-a>com.example.SourceBean</class-a>
    <class-b>com.example.TargetBean</class-b>
    <field>
        <a>username</a>
        <b>name</b>
    </field>
</mapping>

5.2. ModelMapper 映射规则

modelMapper.typeMap(SourceBean.class, TargetBean.class)
    .addMappings(mapper -> mapper.map(SourceBean::getUsername, TargetBean::setName));

5.3. 支持复杂对象和嵌套属性

适合复杂领域模型转换,但性能一般。

6、JSON序列化方式进阶

6.1. Jackson

ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(source);
TargetBean target = mapper.readValue(json, TargetBean.class);

6.2. Gson

Gson gson = new Gson();
String json = gson.toJson(source);
TargetBean target = gson.fromJson(json, TargetBean.class);

6.3. 注意事项

7、Lombok Builder/构造方法进阶

7.1. Lombok简化代码

@Getter
@Setter
@Builder
public class TargetBean {
    private String name;
    private int age;
}

拷贝:

TargetBean target = TargetBean.builder()
    .name(source.getName())
    .age(source.getAge())
    .build();

7.2. 适合场景

8、实战建议

9、注意事项与最佳实践

三、常见问题与解决办法

1. 字段名不一致

问题:源对象和目标对象字段名不同,常规工具(如Spring BeanUtils)无法自动拷贝。

解决方案

2. 类型不一致

问题:如源对象字段为String,目标对象为Integer

解决方案

3. 嵌套对象或集合

问题:如源对象有嵌套对象或集合,浅拷贝只拷贝引用。

解决方案

4. 性能瓶颈

问题:反射类工具在大数据量场景下性能不足。

解决方案

5. Null值处理

问题:拷贝时源对象字段为null,目标对象是否需要覆盖?

解决方案

四、性能对比与实测

工具性能(高/中/低)备注
手动拷贝极高无反射,代码量大
CGLIB BeanCopier极高字节码生成,适合高并发
MapStruct极高编译期生成,适合复杂场景
Spring BeanUtils低~中反射实现,适合简单场景
Apache BeanUtils反射+类型转换,性能最差
Dozer/ModelMapper反射+复杂映射,灵活性高
JSON序列化适合临时深拷贝,性能低

实测建议

五、实际项目中的选择建议

六、自定义拷贝场景举例

1. 只拷贝非null字段

public static void copyNonNullProperties(Object src, Object target) {
    BeanWrapper srcWrap = new BeanWrapperImpl(src);
    BeanWrapper trgWrap = new BeanWrapperImpl(target);
    for (PropertyDescriptor pd : srcWrap.getPropertyDescriptors()) {
        Object value = srcWrap.getPropertyValue(pd.getName());
        if (value != null) {
            trgWrap.setPropertyValue(pd.getName(), value);
        }
    }
}

2. 字段名映射(MapStruct示例)

@Mapper
public interface MyMapper {
    @Mappings({
        @Mapping(source = "userName", target = "name"),
        @Mapping(source = "userAge", target = "age")
    })
    TargetBean toTarget(SourceBean source);
}

3. 嵌套对象拷贝(MapStruct示例)

@Mapper
public interface OrderMapper {
    OrderDTO toDTO(Order order);
    AddressDTO addressToDTO(Address address);
}

MapStruct会自动递归调用addressToDTO。

七、最佳实践

八、参考工具封装(示例)

public class BeanCopyUtil {
    public static <T> T copy(Object source, Class<T> clazz) {
        try {
            T target = clazz.newInstance();
            BeanUtils.copyProperties(source, target);
            return target;
        } catch (Exception e) {
            throw new RuntimeException("Bean copy failed", e);
        }
    }
}

可根据实际需要扩展支持MapStruct、CGLIB等。

到此这篇关于Java Bean所有拷贝方式使用方法及性能比较详解的文章就介绍到这了,更多相关Java Bean所有拷贝方式使用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文