- 什么是clone方法?clone方法有什么作用?
首先要明白一个基本点:基本数据类型的传递是值传递,其他类型的传递是引用传递。
Person person = new Person();
Person newPerson = person;
System.out.println(person); // com.question.clone.Person@1b6d3586
System.out.println(newPerson); // com.question.clone.Person@1b6d3586
上述代码证明,单纯得将一个对象赋值给另一个对象,实际上是将引用地址赋值给了新的对象,它们指向的是同一片内存区域,因此当对newPerson的属性进行操作时,同样会改变person属性,这显然是不合理的。
为了规避这一现象,Java提供了clone方法。具体操作如下:
- 实现clone的类首先需要继承Cloneable接口(Cloneable接口实质是一个标识接口,没有任何的接口方法)
- 在类中重写Object类中的clone()方法
- 在clone()方法中调用super.clone()。无论clone类继承结构是什么,super.clone()会直接或间接java.lang.Object类中的clone()方法
- 把浅复制的引用指向原型对象新的克隆体。
浅复制和深复制
- 浅复制:被复制的对象的所有变量都含有与原来对象一样的值(这部分值在内存中开辟了新空间),而其他对象的引用仍指向原来的对象。换言之,浅复制仅仅复制了所考虑对象的引用,而不赋值它所引用的对象。
- 深复制:被复制的对象的所有变量都含有与原来对象一样的值,除去那些引用对其他对象的变量(因此如果要完整得实现克隆,非基本数据类型的属性也要实现Cloneable接口并重写clone方法),那些引用其他对象的变量将指向被复制的新对象,而不知原来那些被引用的对象。换言之,深复制把浅复制的对象所引用的对象都复制了一遍。
代码实现
public class Person implements Cloneable{
private String name;
Money m;
int age;
public Person(){
}
public Person(String name, int age){
this.name = name;
m = new Money();
this.age = 18;
}
@Override
protected Object clone() throws CloneNotSupportedException {
Person person = (Person) super.clone(); // 浅复制:克隆Person对象
person.m = (Money) this.m.clone(); // 深复制:克隆Person对象中引用指向对象
return person;
}
}
class Money implements Cloneable{
double money = 12.0;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public static void main(String[] args) throws CloneNotSupportedException {
Person person1 = new Person("曹操", 18);
Person person2 = (Person) person1.clone();
System.out.println(person1.m); // com.question.clone.Money@1b6d3586
System.out.println(person2.m); // com.question.clone.Money@4554617c
person2.m.money = 1000.0;
person2.age = 24;
System.out.println(person1.m.money); // 12.0
System.out.println(person2.m.money); // 1000.0
System.out.println(person1.age); // 18
System.out.println(person2.age); // 24
}