java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java克隆技术及深拷贝与浅拷贝

一文搞懂Java克隆及深拷贝与浅拷贝的区别

作者:蜀山剑客李沐白

在编程中,通常通过实现Cloneable接口和重写clone方法来实现对象的克隆,然而,需要注意的是克隆操作可能存在深拷贝和浅拷贝的区别,在使用时需要根据实际需求选择合适的克隆方式,本文就给大家详细讲讲什么是克隆以及深拷贝与浅拷贝的区别,需要的朋友可以参考下

什么是克隆,为什么在编程中使用克隆

克隆是指创建一个对象的副本,使得新创建的对象在内容上与原始对象相同。在编程中,克隆是常用的技术之一,它具有以下几个重要用途和优势:

在编程中,通常通过实现Cloneable接口和重写clone方法来实现对象的克隆。然而,需要注意的是克隆操作可能存在深拷贝和浅拷贝的区别,在使用时需要根据实际需求选择合适的克隆方式。

什么是深拷贝和浅拷贝

深拷贝(Deep Copy)和浅拷贝(Shallow Copy)是在克隆(Clone)操作中经常遇到的两个概念,它们描述了克隆操作对于对象内部引用的处理方式。

为了实现深拷贝,需要对对象内部的引用类型属性进行递归复制。常见的实现深拷贝的方式包括:

需要注意的是,并非所有对象都能进行深拷贝。某些对象或者类中的属性可能是不可变的,无需拷贝;某些对象可能包含循环引用,无法完全复制。因此,在进行克隆操作时,需要根据具体情况选择合适的拷贝方式。

深拷贝和浅拷贝的主要区别在于对于对象内部引用类型属性的处理方式。

浅拷贝示例

实现 Cloneable 接口和重写 clone() 方法:

下面是一个示例代码,演示了如何使用 Cloneable 接口和 clone() 方法实现浅拷贝:

class Person implements Cloneable {
    private String name;
    private int age;
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public int getAge() {
        return age;
    }
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
public class Main {
    public static void main(String[] args) {
        Person person1 = new Person("Alice", 25);
        try {
            // 浅拷贝
            Person person2 = (Person) person1.clone();
            System.out.println(person1.getName() + " " + person1.getAge()); // Alice 25
            System.out.println(person2.getName() + " " + person2.getAge()); // Alice 25
            person2.setName("Bob");
            person2.setAge(30);
            System.out.println(person1.getName() + " " + person1.getAge()); // Alice 25
            System.out.println(person2.getName() + " " + person2.getAge()); // Bob 30
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

在上述示例中,我们创建了一个 Person 类,并实现了 Cloneable 接口。在 clone() 方法中直接调用了父类的 clone() 方法,并进行了类型转换。通过调用 clone() 方法,可以得到一个新的对象 person2,它与原始对象 person1 具有相同的属性值。当修改 person2 的属性时,不会影响到 person1

深拷贝示例

使用序列化和反序列化:

下面是一个示例代码,演示了如何使用序列化和反序列化实现深拷贝:

import java.io.*;
class Address implements Serializable {
    private String city;
    private String street;
    public Address(String city, String street) {
        this.city = city;
        this.street = street;
    }
    public void setCity(String city) {
        this.city = city;
    }
    public void setStreet(String street) {
        this.street = street;
    }
    public String getCity() {
        return city;
    }
    public String getStreet() {
        return street;
    }
}
class Person implements Serializable {
    private String name;
    private int age;
    private Address address;
    public Person(String name, int age, Address address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public void setAddress(Address address) {
        this.address = address;
    }
    public String getName() {
        return name;
    }
    public int getAge() {
        return age;
    }
    public Address getAddress() {
        return address;
    }
}
public class Main {
    public static void main(String[] args) {
        Address address = new Address("City", "Street");
        Person person1 = new Person("Alice", 25, address);
        // 深拷贝
        Person person2 = deepCopy(person1);
        System.out.println(person1.getName() + " " + person1.getAge() + " " + person1.getAddress().getCity()); // Alice 25 City
        System.out.println(person2.getName() + " " + person2.getAge() + " " + person2.getAddress().getCity()); // Alice 25 City
        person2.setName("Bob");
        person2.setAge(30);
        person2.getAddress().setCity("New City");
        System.out.println(person1.getName() + " " + person1.getAge() + " " + person1.getAddress().getCity()); // Alice 25 City
        System.out.println(person2.getName() + " " + person2.getAge() + " " + person2.getAddress().getCity()); // Bob 30 New City
    }
    public static <T extends Serializable> T deepCopy(T object) {
        try {
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
            objectOutputStream.writeObject(object);
            objectOutputStream.flush();
            ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
            ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
            return (T) objectInputStream.readObject();
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
            return null;
        }
    }
}

在上述示例中,我们创建了一个 Address 类和一个 Person 类,它们都实现了 Serializable 接口。通过序列化和反序列化操作,我们可以实现深拷贝。在 deepCopy() 方法中,我们使用字节流将对象写入到内存中,并从内存中读取出来,从而得到一个新的独立对象。通过调用 deepCopy() 方法,可以得到一个新的对象 person2,它与原始对象 person1 完全独立。在修改 person2 的属性时,不会影响到 person1。 值得注意的是,要实现深拷贝,所有相关的类都需要实现 Serializable 接口。

深拷贝和浅拷贝的区别

深拷贝(Deep Copy):

浅拷贝(Shallow Copy):

以上就是一文搞懂Java克隆技术及深拷贝与浅拷贝的区别的详细内容,更多关于Java克隆技术及深拷贝与浅拷贝的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文