在Java開發過程中,經常需要針對對象進行拷貝操作。這是因為,在某些場景下,我們需要創建新的對象,但是這些新的對象需要與已有的對象具有相同的屬性值。
本文將介紹多種Java對象拷貝的實現方式,包括深拷貝、淺拷貝、序列化、BeanUtils、Cloneable等方式,並對每種方式的優缺點進行比較和討論。
一、深拷貝
深拷貝是指拷貝對象的所有屬性,包括對象中的引用類型屬性。當對象中存在引用類型的屬性時,深拷貝將會遞歸地拷貝該引用類型的對象。
1. 方式一:手動拷貝
手動拷貝方式是最原始的實現方式,通過遍歷對象中的每一個屬性,遞歸拷貝對象中的引用類型屬性。下面是一個示例:
public class Person { private String name; private Address address; // 省略 getter 和 setter 方法 public Person deepClone() { Person newPerson = new Person(); newPerson.setName(this.getName()); Address newAddress = new Address(); newAddress.setCity(this.getAddress().getCity()); newAddress.setStreet(this.getAddress().getStreet()); newPerson.setAddress(newAddress); return newPerson; } } public class Address { private String city; private String street; // 省略 getter 和 setter 方法 } public class Demo { public static void main(String[] args) { Person person = new Person(); person.setName("張三"); Address address = new Address(); address.setCity("杭州"); address.setStreet("西湖區"); person.setAddress(address); Person newPerson = person.deepClone(); } }
2. 方式二:序列化
使用序列化方式也可以實現對象的深拷貝,不需要手動遞歸拷貝對象中的引用類型屬性。但是,被拷貝的對象以及對象中的所有引用類型屬性都需要實現序列化接口。下面是一個示例:
public class Person implements Serializable { private static final long serialVersionUID = 1L; private String name; private Address address; // 省略 getter 和 setter 方法 public Person deepClone() 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(); } } public class Address implements Serializable { private static final long serialVersionUID = 1L; private String city; private String street; // 省略 getter 和 setter 方法 } public class Demo { public static void main(String[] args) { Person person = new Person(); person.setName("張三"); Address address = new Address(); address.setCity("杭州"); address.setStreet("西湖區"); person.setAddress(address); Person newPerson = person.deepClone(); } }
二、淺拷貝
淺拷貝是指只拷貝對象的基本類型屬性,不拷貝對象中的引用類型屬性。拷貝之後的對象與原對象共享引用類型屬性的內存地址。
1. Cloneable接口實現
Cloneable接口是一個標記接口,實現該接口的對象可以被克隆。但是,需要注意的是,Cloneable接口並沒有定義任何方法。如果要實現Cloneable接口,需要重寫Object類中的clone()方法,並且為該方法添加public修飾符。
public class Address { private String city; private String street; // 省略 getter 和 setter 方法 } public class Person implements Cloneable { private String name; private Address address; // 省略 getter 和 setter 方法 @Override public Person clone() throws CloneNotSupportedException { return (Person) super.clone(); } } public class Demo { public static void main(String[] args) throws CloneNotSupportedException { Person person = new Person(); person.setName("張三"); Address address = new Address(); address.setCity("杭州"); address.setStreet("西湖區"); person.setAddress(address); Person newPerson = person.clone(); } }
2. BeanUtils.copyProperties()
BeanUtils.copyProperties()是一個高效便捷的對象屬性拷貝工具,可以將源對象的屬性值拷貝到目標對象中。但是,BeanUtils.copyProperties()只能實現淺拷貝,無法拷貝引用類型屬性。
public class Address { private String city; private String street; // 省略 getter 和 setter 方法 } public class Person { private String name; private Address address; // 省略 getter 和 setter 方法 } public class Demo { public static void main(String[] args) throws InvocationTargetException, IllegalAccessException { Person person = new Person(); person.setName("張三"); Address address = new Address(); address.setCity("杭州"); address.setStreet("西湖區"); person.setAddress(address); Person newPerson = new Person(); BeanUtils.copyProperties(newPerson, person); } }
三、總結
本文介紹了Java中多種對象拷貝的實現方式,以及每種方式的優缺點和適用場景。在選擇對象拷貝方式時,需要根據拷貝的深度、效率和對原對象屬性的影響等方面進行綜合考慮,以選取最合適的方式。
原創文章,作者:VCWL,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/148847.html