一、淺拷貝與深拷貝
拷貝對象在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-hant/n/289107.html
微信掃一掃
支付寶掃一掃