目录
Bean Copy常见工具类
硬编码
手动get、set,性能最高,但写起来麻烦。
MapStruct(推荐)
- 需要引入依赖、自行定义mapper接口;
- 编译时自动生成硬编码方式的拷贝,性能几乎可以媲美硬编码;
- 可以拷贝普通对象、Collection,不能拷贝Map;
- 支持自定义转换,扩展性好;
使用可参考:https://blog.csdn.net/chy_18883701161/article/details/127916574
cglib的BeanCopier
- 基于动态代理实现,性能不错;支持自定义转换器,可扩展;
- 只能拷贝普通对象,不能拷贝Collection、Map
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
//参数依次指定源类、目标类、是否使用转换器
BeanCopier beanCopier = BeanCopier.create(UserOrderBo.class, UserOrderVo.class, false);
//参数分别为source、target、转换器,返回值void,需要目标对象已存在
beanCopier.copy(userOrderBo, userOrderVo, null);
spring-beans的BeanUtils
- 基于反射实现,性能一般;
- 只能拷贝普通对象,不能拷贝Collection、Map
//参数依次指定source、target,返回值void,需要target已存在
BeanUtils.copyProperties(userBo, userVo);
//可以指定要忽略的属性,参数个数可变
BeanUtils.copyProperties(userBo, userVo, "password", "tel");
apache的BeanUtils
基于反射实现,性能极差,避免使用
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
</dependency>
浅拷贝与深拷贝
拷贝都是新建目标类实例,浅拷贝、深拷贝的区别在于引用类型的成员字段的复制方式不同
- 浅拷贝:字段都是直接拷贝引用(地址),和原成员字段指向的堆中的同一个对象,优点是开销小、速度快、性能好,缺点是通过其中一个引用修改堆中对象时,会影响到指向这个对象的其它引用;
- 深拷贝:引用类型的成员变量会重新创建实例,开销大、速度慢,但更安全,可以避免共用堆中对象导致的问题。
以上介绍的几种bean copy方式都是浅拷贝,通常出于性能考虑,也是使用浅拷贝,除非特殊情况
使用Object的clone()方法实现浅拷贝
根类 Object 的 clone() 方法是 native 方法,速度快、性能高
//实现标记接口 Cloneable
public class User implements Cloneable {
//修改访问权限为public,把返回值转换为具体类型,方法体中调用根类Object的clone()方法
@Override
public User clone() throws CloneNotSupportedException {
return (User) super.clone();
}
}
通过反序列化实现深拷贝
反序列化是深拷贝的,这也是实现深拷贝最常见的方式
/**
* 操作对象的工具类
*/
public class ObjectUtil {
/**
* 深拷贝对象
*
* @param source 源对象
* @param <T> 目标类型
* @return 深拷贝得到的对象
* @throws IOException, ClassNotFoundException
*/
public static <T> T deepClone(T source) throws IOException, ClassNotFoundException {
//序列化源对象
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(source);
//反序列化得到新对象
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
T target = (T) ois.readObject();
ois.close();
oos.close();
return target;
}
}