深拷贝和浅拷贝
引用拷贝
创建一个指向对象的引用变量的拷贝。
Teacher teacher = new Teacher("Taylor",26);
Teacher otherteacher = teacher;
System.out.println(teacher);
System.out.println(otherteacher);
//输出结果
blog.Teacher@355da254
blog.Teacher@355da254
结果分析:由输出结果可以看出,它们的地址值是相同的,那么它们肯定是同一个对象
teacher和otherteacher的只是引用而已
他们都指向了一个相同的对象Teacher(“Taylor”,26)。 这就叫做引用拷贝。
对象拷贝
创建对象本身的一个副本
Teacher teacher = new Teacher("Swift",26);
Teacher otherteacher = (Teacher)teacher.clone();
System.out.println(teacher);
System.out.println(otherteacher);
//输出结果
blog.Teacher@355da254
blog.Teacher@4dc63996
深拷贝和浅拷贝都要重新开辟内存空间
浅拷贝生成的对象中引用数据类型与原本共用
深拷贝是引用数据类型也重新创建
浅拷贝实例(克隆方法破坏单例模式)
public class Test02 {
public static void main(String[] args) throws CloneNotSupportedException {
Test test = new Test();
Test clone = (Test) test.clone();
//结果为false
System.out.println(test == clone);
//结果为true
System.out.println(test.arr == clone.arr);
}
}
public class Test implements Cloneable {
public static Test t;
int[] arr = {1,2,3};
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public static void main(String[] args) {
if (t == null) {
synchronized (Test.class) {
if (t == null) {
t = new Test();
}
}
}
}
}
结果分析: 两个引用test和clone指向不同的两个对象
但是两个引用test和clone中的两个arr数组引用指向的是同一个对象,所以说明是浅拷贝。
深拷贝实现方法
深拷贝把要复制的对象所引用的对象都复制了一遍
继续利用clone()方法,对该对象的引用类型变量再实现一次clone()方法
通过重写克隆方法将引用数据类型一一克隆一遍放入浅拷贝对象中(实例1)
public class Test implements Cloneable {
public static Test t;
int[] arr = {1,2,3};
@Override
protected Object clone() throws CloneNotSupportedException {
Test clone = (Test) super.clone();
clone.arr = arr.clone();
return clone;
}
public static void main(String[] args) {
if (t == null) {
synchronized (Test.class) {
if (t == null) {
t = new Test();
}
}
}
}
}
public class Test02 {
public static void main(String[] args) throws CloneNotSupportedException {
Test test = new Test();
Test clone = (Test) test.clone();
//结果为false
System.out.println(test == clone);
//结果为false
System.out.println(test.arr == clone.arr);
}
}
利用序列化实现深拷贝(实例2)
序列化该对象,然后反序列化回来,就能得到一个新的对象了
序列化:将对象写入到IO流中
反序列化:从IO流中恢复对象 序列化机制允许将实现序列化的java对象转化为字节序列
这些字节序列可以保存到磁盘或者网络传输上,以达到以后恢复成原来的对象
序列化机制使得对象可以脱离程序的运行而独立存在
import java.io.*;
public class Test implements Cloneable, Serializable {
public Object deepClone() throws IOException, ClassNotFoundException {
// 序列化
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
// 反序列化
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return ois.readObject();
}
public static Test t;
int[] arr = {1,2,3};
@Override
protected Object clone() throws CloneNotSupportedException {
Test clone = (Test) super.clone();
clone.arr = arr.clone();
return clone;
}
public static void main(String[] args) {
if (t == null) {
synchronized (Test.class) {
if (t == null) {
t = new Test();
}
}
}
}
}
public class Test02 {
public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException {
Test test = new Test();
//Test clone = (Test) test.clone();
Test clone = (Test) test.deepClone();
//结果为false
System.out.println(test == clone);
//结果为false
System.out.println(test.arr == clone.arr);
}
}
Test clone = (Test) test.deepClone();
//结果为false
System.out.println(test == clone);
//结果为false
System.out.println(test.arr == clone.arr);
}
}