前言
这道问题经常在面试题中遇到
甚至在leetcode算法也有体现
比如这两行代码的区别
res.add(new ArrayList<String>(item));
res.add(item);
学完这篇文章再来回顾一下这个知识点
1. 定义
深拷贝和浅拷贝最根本的区别在于是否真正获取一个对象的复制实体,而不是引用
-
浅拷贝(shallowCopy):增加一个指针指向已存在的内存地址
-
深拷贝(deepCopy):增加一个指针并且申请了一个新的内存,使这个增加的指针指向这个新的内存
查看其概念,发现还是有些懵懂
通俗易懂的说:
A复制B,两者都是一样,但是修改B(原始状态)的时候,看A是否发生变化
-
浅拷贝现象:A跟着也变了(拿人手短,原模原样复制),因为修改堆内存中的同一个值
-
深拷贝现象:A没有改变(自食其力),因为修改堆内存中的不同的值,而且有了新地址
2. 浅拷贝
有着原始对象属性值的一份精确拷贝
- 属性是基本类型,拷贝的就是基本类型的值
- 属性是引用类型(内存地址),拷贝是内存地址(修改其地址,会影响到另一个对象调用其地址内的数据)
书写一个引用类的代码模块
@Data
这个注解可以生成get 、set等方法
具体可看我这篇文章
spring中@Data注解详细解析
@Data
@AllArgsConstructor
@NoArgsConstructor
public class books {
private String name;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
//引用类型
private books books;
//基础数据类型
private String name;
private int age;
}
具体其测试的实现类如下
public static void main(String[] args) {
studentA.setBooks(new books("码农研究僧"););
studentA.setName("码农");
studentA.setAge(15);
Student studentB = studentA;
studentB.setName("研究僧");
studentB.setAge(18);
Books books = studentB.getBooks();
subjectB.setName("码农研究僧");
System.out.println("studentA:" + studentA.toString());
System.out.println("studentB:" + studentB.toString());
}
}
通过其输出结果可以发现
其地址都是一样的
也就是改变会连着一起改变数值
3. 深拷贝
深拷贝,在拷贝引用类型成员变量时,为引用类型的数据成员另辟了一个独立的内存空间,实现真正内容上的拷贝
只需修改上面这部分代码即可
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student implements Cloneable {
//引用类型
private books books;
//基础数据类型
private String name;
private int age;
/**
* 重写clone()方法
* @return
*/
@Override
public Object clone() {
//深拷贝
try {
// 直接调用父类的clone()方法
Student student = (Student) super.clone();
student.books = (Books) books.clone();
return student;
} catch (CloneNotSupportedException e) {
return null;
}
}
}
其测试类和上面如出一辙
public static void main(String[] args) {
studentA.setBooks(new books("码农研究僧"););
studentA.setName("码农");
studentA.setAge(15);
Student studentB = (Student) studentA.clone();
studentB.setName("研究僧");
studentB.setAge(18);
Books books = studentB.getBooks();
subjectB.setName("码农研究僧");
System.out.println("studentA:" + studentA.toString());
System.out.println("studentB:" + studentB.toString());
}
}
地址不会随着改变
因为有个新地址