浅拷贝VS深拷贝
只复制指向某个对象的指针,不复制对象本身,新旧对象共享一个块内存
复制并创建一个一模一样的对象,不共享内存,修改新对象,旧对象保持不变
浅拷贝
demo
package com.jysemel.java.basic;
public class Demo {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
package com.jysemel.java.basic;
public class Main {
public static void main(String[] args) {
Demo demo = new Demo();
demo.setName("jysemel");
demo.setAge(18);
System.out.println(demo.getName());
Demo demo1 = demo;
demo1.setName("jysemel1");
System.out.println(demo.getName());
System.out.println(demo1.getName());
}
}
深拷贝
实现 Cloneable 接口,并重写 clone 方法
package com.jysemel.java.basic;
import lombok.SneakyThrows;
import java.util.List;
public class Demo1 implements Cloneable{
private String name;
private int age;
private List<String> list;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public List<String> getList() {
return list;
}
public void setList(List<String> list) {
this.list = list;
}
@SneakyThrows
@Override
public Demo1 clone() {
return (Demo1) super.clone();
}
@Override
public String toString() {
return "Demo1{" +
"name='" + name + '\'' +
", age=" + age +
", list=" + list +
'}';
}
}
package com.jysemel.java.basic;
import java.util.ArrayList;
import java.util.List;
public class Main1 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
Demo1 demo = new Demo1();
demo.setName("jysemel");
demo.setAge(18);
demo.setList(list);
demo.getList().add("2");
System.out.println(demo.getName());
Demo1 demo1 = demo.clone();
demo1.setAge(19);
demo1.setName("jysemel1");
demo.getList().add("4");
System.out.println(demo);
System.out.println(demo1);
}
}
结果
Demo1{name='jysemel', age=18, list=[2, 4]}
Demo1{name='jysemel1', age=19, list=[2, 4]}
String 对象一旦创建,内容不会变,修改会创建新对象,不会改变原来的对象
list 引用类型,没有进行深拷贝,修改会改变原来的对象
浅拷贝和深拷贝的场景
1、避免线程间共享可变状态导致线程安全问题,可传递该对象的深拷贝副本
2、DTO(数据传输对象)转换
3、缓存快照
优化拷贝
问题
1、对象嵌套层次越深,深拷贝的开销就越大
2、对于大量对象的复制操作,深拷贝可能导致性能下降
其他方式
其一 序列化 demo
package com.jysemel.java.basic.demo3;
import java.io.*;
public class Dept implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private String address;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "Dept{" +
"name='" + name + '\'' +
", address='" + address + '\'' +
'}';
}
public Dept(String name, String address) {
this.name = name;
this.address = address;
}
// 深拷贝方法:利用序列化
Dept deepCopy() {
try {
// 写入字节数组流
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(this);
oos.close();
// 从字节数组流读取
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
return (Dept) ois.readObject();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
package com.jysemel.java.basic.demo3;
public class SimpleDeepCopyDemo {
public static void main(String[] args) {
Dept p1 = new Dept("张三", "333");
// 深拷贝
Dept p2 = p1.deepCopy();
// 打印原始和副本
System.out.println("原始: " + p1);
System.out.println("副本: " + p2);
// 修改副本的基本类型字段
p2.setName("李四");
p2.setAddress("李四33");
// 再次打印,观察原始对象是否被影响
System.out.println("\n修改副本后:");
System.out.println("原始: " + p1); // 原始对象不受影响
System.out.println("副本: " + p2);
}
}