一、初探对象深拷贝
对象深拷贝,在某些场合下是非常有必要的,因为我们想要充分利用对象的复用。例如,我们有一个学生类Student,其中有一个List的成员属性courses。当我们需要对某一个学生进行处理的时候,为了避免直接修改原有的courses属性,我们需要进行对象深拷贝。在Java中,对象深拷贝可以通过两种方式实现:第一种方式是使用Serializable序列化和反序列化,第二种方式是使用Cloneable接口和clone方法。
二、序列化和反序列化实现对象深拷贝
Serializable序列化和反序列化是一种比较常用的方法实现对象深拷贝,它可以把一个对象序列化为字节流,再把字节流反序列化为一个新的对象,从而实现对象深拷贝。
public class Student implements Serializable { private String name; private int age; private Listcourses; 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 Listcourses; 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方法两种方式。我们需要根据具体的场合和应用来选择不同的方式实现对象深拷贝。