对于一个对象的拷贝,有很多方法,比如最简单的
就是这个类实现 cloneable接口,实现clone()方法即可,
但是这样是浅拷贝,意思就是对象的基础类型和引用对象的句柄都拷贝过去了
注意 这里说的是引用对象的句柄
但是,学过JVM的都知道,基础类型都是存放在JAVA栈中,
引用类型:句柄存放在栈中,对象是存在放堆中
所以你如果修改1个对象的引用,相当于修改了2个对象的应用。
因为浅拷贝的目标对象和源对象指向的引用成员变量是同一个地方。
所以我们需要深拷贝,意思就是拷贝的时候,同时把引用对象也拷贝出一份
用对象字节流的序列与反序列化很方便,下面是例子
Student.java
@Data
@Builder
public class Student implements Cloneable,Serializable{
private static final long serialVersionUID = 2L;
private String Name;
private String sex;
private Classes classes;
/**
* 浅拷贝
* @return
* @throws CloneNotSupportedException
*/
@Override
protected Student clone() throws CloneNotSupportedException {
return (Student)super.clone();
}
/**
* 深度拷贝 == 不管你对象中是值类型部分,还是引用类型部分,我全部拿走
* 对象字节流的序列与反序列化 ==> 对象完全、深度、彻彻底底的Copy!!!
* @return
*/
public Student deepClone(){
// Anything 都是可以用字节流进行表示,记住是任何!
Student student = null;
try{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
// 将当前的对象写入baos【输出流 -- 字节数组】里
oos.writeObject(this);
// 从输出字节数组缓存区中拿到字节流
byte[] bytes = baos.toByteArray();
// 创建一个输入字节数组缓冲区
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
// 创建一个对象输入流
ObjectInputStream ois = new ObjectInputStream(bais);
// 下面将反序列化字节流 == 重新开辟一块空间存放反序列化后的对象
student = (Student) ois.readObject();
}catch (Exception e){
System.out.println(e.getClass()+":"+e.getMessage());
}
return student;
}
}
测试类
public static void main(String[] args) throws CloneNotSupportedException {
Classes classes = Classes.builder().classesName("classname")
.classesLeavl(1).build();
Student student1 = Student.builder().Name("aaa")
.sex("男").classes(classes).build();
Student student2 = student1.clone();
classes.setClassesName("classnamenew");
student1.setName("bbbb");
Student student3 = student1.deepClone();
classes.setClassesName("classname333");
student1.setName("cccc");
System.out.println("student1.classes"+student1.getClasses().hashCode());
System.out.println("student1"+student1.getClasses());
System.out.println("student2.classes"+student2.getClasses().hashCode());
System.out.println("student2"+student2.getClasses());
System.out.println("student3.classes"+student3.getClasses().hashCode());
System.out.println("student3"+student3.getClasses());
}
打印结果
student1.classes1185899242
student1Classes(classesName=classname333, classesLeavl=1)
student2.classes1185899242
student2Classes(classesName=classname333, classesLeavl=1)
student3.classes1189339945
student3Classes(classesName=classnamenew, classesLeavl=1)
从结果可以看到,student2是student1的浅拷贝对象,修改classes对象时,同时也影响到student2
student3是student1的深拷贝对象,修改classes对象时,不会影响到student3.