Clone方法与浅拷贝&深拷贝
介绍
在Java中,如果需要创建一个对象的副本,特别是这个对象的创建需要很大代价时,可以使用Clone()方法快速高效创建对象副本。
如何实现
实现Cloneable接口,重写Object.clone()方法即可。
class OracleDriver implements Cloneable{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public OracleDriver clone() throws CloneNotSupportedException {
return (OracleDriver) super.clone();
}
}
通常来说,clone之后的对象与原生对象应该是相互独立的,没有任何关联的,为了使原生对象与克隆对象保持独立,需要视不同情况使用浅拷贝与深拷贝。
当类中包含可变对象时,如果使用浅拷贝,就会发生以下情况:
class OtherInfo{
private String name;
/* getter & setter*/
@Override
public String toString() {
return "hashCode= {" + hashCode() + "}OtherInfo{" +
"name='" + name + '\'' +
'}';
}
}
class OracleDriver implements Cloneable{
private String name;
private OtherInfo otherInfo;
public OracleDriver(OtherInfo otherInfo){
this.otherInfo = otherInfo;
}
/* getter & setter*/
@Override
public OracleDriver clone() throws CloneNotSupportedException {
return (OracleDriver) super.clone();
}
@Override
public String toString() {
return "hashCode= {" + hashCode() + "}OracleDriver{" +
"name='" + name + '\'' +
", otherInfo=" + otherInfo +
'}';
}
}
public static void main(String[] args) throws CloneNotSupportedException {
OracleDriver origin = new OracleDriver(new OtherInfo());
OracleDriver clone = origin.clone();
System.out.println("origin:" + origin);
System.out.println("clone:" + clone);
}
/*
打印结果:
origin:hashCode= {1175962212}OracleDriver{name='null', otherInfo=hashCode= {918221580}OtherInfo{name='null'}}
clone:hashCode= {2055281021}OracleDriver{name='null', otherInfo=hashCode= {918221580}OtherInfo{name='null'}}
*/
结果
可以看到原生对象与克隆对象引用的OtherInfo的hashCode是一致的,也就是引用的是同一个实例对象,这种情况下,原生对象与克隆对象是存在关联的,当原生对象修改了OtherInfo对象时,克隆对象也被修改了,这样是不行的。这时候需要深拷贝。
浅拷贝 shallow copy
当一个类中的成员变量只包含8中原生数据类型或者是不可变数据类型的变量时,只需要当前类实现Cloneable接口即可。
class OracleDriver implements Cloneable{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public OracleDriver clone() throws CloneNotSupportedException {
return (OracleDriver) super.clone();
}
}
深拷贝 deep copy
当一个类中的成员变量存在可变数据类型的变量时,比如引用了另一个类,为了保持原生对象与克隆对象相互独立,需要在clone()方法返回之前,修改这些可变对象,通常会clone这些可变对象,并使用克隆对象替换这些可变对象。
OracleDriver引用了OtherInfo
class OracleDriver implements Cloneable{
private String name;
private OtherInfo otherInfo;
public OracleDriver(OtherInfo otherInfo){
this.otherInfo = otherInfo;
}
@Override
public OracleDriver clone() throws CloneNotSupportedException {
OracleDriver oracleDriver = (OracleDriver) super.clone();
OtherInfo otherInfo = oracleDriver.getOtherInfo().clone();
oracleDriver.setOtherInfo(otherInfo);
return oracleDriver;
}
@Override
public String toString() {
return "hashCode= {" + hashCode() + "}OracleDriver{" +
"name='" + name + '\'' +
", otherInfo=" + otherInfo +
'}';
}
引用类也需要实现Cloneable接口
class OtherInfo implements Cloneable{
private String name;
@Override
protected OtherInfo clone() throws CloneNotSupportedException {
return (OtherInfo) super.clone();
}
@Override
public String toString() {
return "hashCode= {" + hashCode() + "}OtherInfo{" +
"name='" + name + '\'' +
'}';
}
}
结果
可以看到原生对象与克隆对象应用的OtherInfo是两个实例,原生对象与克隆对象彼此不影响。
public static void main(String[] args) throws CloneNotSupportedException {
OracleDriver origin = new OracleDriver(new OtherInfo());
OracleDriver clone = origin.clone();
System.out.println("origin:" + origin);
System.out.println("clone:" + clone);
}
/*
打印结果:
origin:hashCode= {1175962212}OracleDriver{name='null', otherInfo=hashCode= {918221580}OtherInfo{name='null'}}
clone:hashCode= {2055281021}OracleDriver{name='null', otherInfo=hashCode= {1554547125}OtherInfo{name='null'}}
*/
数组中的clone
在Java中,数组对象已经原生实现了Cloneable接口,但实现的是浅拷贝。所以当数组中存在可变对象时,需要自行替换掉这些可变对象。