深度拷贝与浅度拷贝的区别主要在于有没有为拷贝出的新对象在堆中重新分配一块内存区域。
浅度拷贝 :直接赋值,拷贝的只是原始对象的引用地址,在堆中仍然共用一块内存。
深度拷贝 : 新对象在堆中重新分配一块内存,所以对新对象的操作不会影响原始对象。
深度拷贝几种方法
1. 使用Java序列化方法#
想要深拷贝一个对象,常用的方法是序列化为数据流,此方法的前提是对象以及对象中包含的子对象都要继承Serializable接口。
/**
* 深层拷贝 - 需要类继承序列化接口
* @param <T>
* @param obj
* @return
* @throws Exception
*/
public static <T> T copyImplSerializable(T obj) throws Exception {
ByteArrayOutputStream baos = null;
ObjectOutputStream oos = null;
ByteArrayInputStream bais = null;
ObjectInputStream ois = null;
Object o = null;
try {
baos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(baos);
oos.writeObject(obj);
bais = new ByteArrayInputStream(baos.toByteArray());
ois = new ObjectInputStream(bais);
o = ois.readObject();
return (T) o;
} catch (Exception e) {
throw new Exception("对象中包含没有继承序列化的对象");
} finally{
try {
baos.close();
oos.close();
bais.close();
ois.close();
} catch (Exception e2) {
}
}
}
2. 利用Kryo序列化框架#
Kryo是一个快速高效的Java序列化框架,旨在提供快速、高效和易用的API。无论文件、数据库或网络数据Kryo都可以随时完成序列化。Kryo还可以执行自动深拷贝(克隆)、浅拷贝(克隆)。这是对象到对象的直接拷贝,非对象->字节->对象的拷贝。该方法不需要继承Serializable接口。
<dependency>
<groupId>com.esotericsoftware</groupId>
<artifactId>kryo</artifactId>
<version>4.x.x</version>
</dependency>
public static T copyByKryo(T source){
Kryo kryo = new Kryo();
return kryo.copy(source);
}
3. 利用Json转化的方法
如果对象没有继承Serializable接口,可以先将对象转化为JSON,再序列化为对象,和第一种方法类似。Json转换工具可以用Jackson或者Json-lib,本文选择Json-lib只需要在maven里面添加以下依赖:
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>x.x</version>
<classifier>jdk15</classifier>
</dependency>
public static <T> T copyByJson(T obj) throws Exception {
return (T)JSONObject.toBean(JSONObject.fromObject(obj),obj.getClass());
}
4. 手动New对象的方法
手动new对象,将属性值挨个调用set方法,比较繁琐。
参考: https://www.cnblogs.com/coderzhw/p/11094284.html#3757894395