Java中的可克隆接口
在Java中,我们经常需要复制一个对象而不想改变原有的对象。这时,就需要使用到克隆(Clone)的功能。克隆可以返回一个与原对象相同的对象,但存放在不同的内存地址中。在Java中,想要实现克隆功能,必须使用可克隆(Cloneable)接口。
Cloneable 接口
Cloneable 接口是一个标记型接口,它并没有实际的方法,只是一个标志,使用它可以告诉JVM:这个类可以被克隆。
示例代码如下:
public class Person implements Cloneable {
private String name;
private int age;
// 构造函数省略
// Getter Setter 省略
// 重写clone方法
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
以上代码展示了如何实现可克隆接口。clone() 方法被重写后,框架就将默认的浅拷贝变为了深拷贝。在调用的时候,我们只需要调用这个重写的 clone() 方法即可:
Person p1 = new Person("Jack", 18);
Person p2 = (Person) p1.clone();
深拷贝和浅拷贝
在克隆的时候,拷贝出来的新对象可能会有浅拷贝和深拷贝的区别。
浅拷贝只是拷贝对象的指针,指向同样的地址。在新对象和原对象只要有任何一个改变的时候,另一个都会跟着也发生改变。示例代码如下:
public class Address {
private String city;
public Address(String city) {
this.city = city;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
}
public class Student implements Cloneable {
private String name;
private int age;
private Address address;
public Student(String name, int age, Address address) {
this.name = name;
this.age = age;
this.address = address;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
在使用浅拷贝的时候,复制后的实例和原实例是使用同一个 address 实例,如下代码所示:
Address address = new Address("beijing");
Student student1 = new Student("Jack", 18, address);
Student student2 = (Student) student1.clone();
address.setCity("shanghai");
System.out.println(student1.getAddress().getCity()); // shanghai
System.out.println(student2.getAddress().getCity()); // shanghai
使用了可克隆接口之后,同时在重写 clone() 方法时,让 Student 和 Address 两个类也同时实现了 Cloneable 接口。这就是深拷贝,会重新克隆一份 address,如下代码所示:
Address address = new Address("beijing");
Student student1 = new Student("Jack", 18, address);
Student student2 = (Student) student1.clone();
address.setCity("shanghai");
System.out.println(student1.getAddress().getCity()); // shanghai
System.out.println(student2.getAddress().getCity()); // beijing
结论
Java中实现克隆功能,必须使用到可克隆接口(Cloneable)。同时,我们还要区分浅拷贝和深拷贝的概念。浅拷贝只是复制指针,使用克隆后的对象和原对象的部分实例变量指向的是同一块内存地址;而深拷贝则是完全的副本,使用克隆后的对象和原对象的所有实例变量指向的是不同的内存地址。在使用时需要根据具体情况来选择浅拷贝还是深拷贝,以保证数据的正确性和一致性。