📅  最后修改于: 2023-12-03 15:31:58.032000             🧑  作者: Mango
在Java中,克隆即是创建一个与原始对象相同的新对象。Java中的克隆功能可以通过Cloneable
接口实现。当一个对象调用clone()
方法时,系统会创建一个新的对象,并复制原始对象的所有值,并将其作为新对象的属性进行设置,这种机制就称为克隆。
以下是克隆的基本实现方式:
public class MyClass implements Cloneable {
private int value;
public MyClass(int value) {
this.value = value;
}
public void setValue(int value) {
this.value = value;
}
public int getValue() {
return value;
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone(); // 确保返回的是克隆的实例,否则抛出CloneNotSupportedException异常
}
}
在Java中,Cloneable
接口被用来标识可克隆的对象,如果一个对象没有实现Cloneable
接口,调用它的clone()
方法会抛出CloneNotSupportedException
异常。同时,Object
类中的clone()
方法返回的是一个Object
类型的对象,但使用时一般需要进行强制类型转换。
MyClass mc1 = new MyClass(10);
try {
MyClass mc2 = (MyClass)mc1.clone(); // 通过强制类型转换实现克隆
System.out.println("mc1: " + mc1.getValue()); // 输出 "mc1: 10"
System.out.println("mc2: " + mc2.getValue()); // 输出 "mc2: 10"
mc2.setValue(20);
System.out.println("mc1: " + mc1.getValue()); // 输出 "mc1: 10"
System.out.println("mc2: " + mc2.getValue()); // 输出 "mc2: 20"
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
从上述代码中可以看出,克隆后对象的属性与原始对象保持一致,并不会相互干扰。
注意:当对象是一个引用类型,则克隆得到的对象与原始对象的指针会指向同一引用对象,所以克隆后的对象改变了引用对象中的属性值,原始对象也会发生相应的改变。为了避免这种情况,需要将引用类型也进行克隆,确保克隆后的对象是新的对象,而不是原始对象的引用。
以上是Java中的浅克隆,即只拷贝对象本身以及其数据成员的值,而对于它所引用的对象,只拷贝引用而不拷贝引用的对象本身。为了克服浅克隆的缺陷,需要使用深克隆,即在进行克隆时对所引用的对象也进行克隆。
以下是实现深克隆的一个例子(假设类MyClass
中有一个成员变量为MyOtherClass
):
public class MyClass implements Cloneable {
private int value;
private MyOtherClass myOtherClass;
public MyClass(int value, MyOtherClass myOtherClass) {
this.value = value;
this.myOtherClass = myOtherClass;
}
public void setValue(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public void setMyOtherClass(MyOtherClass myOtherClass) {
this.myOtherClass = myOtherClass;
}
public MyOtherClass getMyOtherClass() {
return myOtherClass;
}
@Override
public Object clone() throws CloneNotSupportedException {
MyClass cloned = (MyClass)super.clone();
cloned.myOtherClass = (MyOtherClass)myOtherClass.clone(); // 克隆对象的引用类型对象
return cloned;
}
}
在该实例中,对MyClass
中的clone()
方法进行重写,首先用super.clone()
完成对本对象(即深克隆所在对象)的赋值,新建一个MyClass
类的实例并将超类中的属性字段值复制到新的实例中,这样就可以实现深度克隆。接着将myOtherClass
进行克隆,当MyClass
类中含有多个引用类型时,需要对每个引用类型都进行克隆,同时保证克隆对象也会自动克隆它的引用对象,然后返回深克隆所在对象的实例。
Java中的clone()
方法用于创建新对象,使其属性与原始对象相同,但克隆对象与原始对象的引用地址不同。通过实现Cloneable
接口,克隆对象较为容易。这里还介绍了深克隆和浅克隆的概念,当克隆对象中的成员包含引用类型时,需要进行深克隆,才能正确的克隆整个对象。
需要注意的是,使用克隆时需要避免对克隆对象进行不必要的修改,因为克隆后的对象仍然可能被其他对象引用。如果一定需要对克隆对象的属性进行修改,推荐使用深克隆的方式。