Cloneable 接口:一个标记接口,表明一个类可以被克隆

Cloneable 接口是一个标记接口(也称为标记型接口,它没有任何方法定义),位于 java.lang 包中。它的存在是为了表明一个类可以被克隆。当一个类实现了 Cloneable 接口后,就可以使用 Object 类的 clone() 方法来创建该类的一个副本。

Cloneable 接口是一个标记接口(也称为标记型接口,它没有任何方法定义),位于 java.lang 包中。它的存在是为了表明一个类可以被克隆。当一个类实现了 Cloneable 接口后,就可以使用 Object 类的 clone() 方法来创建该类的一个副本。

提供一种简单的对象复制机制,在某些情况下可以方便地创建对象的副本,比如在需要保留对象原始状态的备份,或者快速创建一个具有相似初始状态的新对象等场景。

实现 Cloneable 接口的步骤和示例

步骤一:实现 Cloneable 接口

首先,在自定义类中声明实现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 () 方法

因为 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;
    }
}

运行结果:

3448d8d6b844b379d65844b7600f8408_1737007454473-ec578d87-b62b-4b13-a9e1-e5a4ece4c46d_x-oss-process=image%2Fformat%2Cwebp.png

在这个例子中,当修改原始 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;
    }
}

运行结果:

ce7b1abfb90780169446b25f049318bf_1737007917515-a5a034d8-b3cd-4323-aa70-e47de540cb39_x-oss-process=image%2Fformat%2Cwebp.png

现在,当修改原始 Person3  对象的 Address3  对象的城市名称时,克隆后的 Person3  对象的 Address3  城市名称不会改变,因为它们有各自独立的 Address3  对象。

学习有两忌,自高和自狭。 —— 书摘
0 不喜欢
说说我的看法 -
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
公众号