传媒网站建设价格百度应用市场
浅拷贝
浅拷贝会创建一个新的对象,复制该对象的基本类型引用,但不复制该对象内的其他对象引用。一个对象要支持浅拷贝,需要实现Cloneable
接口,不然在调用clone()
方法时会抛出异常
protected Object clone() throws CloneNotSupportedException {if (!(this instanceof Cloneable)) {throw new CloneNotSupportedException("Class " + getClass().getName() +" doesn't implement Cloneable");}return internalClone();}
看个简单的demo
public class ShallowCopy implements Cloneable {int i = 10;String str = "ShallowCopy";Shallow shallow = new Shallow();public static class Shallow {String shallow = "shallow";}public static void testShallowCopy() {ShallowCopy shallowCopy = new ShallowCopy();try {ShallowCopy shallowCopyClone = (ShallowCopy) shallowCopy.clone();LogUtil.info("ShallowCopy", "(shallowCopy == shallowCopyClone) = " + (shallowCopy == shallowCopyClone));LogUtil.info("ShallowCopy", "(shallowCopy.equals(shallowCopyClone)) = " + (shallowCopy.equals(shallowCopyClone)));LogUtil.info("ShallowCopy", "(shallowCopy.shallow == shallowCopyClone.shallow) = " + (shallowCopy.shallow == shallowCopyClone.shallow));LogUtil.info("ShallowCopy", "(shallowCopy.shallow.equals(shallowCopyClone.shallow)) = " + (shallowCopy.shallow.equals(shallowCopyClone.shallow)));} catch (CloneNotSupportedException e) {throw new RuntimeException(e);}}
}
打印结果如下
2025-03-13 16:53:25.564 (shallowCopy == shallowCopyClone) = false
2025-03-13 16:53:25.564 (shallowCopy.equals(shallowCopyClone)) = false
2025-03-13 16:53:25.564 (shallowCopy.shallow == shallowCopyClone.shallow) = true
2025-03-13 16:53:25.564 (shallowCopy.shallow.equals(shallowCopyClone.shallow)) = true
我们发现shallowCopy
和shallowCopyClone
指向不同的对象,但是里面的shallow
却是同一个。如果要实现两个shallowCopy
和shallowCopyClone
两个完全不同的对象,也即是要实现深拷贝,有两个办法,下文介绍两种方法
深拷贝
- 内部的对象引用所属类也继承
clone
接口,重写clone()
方法,例如
public class ShallowCopy implements Cloneable {int i = 10;String str = "ShallowCopy";Shallow shallow = new Shallow();@NonNull@Overrideprotected Object clone() throws CloneNotSupportedException {ShallowCopy cloned = (ShallowCopy)super.clone();cloned.shallow = (Shallow)shallow.clone();return cloned;}public static class Shallow implements Cloneable {String shallow = "shallow";@NonNull@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}}public static void testShallowCopy() {ShallowCopy shallowCopy = new ShallowCopy();try {ShallowCopy shallowCopyClone = (ShallowCopy) shallowCopy.clone();LogUtil.info("ShallowCopy", "(shallowCopy == shallowCopyClone) = " + (shallowCopy == shallowCopyClone)); // falseLogUtil.info("ShallowCopy", "(shallowCopy.equals(shallowCopyClone)) = " + (shallowCopy.equals(shallowCopyClone))); // falseLogUtil.info("ShallowCopy", "(shallowCopy.shallow == shallowCopyClone.shallow) = " + (shallowCopy.shallow == shallowCopyClone.shallow)); // falseLogUtil.info("ShallowCopy", "(shallowCopy.shallow.equals(shallowCopyClone.shallow)) = " + (shallowCopy.shallow.equals(shallowCopyClone.shallow))); // false} catch (CloneNotSupportedException e) {throw new RuntimeException(e);}}
}
返回结果
2025-03-13 17:14:09.906 (shallowCopy == shallowCopyClone) = false
2025-03-13 17:14:09.906 (shallowCopy.equals(shallowCopyClone)) = false
2025-03-13 17:14:09.906 (shallowCopy.shallow == shallowCopyClone.shallow) = false
2025-03-13 17:14:09.906 (shallowCopy.shallow.equals(shallowCopyClone.shallow)) = false
但这个方法有个弊端,就是如果引用对象的链路比较深,例如 A 引用 B,B 引用 C,C 引用 D,甚至更深,就需要重写很多clone()
方法,不易于维护.
值得注意的是
Shallow
类里面的shallow
变量,它是一个String
类型的对象引用,但是却可以不用实现clone
接口实现深拷贝。原因是String
是不可变的,修改String类型都会返回一个新对象,参考文档String 基础知识
- 使用
Serializable
序列化实现深拷贝
需要注意的是引用对象的类型也要实现
Serializable
接口,不然后报错
public class ShallowCopy implements Cloneable, Serializable {public static class Shallow implements Cloneable, Serializable {}
}
如果Shallow
没有实现Serializable
接口,则会出现java.io.NotSerializableException
。接着使用IO实现序列化和反序列化
public ShallowCopy deepClone() {ShallowCopy deepClone = null;try {ByteArrayOutputStream bos = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(bos);oos.writeObject(this);ByteArrayInputStream bio = new ByteArrayInputStream(bos.toByteArray());ObjectInputStream ois = new ObjectInputStream(bio);deepClone = (ShallowCopy) ois.readObject();} catch (IOException | ClassNotFoundException e) {throw new RuntimeException(e);}return deepClone;}
结果打印
public static void testDeepCopy() {ShallowCopy shallowCopy = new ShallowCopy();ShallowCopy shallowCopyDeepClone = shallowCopy.deepClone();LogUtil.info("ShallowCopy", "(shallowCopy == shallowCopyDeepClone) = " + (shallowCopy == shallowCopyDeepClone)); // falseLogUtil.info("ShallowCopy", "(shallowCopy.equals(shallowCopyDeepClone)) = " + (shallowCopy.equals(shallowCopyDeepClone))); // falseLogUtil.info("ShallowCopy", "(shallowCopy.shallow == shallowCopyDeepClone.shallow) = " + (shallowCopy.shallow == shallowCopyDeepClone.shallow)); // falseLogUtil.info("ShallowCopy", "(shallowCopy.shallow.equals(shallowCopyDeepClone.shallow)) = " + (shallowCopy.shallow.equals(shallowCopyDeepClone.shallow))); // false}