唠嗑部分
首先什么是浅拷贝(浅克隆)与深拷贝(深克隆)呢?
见名知意,就是从源数据复制一份一模一样的,两份是独立的,互不影响(即修改任何一个,另一个不受影响)
浅拷贝:拷贝基本数据类型及引用数据类型的地址
深拷贝:拷贝引用数据类型的值
在前端js中,基本数据类型有字符串、布尔、数字,在Java中,8大基本数据类型byte、short、int、long、float、double、boolean、char
今天我们就来说一说前后端分别如何实现对象的深拷贝与浅拷贝
言归正传
我们用以下这个数据来说明
{
name: "张三",
age: 23,
job: {
company: "阿里巴巴",
salary: 30
}
}
前端如何实现深拷贝
预期结果:修改源数据的值后克隆数据的值不会变化
1、大家最先想到的一种方式肯定是赋值了,如下
说明:基本数据类型的赋值是值的拷贝,引用数据类型是地址的拷贝
// 赋值
const personCopy = person;
console.log("源数据", person)
console.log("克隆数据", personCopy)
// 修改源数据的值
person.age = 20
person.job.salary = 40
console.log("修改后源数据", person)
console.log("修改后克隆数据", personCopy)
这种的方式可想而知,经过赋值语句会吧person的地址赋给personCopy,是浅拷贝,看结果

2、Object.assign()
// 语法
const personCopy = {};
Object.assign(personCopy, person)
// 打印同上
这种方式可以达到浅层次的深拷贝,如果对象有深层次的嵌套,依然是浅拷贝,看下图,age完成了深克隆,但是薪资依然是浅克隆

3、展开运算符
// 语法
const personCopy = {...person};
展开运算符是ES6的一种语法,这种方式同上依然可以达到浅层次的深克隆,嵌套对象依然处理不了

4、序列化与反序列化
// 语法
const personCopy = JSON.parse(JSON.stringify(person))
这种方式可以实现深拷贝,但是会出现一些问题,请百度自查

那说了这么多方法,难道就没有一种方式实现深拷贝了嘛?
5、使用函数的方式
/**
* 深拷贝
* @param dest 拷贝的目标对象
* @param src 源对象
* @returns {{}}
*/
function deepCopy(dest,src){
var dest = dest || {};
for(let key in src){
//如果对象的属性又是复杂数据类型,则递归处理
if(typeof src[key] === "object"){
dest[key]= (src[key].constructor === Array)?[]:{};
deepCopy(dest[key],src[key]);
}else{
dest[key]=src[key];
}
}
return dest;
}
// 语法
const personCopy = {}
deepCopy(personCopy, person)
编写深拷贝函数,如果是复杂对象,则递归处理

Java如何实现深拷贝
首先创建Person类,Job类,由于篇幅原因,构造器、toString、Getter、Setter方法省略,自行补充
class Person implements Cloneable{
private String name;
private Integer age;
private Job job;
...
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
class Job implements Cloneable{
private String company;
private Integer salary;
...
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
在Java中,要实现对象的拷贝,该对象必须实现Cloneable接口,否则会报错的哦
测试代码,与前端js一致
/**
* @Project: wanju
* @Author: cxs2014501@163.com
* @Create: 2023/4/27 10:15
* @Description:
**/
public class DeepCopyTest {
public static void main(String[] args) {
try {
Person person = new Person("张三", 23, new Job("阿里巴巴", 30));
Person personCopy = (Person) person.clone();
System.out.println("源数据" + person);
System.out.println("克隆数据" + personCopy);
person.setAge(20);
person.getJob().setSalary(40);
System.out.println("修改后源数据" + person);
System.out.println("修改后克隆数据" + personCopy);
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
首先看效果,套娃的对象还是没有完成深拷贝

深拷贝实现方案一:clone方法
修改person类的clone方法,针对于复杂对象单独处理,可以实现深拷贝
但是如果对象层层嵌套,那就每个对象都要处理clone方法
@Override
protected Object clone() throws CloneNotSupportedException {
Person personClone = (Person) super.clone();
Job jobClone = (Job) personClone.getJob().clone();
personClone.setJob(jobClone);
return personClone;
}
看效果

深拷贝实现方案二(推荐):对象的序列化与反序列化
注意:对象要实现序列化接口Serializable,否则会无法序列化

/**
* @Project: wanju
* @Author: cxs2014501@163.com
* @Create: 2023/4/27 10:15
* @Description:
**/
public class DeepCopyTest {
public static void main(String[] args) {
ObjectInputStream oin = null;
ObjectOutputStream oos = null;
ByteArrayOutputStream bos = null;
ByteArrayInputStream bis = null;
try {
Person person = new Person("张三", 23, new Job("阿里巴巴", 30));
Person personCopy = null;
// 对象序列化
bos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bos);
oos.writeObject(person);
// 对象反序列化
bis = new ByteArrayInputStream(bos.toByteArray());
oin = new ObjectInputStream(bis);
personCopy = (Person) oin.readObject();
System.out.println("源数据" + person);
System.out.println("克隆数据" + personCopy);
person.setAge(20);
person.getJob().setSalary(40);
System.out.println("修改后源数据" + person);
System.out.println("修改后克隆数据" + personCopy);
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭流资源,先开的后关
...
}
}
}
看效果,没有问题,这种方式也是推荐使用的

结语
1、浅拷贝拷贝出来的两个对象地址是一样的,实际在堆中指向同一个实例
2、深拷贝拷贝出来的两个对象是完全独立的,因为拷贝的是堆中的整个对象,person与personCopy的地址不一样
3、制作不易,一键三连再走吧,您的支持永远是我最大的动力!
4、Java全栈技术交流QQ群:941095490,欢迎您的加入,案例代码见群文件!

792

被折叠的 条评论
为什么被折叠?



