在java中拷贝
是生成一个对象的副本,在工具类中提供了很多拷贝方法,需要知道他的底层原理,可能因为不知道原理,酿成大错。
浅拷贝
Object
提供了native clone()
方法,为浅拷贝。他返回Object
类型需要显示的进行对象转换。仔细看该方法是protected。子类无法直接调用,需要重写该方法,实现业务,也可以直接调用super.clone()
,并且该类需要实现Cloneable
接口,标识该类支持clone。否则会抛出java.lang.CloneNotSupportedException
异常,依赖于Object
类的实现,得到的是一个浅拷贝对象。
验证代码:
/**
* 描述:
*
* @author liweigao
* @create 2018-07-25 下午6:04
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Person implements Serializable, Cloneable {
private static final long serialVersionUID = 2L;
private int age;
private String name;
private List<String> hobbies;
@Override
public Person clone() throws CloneNotSupportedException {
return (Person) super.clone();
}
}
/**
* 描述:
*
* @author liweigao
* @create 2018-07-25 下午6:05
*/
public class Sample {
public static void main(String[] args) throws CloneNotSupportedException, InterruptedException, Exception {
List<String> hobbies = Lists.newArrayList("play Basketball");
Person person = Person.builder().age(10).name("li").hobbies(hobbies).build();
Person personClone = person.clone();
hobbies.add("play ping-pong");
System.out.println(JSON.toJSONString(person));
System.out.println(JSON.toJSONString(personClone));
}
}
测试输出:
origin: {"age":10,"hobbies":["play Basketball","play ping-pong"],"name":"li"}
copyPojo: {"age":10,"hobbies":["play Basketball","play ping-pong"],"name":"li"}
发现修改hobbies
属性personClone
对象也发生了变化,所以Object提供的clone()
方法返回的是浅拷贝对象。
深拷贝
深拷贝实现,当复制的对象包涵其他一些对象时(类似:person中包涵hobbies属性
),它的引用将以深层副本的形式递归复制,如果使用不当将会造成循环依赖,上一篇 浅谈序列化-Serialization 可以利用序列化来可以重建该对象,它隐式的实现了深复制并且优雅的处理了深复制循环依赖。
添加deepClone()
方法
//利用序列化来实现深拷贝
public Person deepClone() throws Exception {
ByteArrayOutputStream bos = null;
ObjectOutputStream oos = null;
ByteArrayInputStream bis = null;
ObjectInputStream ois = null;
try {
bos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bos);
oos.writeObject(this);
oos.flush();
bis = new ByteArrayInputStream(bos.toByteArray());
ois = new ObjectInputStream(bis);
return (Person) ois.readObject();
} finally {
if (ois != null) {
ois.close();
}
if (bis != null) {
bis.close();
}
if (oos != null) {
oos.close();
}
if (bos != null) {
bos.close();
}
}
}
/**
* 描述:
*
* @author liweigao
* @create 2018-07-25 下午6:05
*/
public class Sample {
public static void main(String[] args) throws CloneNotSupportedException, InterruptedException, Exception {
List<String> hobbies = Lists.newArrayList("play Basketball");
Person person = Person.builder().age(10).name("li").hobbies(hobbies).build();
Person personClone = person.deepClone();
hobbies.add("play ping-pong");
System.out.println("origin: " + JSON.toJSONString(person));
System.out.println("copyPojo: " + JSON.toJSONString(personClone));
}
}
测试输出:
origin: {"age":10,"hobbies":["play Basketball","play ping-pong"],"name":"li"}
copyPojo: {"age":10,"hobbies":["play Basketball"],"name":"li"}
为此实现深拷贝
注意 克隆不用于实例化和初始化对象,因为克隆对象在创建中构造函数永远不会被调用(我们可以修改构造函数为私有的来验证),拷贝只用于对象的复制,而并非是创建。
个人看法,以上多多批评!谢谢。