大家常见的拷贝克隆的方法对于集合来说都是浅层拷贝即只是拷贝一个引用。
诸如:Collections.addAll() 、Collections.copy(des,src)、list.clone、new ArrayList(list)等都是浅层拷贝,这种很容易造成数据的不安全。
要安全的拷贝,深度的拷贝,要通过流-对象流。
笔者自己封装的深度拷贝工具类:
package com.wlt.collection;
import java.io.*;
import java.util.List;
/**
* 集合的普通拷贝克隆复制都是浅层的,下面介绍一种基于对象流的深度拷贝
* @author 魏霖涛
* @since 2018/2/28 0028
*/
public class DeepCopy {
public static <T> List<T> deepCopyList(List<T> source) throws IOException, ClassNotFoundException {
List<T> target;
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(source);
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
target = (List<T>) objectInputStream.readObject();
return target;
}
}
测试:
public static void main(String[] args) throws IOException, ClassNotFoundException {
WltDeepcopy wltClone = new WltDeepcopy("wlt");
System.out.println("deepCopy-集合使用-------------深度拷贝");
//Arrays.asList("1","2")返回的是只读的集合,而new ArrayList<>(Arrays.asList("1","2"))返回的是正常的集合
ArrayList list = new ArrayList(Arrays.asList(wltClone,"2"));
ArrayList clonelist = (ArrayList) deepCopyList(list);
System.out.println("modify---之前");
System.out.println(list);
System.out.println(clonelist);
System.out.println(list.hashCode());
System.out.println(clonelist.hashCode());
//下面这种是把集合元素的引用所指的对象属性改变,所以会引发连锁改变
((WltDeepcopy)list.get(0)).setName("modify");
//下面这种是直接把集合的引用给改变了,所以不会引发连锁改变
// list.set(0,new WltClone("happy"));
System.out.println("modify---之后");
System.out.println(list);
System.out.println(clonelist);
}
测试对象类:
class WltDeepcopy implements Serializable{
private String name;
public WltDeepcopy(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "WltClone{" +
"name='" + name + '\'' +
'}';
}
}
测试结果:
可以发现,拷贝之后的对象的hashcode(更正下,这边的hashcode是集合的hashcode,所以肯定是不一样的,拷贝后的对象,应该要把对象取出来打印对象的hashcode--2018/3/2)是不一样的,说明拷贝前后的对象不是同一个,修改其中一个属性,发现不会引发连锁改变。
2018/3/4更新 添加try-with-source自动关闭流
public static <T> List<T> deepCopyList(List<T> source) throws IOException, ClassNotFoundException {
List<T> target;
try(
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
){
objectOutputStream.writeObject(source);
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
target = (List<T>) objectInputStream.readObject();
return target;
}
}