您的位置:

Java对象深拷贝

一、初探对象深拷贝

对象深拷贝,在某些场合下是非常有必要的,因为我们想要充分利用对象的复用。例如,我们有一个学生类Student,其中有一个List的成员属性courses。当我们需要对某一个学生进行处理的时候,为了避免直接修改原有的courses属性,我们需要进行对象深拷贝。在Java中,对象深拷贝可以通过两种方式实现:第一种方式是使用Serializable序列化和反序列化,第二种方式是使用Cloneable接口和clone方法。

二、序列化和反序列化实现对象深拷贝

Serializable序列化和反序列化是一种比较常用的方法实现对象深拷贝,它可以把一个对象序列化为字节流,再把字节流反序列化为一个新的对象,从而实现对象深拷贝。

public class Student implements Serializable {
    private String name;
    private int age;
    private List courses;

    public Student(String name, int age, List
    courses) {
        this.name = name;
        this.age = age;
        this.courses = courses;
    }

    public static void main(String[] args) throws Exception {
        List
     courses = new ArrayList<>();
        courses.add("Math");
        courses.add("Physics");
        courses.add("Chemistry");
        Student student = new Student("Tom", 20, courses);

        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("student.txt"));
        objectOutputStream.writeObject(student);
        objectOutputStream.close();

        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("student.txt"));
        Student cloneStudent = (Student) objectInputStream.readObject();
        objectInputStream.close();

        System.out.println(student == cloneStudent);
        System.out.println(student.equals(cloneStudent));
    }
}

    
   
  

在上述代码中,我们首先创建了一个Student对象,并将其序列化到文件student.txt中。接着,我们再从文件student.txt中通过反序列化方式读取一个新的对象cloneStudent。最后,我们使用==和equals方法比较了原有的对象student和新的对象cloneStudent。通过运行结果,我们可以发现两个对象物理地址不同,但是它们的值是相同的,即序列化和反序列化实现了对象深拷贝。

三、Cloneable接口和clone方法实现对象深拷贝

Cloneable接口和clone方法是另一种实现对象深拷贝的方式。需要注意,如果需要使用clone方法实现对象深拷贝,需要保证被拷贝的对象及其所有引用类型的属性都实现了Cloneable接口,并且重写了clone方法。

public class Student implements Cloneable {
    private String name;
    private int age;
    private List courses;

    public Student(String name, int age, List
    courses) {
        this.name = name;
        this.age = age;
        this.courses = courses;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Student cloneStudent = (Student) super.clone();
        cloneStudent.courses = new ArrayList<>(this.courses);
        return cloneStudent;
    }

    public static void main(String[] args) throws Exception {
        List
     courses = new ArrayList<>();
        courses.add("Math");
        courses.add("Physics");
        courses.add("Chemistry");
        Student student = new Student("Tom", 20, courses);

        Student cloneStudent = (Student) student.clone();
        System.out.println(student == cloneStudent);
        System.out.println(student.equals(cloneStudent));
    }
}

    
   
  

在上述代码中,我们首先创建了一个Student对象,然后使用clone方法创建了一个新的对象cloneStudent。需要注意的是,在clone方法中,我们手动对List类型的属性进行了深拷贝。最后,我们使用==和equals方法比较了原有的对象student和新的对象cloneStudent。通过运行结果,我们可以发现两个对象物理地址不同,但是它们的值是相同的,即clone方法实现了对象深拷贝。

四、对比Serializable序列化和反序列化和Cloneable接口和clone方法的区别

Serializable序列化和反序列化和Cloneable接口和clone方法都可以实现对象深拷贝,它们之间有如下的区别:

1、Cloneable接口和clone方法方式要比Serializable序列化和反序列化效率更高,因为前者是在内存中复制对象,而后者需要进行IO操作以及序列化、反序列化等复杂的操作。

2、Cloneable接口和clone方法方式要求被克隆对象及其所有引用类型的属性都必须实现Cloneable接口,并且重写了clone方法。而Serializable序列化和反序列化方式没有这个要求。

3、Cloneable接口和clone方法方式克隆的对象与原有对象不共享引用类型的属性,即是真正的深拷贝。而Serializable序列化和反序列化方式克隆的对象和原有对象共享引用类型的属性,不是真正的深拷贝。

五、总结

对象深拷贝是Java编程中非常重要的一项技术。它可以让我们在复用对象的同时,避免对原有对象的影响。在Java中,实现对象深拷贝一般可以使用Serializable序列化和反序列化和Cloneable接口和clone方法两种方式。我们需要根据具体的场合和应用来选择不同的方式实现对象深拷贝。