Cloneable 接口是一个标记接口(也称为标记型接口,它没有任何方法定义),位于 java.lang 包中。它的存在是为了表明一个类可以被克隆。当一个类实现了 Cloneable 接口后,就可以使用 Object 类的 clone() 方法来创建该类的一个副本。
提供一种简单的对象复制机制,在某些情况下可以方便地创建对象的副本,比如在需要保留对象原始状态的备份,或者快速创建一个具有相似初始状态的新对象等场景。
首先,在自定义类中声明实现Cloneable接口。例如,我们创建一个简单的Person类来演示:
class Person implements Cloneable { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } // 省略getter和setter方法 }
因为 clone() 方法是在 Object 类中定义的,并且它是受保护的(protected)方法,所以在实现类中需要重写它,并将其访问修饰符修改为 public,以便在其他类中可以调用。同时,需要处理CloneNotSupportedException 异常,这个异常是在对象不支持克隆操作时抛出的。
代码如下:
class Person implements Cloneable { //...其他代码同步骤一 @Override public Person clone() throws CloneNotSupportedException { return (Person) super.clone(); } }
完整 Person 代码如下:
package com.hxstrive.java_lang.cloneable; /** * Cloneable 示例 * @author hxstrive */ public class Person implements Cloneable { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } 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; } @Override public Person clone() throws CloneNotSupportedException { return (Person) super.clone(); } }
现在可以在其他类中使用Person类的克隆功能了。例如:
package com.hxstrive.java_lang.cloneable; /** * Cloneable 接口的示例 * @author hxstrive */ public class CloneableDemo { public static void main(String[] args) { try { Person originalPerson = new Person("Alice", 30); Person clonedPerson = originalPerson.clone(); System.out.println("Original Person: Name = " + originalPerson.getName() + ", Age = " + originalPerson.getAge()); System.out.println("Cloned Person: Name = " + clonedPerson.getName() + ", Age = " + clonedPerson.getAge()); } catch (CloneNotSupportedException e) { e.printStackTrace(); } //输出: //Original Person: Name = Alice, Age = 30 //Cloned Person: Name = Alice, Age = 30 } }
如果一个对象的克隆只是简单地复制了对象的基本类型成员变量和引用类型成员变量的引用(即没有复制引用对象本身),这种克隆方式称为浅克隆。
示例:假设Person类有一个Address类型的引用成员变量。
package com.hxstrive.java_lang.cloneable; /** * @author hxstrive */ public class CloneableDemo2 { public static void main(String[] args) { try { // Address对象 Address originalAddress = new Address("New York"); // Person2对象 Person2 originalPerson = new Person2("Bob", 25, originalAddress); // 克隆的 Person2 对象 Person2 clonedPerson = originalPerson.clone(); System.out.println("Original Person's Address City: " + originalPerson.getAddress().getCity()); System.out.println("Cloned Person's Address City: " + clonedPerson.getAddress().getCity()); // 修改原始对象的引用类型成员变量的值 originalAddress.setCity("Los Angeles"); System.out.println("Original Person's Address City after change: " + originalPerson.getAddress().getCity()); System.out.println("Cloned Person's Address City after change: " + clonedPerson.getAddress().getCity()); } catch (CloneNotSupportedException e) { e.printStackTrace(); } } } class Person2 implements Cloneable { private String name; private int age; private Address address; // 引用类型成员变量 public Person2(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 public Person2 clone() throws CloneNotSupportedException { return (Person2) super.clone(); } } 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; } }
运行结果:
在这个例子中,当修改原始 Person2 对象的 Address 对象的城市名称时,克隆后的 Person2 对象的Address 城市名称也会改变,因为它们共享同一个 Address 对象引用。
深克隆不仅复制对象的基本类型成员变量,还会递归地复制引用类型成员变量所指向的对象,使得克隆后的对象和原始对象在引用类型成员变量上也是完全独立的。
示例:修改 Person 类的 clone() 方法来实现深克隆。
package com.hxstrive.java_lang.cloneable; /** * Cloneable 示例 * @author hxstrive */ public class CloneableDemo3 { public static void main(String[] args) { try { Address3 originalAddress = new Address3("New York"); Person3 originalPerson = new Person3("Bob", 25, originalAddress); // 原始对象 Person3 clonedPerson = originalPerson.clone(); // 克隆对象 System.out.println("Original Person's Address City: " + originalPerson.getAddress().getCity()); System.out.println("Cloned Person's Address City: " + clonedPerson.getAddress().getCity()); // 修改原始对象中的地址对象信息 originalAddress.setCity("Los Angeles"); System.out.println("Original Person's Address City after change: " + originalPerson.getAddress().getCity()); System.out.println("Cloned Person's Address City after change: " + clonedPerson.getAddress().getCity()); } catch (CloneNotSupportedException e) { e.printStackTrace(); } } } class Address3 implements Cloneable { private String city; public Address3(String city) { this.city = city; } @Override public Address3 clone() throws CloneNotSupportedException { return (Address3) super.clone(); } public String getCity() { return city; } public void setCity(String city) { this.city = city; } } class Person3 implements Cloneable { private String name; private int age; private Address3 address; // 引用类型成员变量 public Person3(String name, int age, Address3 address) { this.name = name; this.age = age; this.address = address; } @Override public Person3 clone() throws CloneNotSupportedException { Person3 cloned = (Person3) super.clone(); cloned.address = this.address.clone(); return cloned; } 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 Address3 getAddress() { return address; } public void setAddress(Address3 address) { this.address = address; } }
运行结果:
现在,当修改原始 Person3 对象的 Address3 对象的城市名称时,克隆后的 Person3 对象的 Address3 城市名称不会改变,因为它们有各自独立的 Address3 对象。