浅拷贝
默认的克隆操作,也就是Object
的 clone
方法是浅拷贝
,浅拷贝只会拷贝对象属性的值,而不会拷贝对象中属性所引用的对象。
![](https://img.haomeiwen.com/i1902085/a3c476ca223cded6.png)
如上图所示,克隆的对象跟原对象共同引用同一个对象,如果其中有一个改变了
hireDay
的值,另一个对象hireDay
的值也会随之改变(因为是同一个引用),这样的结果有时可能并不是我们想要的,这时就需要 深拷贝
了
深拷贝
深拷贝会将对象及其属性引用的对象一同拷贝,这样的话每个对象及其属性引用的对像都是相互独立的就不会发生上面的问题了,想要实现深拷贝需要重写Object
类的 clone
方法。
另外,因为不可变对象不可修改,如 String
,所以不存在上面所说的问题,深拷贝时不用考虑不可变对象。
实现深拷贝
想要使用clone
方法的对象必须满足以下要求:
-
实现
Cloneable
接口, -
重写
clone
方法,并将访问修饰符改为public
(默认是protected
)
如:
public class Person implements Cloneable{
// ...
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
深拷贝需要将对象属性引用的可变对象逐个拷贝 如
public class Person implements Cloneable{
private String name;
private String sex;
private Date brithday; // 可变对象
// 重写 Object 的 clone 方法
@Override
public Object clone() throws CloneNotSupportedException {
// 克隆本对象
Person cloned = (Person) super.clone();
// 克隆本对象属性引用的可变对象
cloned.brithday = (Date) this.brithday.clone();
return cloned;
}
为什么要实现 Cloneable
接口
核心编程上说 Cloneable
接口是 Java 提供的一组标记接口(tagging interface)
之一,标记接口是不包含任何方法得,它唯一的作用就是允许在类型中查询使用 instanceof
关键字。
从上面可以知道,就算没有 Cloneable
接口我们也可以重写clone
方法,因为 clone
方法是Object的,但是如果类没有实现 Cloneable
接口,调用了clone
方法,运行时就会报 CloneNotSupportedException
异常,所以想要正常调用clone
方法,就必须实现Cloneable
接口。
将重写 clone
的方法默认是 protected
如果不声明为 public
是不能在别的类调用的(只能在自己跟子类中调用或者同包的类),上面例子中的Date
对象能在Person
中调用是因为 Date
这个类已经重写并将修饰符改成了 public
。
Java还可以通过 序列化实现对象克隆,简单易用,就是效率没有 clone
方法高。
网友评论