Cloneable 和 clone()
Cloneable 和 clone()
1.Cloneable 接口
首先,Cloneable 是一个标记接口(marker interface),意味着它没有任何方法。它的唯一作用是告诉Java虚拟机(JVM)当前类支持“克隆”操作,即能够创建当前对象的一个副本。
为什么需要 Cloneable 接口?
Java 的 Object 类有一个方法叫做 clone(),但是它是 受保护的,并且会抛出 CloneNotSupportedException 异常,前提是类没有实现 Cloneable 接口。因此,只有实现了 Cloneable 接口的类才能调用 clone() 方法来复制对象。
总结:Cloneable 只是一个标记接口,标识当前类支持克隆。
2.clone() 方法
clone() 方法是 Object 类的一部分,实际上就是用来克隆(复制)对象的。
- 返回值:clone() 方法返回当前对象的一个“浅拷贝”副本。
- 访问权限:clone() 是 protected 的,所以你需要在子类中重写它,或者通过反射来调用它。
⠀深拷贝 vs 浅拷贝
- 浅拷贝:只复制对象的引用值,而不复制引用对象本身(对象中的引用成员变量,仍然指向原来的对象)。
- 深拷贝:不仅复制对象本身,还递归地复制引用对象,这样就不会发生引用共享。
3. 常见的用例
假设我们有一个 Person 类,并且希望它能被克隆。下面是一个简单的示例:
class Person implements Cloneable {
String name;
int age;
// 构造方法
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// 重写 clone() 方法
@Override
public Person clone() throws CloneNotSupportedException {
return (Person) super.clone();
}
@Override
public String toString() {
return "Person{name='" + name + "', age=" + age + "}";
}
}
public class Main {
public static void main(String[] args) {
try {
Person person1 = new Person("Alice", 25);
Person person2 = person1.clone(); // 克隆 person1
System.out.println(person1); // 输出: Person{name='Alice', age=25}
System.out.println(person2); // 输出: Person{name='Alice', age=25}
person2.age = 30; // 修改克隆对象的 age
System.out.println(person1); // 输出: Person{name='Alice', age=25}
System.out.println(person2); // 输出: Person{name='Alice', age=30}
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
关键点:
- person1.clone() 会创建 person1 的浅拷贝,也就是它的 name 和 age 会被复制,但 name 和 age 是基本类型数据,修改一个不会影响另一个。
- 如果 Person 类中有引用类型字段(比如 Address 类),那么对 clone() 的操作将只是复制引用,而不是创建新的对象。
4. 注意事项
- 如果你的类中有引用类型字段,通常你需要做 深拷贝,否则浅拷贝可能会导致副本与原对象共享引用。
- clone() 并不是推荐使用的方式,Java 更倾向于使用构造器、工厂方法或者其他方式来复制对象。
5. 深拷贝实现
对于需要深拷贝的对象,你可能需要手动处理。比如:
class Person implements Cloneable {
String name;
int age;
Address address; // 假设有一个引用类型字段
// 构造方法
public Person(String name, int age, Address address) {
this.name = name;
this.age = age;
this.address = address;
}
// 重写 clone() 方法进行深拷贝
@Override
public Person clone() throws CloneNotSupportedException {
Person cloned = (Person) super.clone(); // 浅拷贝
cloned.address = new Address(address.getStreet()); // 深拷贝 Address
return cloned;
}
}
class Address {
String street;
public Address(String street) {
this.street = street;
}
public String getStreet() {
return street;
}
}
总结
- Cloneable 接口:标识当前类可以被克隆。
- clone() 方法:用来创建对象的副本,默认是浅拷贝,如果需要深拷贝,你需要手动处理引用类型字段。