参考:https://csp1999.blog.csdn.net/article/details/115702607
在过去很长的一段时间里,博主对深浅拷贝的区别在脑海中的概念大概如下:
首先,拷贝这玩意儿就像是复制,有点像我们把对象中属性通过反射遍历然后挨个赋值给另一个对象
假如一个类由若干类组合而成,内部包含若干其它类的对象的引用
浅拷贝就只拷贝一般属性值,不拷贝引用,而深拷贝则会拷贝所有属性
然后我看了一眼大佬的博客,发现完全错了,属于是歪到银河系以外了已经是
对象的存储机制
此处是jvm相关的知识
由于内存机制的问题,栈内存的速度要远高于堆内存,但是堆有自己的优势,它很大,可以存储相对量比较大的数据,正是由于这个特性,对象的存储实际分为了两个部分,真正的对象数据被存在了堆内存中,而对象的引用则被存在了栈内存中,引用就像是一把钥匙,它帮助我们找到真正的对象数据,如果你有C语言的基础,会发现引用和C中的指针类似
上面这段有人可能看不懂,举个例子 Student student = new Student(),student.setName("张三");
上面的student就是一个引用,它指向堆中的内存,student被存储在栈内存中,你可以在内存中快速找到它。而对象中的具体数据,比如name,就是被存储在堆内存中,通过student引用,你可以找到对象,从而获取数据
深 浅拷贝
浅拷贝:对于基础数据类型:直接复制数据值;对于引用数据类型:只是复制了对象的引用地址,新旧对象指向同一个内存地址,修改其中一个对象的值,另一个对象的值随之改变。
深拷贝:对于基础数据类型:直接复制数据值;对于引用数据类型:开辟新的内存空间,在新的内存空间里复制一个一模一样的对象,新老对象不共享内存,修改其中一个对象的值,不会影响另一个对象。
深 浅拷贝都会复制基础类型的值,但是对于非基础类型复制操作就不同了
深拷贝相比于浅拷贝速度较慢并且花销较大。
package com.example.entity;
import com.alibaba.fastjson.JSON;
import lombok.Data;
import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@Data
public class CloneDemo implements Serializable,Cloneable {
private String name;
private int age;
private List<String> hobbies;
public CloneDemo deepClone() throws IOException, ClassNotFoundException {
//若在此构造中添加文件路径,还会将序列化的对象信息写入文件
//如ByteArrayOutputStream baos = new ByteArrayOutputStream("D:\\1.data");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
//将当前对象序列化
oos.writeObject(this);
ByteArrayInputStream bis = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
CloneDemo cloneDemo = (CloneDemo) ois.readObject();
return cloneDemo;
}
public static void main(String[] args) throws Exception {
CloneDemo cloneDemo = new CloneDemo();
cloneDemo.setName("法外狂徒张三");
cloneDemo.setAge(19);
List<String> tempList = new ArrayList<>(Arrays.asList("basketball","football","make money"));
cloneDemo.setHobbies(tempList);
CloneDemo shallowCloneDemo = (CloneDemo)cloneDemo.clone();
CloneDemo deepCloneDemo = cloneDemo.deepClone();
//对比引用指向地址是否一致
boolean flag3 = shallowCloneDemo.getHobbies() == cloneDemo.getHobbies();
boolean flag4 = deepCloneDemo.getHobbies() == cloneDemo.getHobbies();
boolean flag1 = shallowCloneDemo == cloneDemo;
boolean flag2 = deepCloneDemo == cloneDemo;
System.out.println("浅克隆对象值" + JSON.toJSONString(shallowCloneDemo));
System.out.println("深克隆对象值" + JSON.toJSONString(deepCloneDemo));
System.out.println("浅克隆后地址是否变更" + !flag1);
System.out.println("深克隆后地址是否变更" + !flag2);
System.out.println("浅克隆后属性地址是否变更" + !flag3);
System.out.println("深克隆后属性地址是否变更" + !flag4);
cloneDemo.getHobbies().add("play video games");
cloneDemo.setName("荒野嫖客李四");
System.out.println("浅克隆属性值" + JSON.toJSONString(shallowCloneDemo));
System.out.println("浅克隆属性值" + JSON.toJSONString(deepCloneDemo));
}
}
输出
浅克隆对象值{"age":19,"hobbies":["basketball","football","make money"],"name":"法外狂徒张三"}
深克隆对象值{"age":19,"hobbies":["basketball","football","make money"],"name":"法外狂徒张三"}
浅克隆后地址是否变更true
深克隆后地址是否变更true
浅克隆后属性地址是否变更false
深克隆后属性地址是否变更true
浅克隆属性值{"age":19,"hobbies":["basketball","football","make money","play video games"],"name":"法外狂徒张三"}
浅克隆属性值{"age":19,"hobbies":["basketball","football","make money"],"name":"法外狂徒张三"}
对于深 浅拷贝,获取的新对象地址都与原对象不同,但二者区别明显
首先 深浅拷贝复制的基本属性都不受原对象影响,修改原对象基础类型属性值不会影响到拷贝对象
但是,由于深拷贝是对原对象中的属性对象开辟新的内存空间存储的新属性对象,而浅拷贝的属性对象仍是原来的,所以,修改cloneDemo中的list属性,浅拷贝对象中的list跟着变了,而深拷贝则没有