一、什么是深拷贝
在Java对象的拷贝过程中,有时候只是单纯的复制了引用,指向同一个对象,在这种情况下,对拷贝后的对象进行修改,会直接影响原对象,这就是浅拷贝。而深拷贝则是在拷贝的过程中对所有的属性和引用对象都进行重新创建,使得原对象和拷贝后的对象完全独立。
下面是一个浅拷贝和深拷贝的示例代码:
// 浅拷贝示例 class Person1 implements Cloneable { public int age; public Listskills; @Override public Object clone() throws CloneNotSupportedException { return super.clone(); } } Person1 p1 = new Person1(); p1.age = 18; p1.skills = new ArrayList<>(Arrays.asList("Java", "Python", "C")); Person1 p2 = (Person1) p1.clone(); p2.skills.add("PHP"); System.out.println(p1.skills); // [Java, Python, C, PHP]
// 深拷贝示例 class Person2 implements Cloneable { public int age; public Listskills; @Override public Object clone() throws CloneNotSupportedException { Person2 person = (Person2) super.clone(); person.skills = new ArrayList<>(skills); return person; } } Person2 p1 = new Person2(); p1.age = 18; p1.skills = new ArrayList<>(Arrays.asList("Java", "Python", "C")); Person2 p2 = (Person2) p1.clone(); p2.skills.add("PHP"); System.out.println(p1.skills); // [Java, Python, C]
二、使用Java自带的Cloneable接口进行深拷贝
Java提供了一个Cloneable接口,实现该接口的类可以使用clone方法进行对象的拷贝。在进行深拷贝时,需要在clone方法中对引用类型的属性进行重新创建,避免共用同一个对象。
示例代码:
class Person implements Cloneable { public int age; public Listskills; @Override public Object clone() throws CloneNotSupportedException { Person person = (Person) super.clone(); person.skills = new ArrayList<>(skills); return person; } } Person p1 = new Person(); p1.age = 18; p1.skills = new ArrayList<>(Arrays.asList("Java", "Python", "C")); Person p2 = (Person) p1.clone(); p2.skills.add("PHP"); System.out.println(p1.skills); // [Java, Python, C]
三、使用序列化实现深拷贝
另一种实现深拷贝的方法是使用Java的序列化机制。通过把对象序列化成二进制流,再将其反序列化生成新对象,可以得到完全独立的对象。需要注意的是,被拷贝的类及其引用对象都需要实现序列化接口。
示例代码:
class Person implements Serializable { public int age; public Listskills; public Person deepCopy() throws IOException, ClassNotFoundException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(this); ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bais); return (Person) ois.readObject(); } } Person p1 = new Person(); p1.age = 18; p1.skills = new ArrayList<>(Arrays.asList("Java", "Python", "C")); Person p2 = p1.deepCopy(); p2.skills.add("PHP"); System.out.println(p1.skills); // [Java, Python, C]
四、使用第三方库实现深拷贝
除了Java自带的Cloneable接口和序列化机制外,还可以借用第三方库来实现深拷贝。例如Apache Commons库提供的SerializationUtils.copy方法,该方法可以将一个对象序列化,再反序列化生成新的对象。
示例代码:
class Person { public int age; public Listskills; } Person p1 = new Person(); p1.age = 18; p1.skills = new ArrayList<>(Arrays.asList("Java", "Python", "C")); Person p2 = SerializationUtils.clone(p1); p2.skills.add("PHP"); System.out.println(p1.skills); // [Java, Python, C]