- 对象的浅拷贝、深拷贝
- 浅拷贝常见的实现方式
- 使用Object类的clone()方法
- apache的BeanUtils工具类
- spring的BeanUtils工具类
- hutool提供的BeanUtil
- 使用建议
- 深拷贝常见的实现方式
- 自行实现深拷贝
- hutool提供的ObjectUtil
对象的浅拷贝、深拷贝
- 浅拷贝:引用类型的成员变量是直接拷贝引用(地址),和原成员变量指向的堆中的同一个对象,优点是速度快,开销小,性能好
- 深拷贝:引用类型的成员变量是重新创建实例,速度慢,开销大,但更安全,可以避免共用对象导致的问题
vo、dto、po之间经常要复制属性进行转换,对象的转换、复制都可以使用getter、setter方法逐个复制属性,对于引用类型,浅拷贝是直接set get获取的引用,深拷贝是set设置new出来的新对象,但这种方式太繁琐,基本不用。
浅拷贝常见的实现方式 使用Object类的clone()方法
优点:根类的clone()是native方法,速度快、性能高
Object的clone是protected方法,只能在子类中使用,需要重写暴露给外部调用
@Data //需要实现标记接口 Cloneable,不然调用clone()会报异常 CloneNotSupportedException
public class User implements Cloneable {
//...
@Override
public User clone() throws CloneNotSupportedException {
return (User) super.clone();
}
}
apache的BeanUtils工具类
性能差,不推荐使用
spring的BeanUtils工具类
优点:不要求2个对象有相同的祖先类,直接拷贝匹配的属性,可用于类型转换;
缺点:提供的方法较少,只能拷贝普通对象,不能拷贝数组、Collection、Map。
//参数依次指定source、target BeanUtils.copyProperties(user, userVO); //可以指定要忽略的属性,参数个数可变 BeanUtils.copyProperties(user, userVO, "password", "tel");
hutool提供的BeanUtil
- 优点:提供的方法相对较多,支持拷贝Collection、Map
//source、target,map类型也可以用此方法拷贝 BeanUtil.copyProperties(user, userVO); //可以指定要忽略的属性 BeanUtil.copyProperties(user, userVO, "password", "tel"); //可以指定字段名是否忽略大小写 BeanUtil.copyProperties(user, userVO, true); //拷贝Collection,数组可以先转换为list再拷贝 ListuserVOList = BeanUtil.copyToList(userList, userVO.class); //Convert.convert() 转换类型,也可以实现浅拷贝 //参数指定目标类型、源对象 User user1 = Convert.convert(User.class, user);
使用建议
spring的BeanUtils、hutool的BeanUtil 对代码侵入最小、使用简单、功能丰富,拷贝普通对象都可以使用,拷贝数组、Collection、Map用 hutool的BeanUtil。
深拷贝常见的实现方式
IO流传输对象时使用的是深拷贝,典型方式是对象的序列化、反序列化,这也是最常见的深拷贝方式,需要注意的是 源类要是可序列化的。
没必要重写每个要深拷贝的类的clone()方法,编码量大、很麻烦,通常是提到工具类中
public class ObjectUtil {
public static T clone(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;
}
}
hutool提供的ObjectUtil
User user1 = ObjectUtil.cloneByStream(user);
实质也是基于序列化、反序列化实现的



