一、淺拷貝與深拷貝
拷貝對象在Java程序中是一個常見的操作,通常有兩種拷貝方式:淺拷貝和深拷貝。
淺拷貝是指只複製了對象的引用,如果原對象的引用類型屬性被修改了,那麼拷貝後的對象的引用類型屬性也會被修改。此時Java中的clone()方法默認實現就是淺拷貝,只需要實現Cloneable介面,重寫clone()方法即可實現淺拷貝。
public class Person implements Cloneable { private String name; private int age; private List hobbies; public Object clone() { try { return super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); return null; } } } Person p1 = new Person(); p1.setName("Alice"); p1.setAge(20); List list = new ArrayList(); list.add("reading"); list.add("writing"); p1.setHobbies(list); Person p2 = (Person)p1.clone(); System.out.println(p2.getName()); // Alice System.out.println(p2.getHobbies()); // [reading, writing] list.add("swimming"); System.out.println(p1.getHobbies()); // [reading, writing, swimming] System.out.println(p2.getHobbies()); // [reading, writing, swimming]
深拷貝則是將原對象的引用類型屬性也複製一份出來,獨立於原對象以及拷貝出來的對象之外。這樣在修改原對象引用類型屬性時,拷貝出來的對象不會受到影響。常見的實現方式有序列化與反序列化、Apache Commons BeanUtils、Spring BeanUtils等。
//使用序列化與反序列化實現深拷貝 public static T deepClone(T obj) throws IOException, ClassNotFoundException { ByteArrayOutputStream out = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(out); oos.writeObject(obj); ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); ObjectInputStream ois = new ObjectInputStream(in); return (T)ois.readObject(); } Person p1 = new Person(); p1.setName("Alice"); p1.setAge(20); List list = new ArrayList(); list.add("reading"); list.add("writing"); p1.setHobbies(list); Person p2 = deepClone(p1); System.out.println(p2.getName()); // Alice System.out.println(p2.getHobbies()); // [reading, writing] list.add("swimming"); System.out.println(p1.getHobbies()); // [reading, writing, swimming] System.out.println(p2.getHobbies()); // [reading, writing]
二、實現Cloneable介面
實現Cloneable介面是實現對象拷貝功能的一種方式,但是需要注意以下幾點:
1、實現Cloneable介面並重寫clone()方法時,clone()方法的訪問控制符應該為public,並且方法內部需要進行異常處理。
2、被拷貝的對象及其引用類型屬性都需要實現Cloneable介面或者是基本數據類型。
3、實現Cloneable介面的對象屬性不能使用final修飾符。
三、序列化與反序列化實現深拷貝
序列化與反序列化也是一種常見的實現深拷貝的方式,具體實現方法可以使用Java的序列化機制,序列化時將對象寫入到位元組流中,反序列化時從位元組流中讀取對象。實現方式如下:
public static T deepClone(T obj) throws IOException, ClassNotFoundException { ByteArrayOutputStream out = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(out); oos.writeObject(obj); ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); ObjectInputStream ois = new ObjectInputStream(in); return (T)ois.readObject(); } Person p1 = new Person(); p1.setName("Alice"); p1.setAge(20); List list = new ArrayList(); list.add("reading"); list.add("writing"); p1.setHobbies(list); Person p2 = deepClone(p1); System.out.println(p2.getName()); // Alice System.out.println(p2.getHobbies()); // [reading, writing] list.add("swimming"); System.out.println(p1.getHobbies()); // [reading, writing, swimming] System.out.println(p2.getHobbies()); // [reading, writing]
四、Apache Commons BeanUtils實現深拷貝
Apache Commons BeanUtils是一個Java類庫,提供各種操作JavaBean的工具,其中就包括實現深拷貝的方法。但是使用時需要注意以下問題:
1、實現深拷貝的對象屬性需要提供get和set方法,並且對應的屬性也需要提供get和set方法。
2、不支持普通的List、Set等集合對象的深拷貝,需要使用Apache Commons Collections提供的工具類。
public static T deepClone(T obj) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException { T newObj = (T)obj.getClass().newInstance(); BeanUtils.copyProperties(newObj, obj); return newObj; } Person p1 = new Person(); p1.setName("Alice"); p1.setAge(20); List list = new ArrayList(); list.add("reading"); list.add("writing"); p1.setHobbies(list); Person p2 = deepClone(p1); System.out.println(p2.getName()); // Alice System.out.println(p2.getHobbies()); // [reading, writing] list.add("swimming"); System.out.println(p1.getHobbies()); // [reading, writing, swimming] System.out.println(p2.getHobbies()); // [reading, writing]
五、Spring BeanUtils實現深拷貝
Spring BeanUtils也提供了一種實現深拷貝的方法,與Apache Commons BeanUtils類似,但是Spring BeanUtils需要使用反射機制,使用時需要注意以下問題:
1、實現深拷貝的對象屬性需要提供get和set方法,並且對應的屬性也需要提供get和set方法。
2、如果對象中有Date或者Calendar類型的屬性,需要設置特殊的轉換器。
public static T deepClone(T obj) { T newObj = (T)ReflectionUtils.newInstance(obj.getClass()); BeanUtils.copyProperties(obj, newObj); return newObj; } Person p1 = new Person(); p1.setName("Alice"); p1.setAge(20); List list = new ArrayList(); list.add("reading"); list.add("writing"); p1.setHobbies(list); Person p2 = deepClone(p1); System.out.println(p2.getName()); // Alice System.out.println(p2.getHobbies()); // [reading, writing] list.add("swimming"); System.out.println(p1.getHobbies()); // [reading, writing, swimming] System.out.println(p2.getHobbies()); // [reading, writing]
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/289107.html