一、深拷贝和浅拷贝的区别
-
浅拷贝:对基本数据类型进行值传递,对引用数据类型进行引用传递般的拷贝,此为浅拷贝。
-
深拷贝:对基本数据类型进行值传递,对引用数据类型,创建一个新的对象,并复制其内容,此为深拷贝。
重点:深拷贝和浅拷贝最根本的区别在于是否真正获取一个对象的复制实体,而不是引用。
1、假设B复制了A,修改A的时候,看B是否发生变化:
2、如果B跟着也变了,说明是浅拷贝(修改堆内存中的同一个值)
3、如果B没有改变,说明是深拷贝(修改堆内存中的不同的值)
-
浅拷贝(shallowCopy)只是增加了一个指针指向已存在的内存地址。
-
深拷贝(deepCopy)是增加了一个指针并且申请了一个新的内存,使这个增加的指针指向这个新的内存。
-
深拷贝是指源对象与拷贝对象互相独立,其中任何一个对象的改动都不会对另外一个对象造成影响。
-
使用深拷贝的情况下,释放内存的时候不会因为出现浅拷贝时释放同一个内存的错误。
二、深拷贝实现方式
2.1 构造函数
@org.junit.Test
public void constructorCopy() {
//被克隆的类
Student xiaoMing = new Student("小明");
// 调用构造函数时进行深拷贝
Student cloneStudent = new Student(xiaoMing.getName());
System.out.println(xiaoMing == cloneStudent); // false
}
2.2 重载clone()方法
Object类有个clone()的拷贝方法,不过它是protected类型的,我们需要重写它并修改为public类型。除此之外,子类还需要实现Cloneable接口来告诉JVM这个类是可以拷贝的。
public class Student implements Cloneable {
private String name;
public Student(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// 重写克隆方法
@Override
public Student clone() throws CloneNotSupportedException {
return (Student) super.clone();
}
}
2.3 Apache Commons Lang序列化
Java提供了序列化的能力,我们可以先将源对象进行序列化,再反序列化生成拷贝对象。但是,使用序列化的前提是拷贝的类(包括其成员变量)需要实现Serializable接口。Apache Commons Lang包对Java序列化进行了封装,我们可以直接使用它。
@org.junit.Test
public void coneableCopy() throws CloneNotSupportedException {
// 被克隆的类
Student xiaoMing = new Student("小明");
// 使用Apache Commons Lang序列化进行深拷贝
Student copyStudent = (Student) SerializationUtils.clone(xiaoMing);
System.out.println(xiaoMing == copyStudent);
}
2.4 Gson
Gson可以将对象序列化成JSON,也可以将JSON反序列化成对象,所以我们可以用它进行深拷贝。
@org.junit.Test
public void coneableCopy() throws CloneNotSupportedException {
//被克隆的类
Student xiaoMing = new Student("小明");
// 使用Gson序列化进行深拷贝
Gson gson = new Gson();
Student copyStudent = gson.fromJson(gson.toJson(xiaoMing), Student.class);
System.out.println(xiaoMing == copyStudent);
}
2.5 Jackson序列化
Jackson与Gson相似,可以将对象序列化成JSON,明显不同的地方是拷贝的类(包括其成员变量)需要有默认的无参构造函数。
@org.junit.Test
public void coneableCopy() throws CloneNotSupportedException, JsonProcessingException {
// 被克隆的类
Student xiaoMing = new Student("小明");
// 使用Jackson序列化进行深拷贝
ObjectMapper objectMapper = new ObjectMapper();
Student copyStudent = objectMapper.readValue(objectMapper.writeValueAsString(xiaoMing), Student.class);
System.out.println(xiaoMing == copyStudent);
}
网友评论