Java中淺拷貝與深拷貝實例解析
前言
在Java中,對象的拷貝有兩種方式:淺拷貝和深拷貝。它們分別代表了不同的拷貝方式,拷貝出的新對象與原始對象之間存在一定的差異。本文將詳細(xì)介紹淺拷貝和深拷貝的概念、特點和實現(xiàn)方式,并且通過實例進(jìn)行解析。
一、淺拷貝
淺拷貝是指在對一個對象進(jìn)行拷貝時,只拷貝對象本身和其中的基本數(shù)據(jù)類型,而不拷貝對象內(nèi)部的引用類型。因此,在淺拷貝的對象中,引用類型的變量指向的依舊是原始對象中的引用。
在Java中,實現(xiàn)淺拷貝可以使用Object類的clone()方法,或者手動重寫類的clone()方法。下面是一個示例:
class Person implements Cloneable { ? ? private String name; ? ? private Address address; ? ? public Person(String name, Address address) { ? ? ? ? this.name = name; ? ? ? ? this.address = address; ? ? } ? ? @Override ? ? protected Object clone() throws CloneNotSupportedException { ? ? ? ? return super.clone(); ? ? } } class Address { ? ? private String city; ? ? public Address(String city) { ? ? ? ? this.city = city; ? ? } } public class Test { ? ? public static void main(String[] args) throws Exception { ? ? ? ? Address address = new Address("Beijing"); ? ? ? ? Person person1 = new Person("Tom", address); ? ? ? ? Person person2 = (Person) person1.clone(); ? ? ? ? System.out.println(person1 == person2); // false ? ? ? ? System.out.println(person1.getAddress() == person2.getAddress()); // true ? ? } }
在上述代碼中,我們定義了一個Person類和Address類。Person類中包含一個引用類型的成員變量address。使用Object類的clone()方法進(jìn)行拷貝,并且在Person類中實現(xiàn)了Cloneable接口,并重寫了clone()方法,使得Person類可以進(jìn)行拷貝。
在main函數(shù)中,我們創(chuàng)建了一個Person對象person1,其中包含一個Address對象。接著,我們使用person1的clone()方法創(chuàng)建了一個新的Person對象person2,并使用“==”判斷person1和person2是否是同一對象。結(jié)果為false,證明兩個對象是不同的。接下來,我們使用“==”判斷person1和person2中的address是否是同一對象,結(jié)果為true,即兩個對象的address成員變量指向的是同一個地址。
總的來說,淺拷貝只是將原始對象的引用類型成員變量復(fù)制到新的對象中,因此新對象中的引用類型成員變量與原始對象中的成員變量指向同一對象。如果原始對象中的引用類型成員變量發(fā)生變化,新對象中的引用類型成員變量也會隨之變化。
二、深拷貝
深拷貝是指在對一個對象進(jìn)行拷貝時,不僅拷貝對象本身和其中的基本數(shù)據(jù)類型,同時也拷貝對象內(nèi)部的引用類型。因此,在深拷貝的對象中,引用類型的變量指向的是全新的對象。
在Java中,實現(xiàn)深拷貝的方式比較多,可以使用對象的序列化、手動編寫clone()方法等。下面是一個使用對象序列化來實現(xiàn)深拷貝的例子:
import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; public class Test { ? ? public static void main(String[] args) throws Exception { ? ? ? ? Address address = new Address("Beijing"); ? ? ? ? Person person1 = new Person("Tom", address); ? ? ? ? Person person2 = (Person) deepCopy(person1); ? ? ? ? System.out.println(person1 == person2); // false ? ? ? ? System.out.println(person1.getAddress() == person2.getAddress()); // false ? ? } ? ? private static Object deepCopy(Object obj) throws Exception { ? ? ? ? ByteArrayOutputStream bos = new ByteArrayOutputStream(); ? ? ? ? ObjectOutputStream oos = new ObjectOutputStream(bos); ? ? ? ? oos.writeObject(obj); ? ? ? ? ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ? ? ? ? ObjectInputStream ois = new ObjectInputStream(bis); ? ? ? ? return ois.readObject(); ? ? } } class Person implements Serializable { ? ? private String name; ? ? private Address address; ? ? ?public Person(String name, Address address) { ? ? ? ? this.name = name; ? ? ? ? this.address = address; ? ? } ? ? public Address getAddress() { ? ? ? ? return address; ? ? } } class Address implements Serializable { ? ? private String city; ? ? ?public Address(String city) { ? ? ? ? this.city = city; ? ? } }
在上述代碼中,我們定義了一個Person類和Address類,并且讓它們都實現(xiàn)了Serializable接口。在main函數(shù)中,我們創(chuàng)建了一個Person對象person1,其中包含一個Address對象。接著,我們使用deepCopy()方法創(chuàng)建了一個新的Person對象person2,并使用“==”判斷person1和person2是否是同一對象。結(jié)果為false,證明兩個對象是不同的。接下來,我們使用“==”判斷person1和person2中的address是否是同一對象,結(jié)果為false,即兩個對象的address成員變量指向的是不同的地址。
在上述代碼中,我們使用了一個deepCopy()方法來實現(xiàn)對象的深拷貝。該方法使用對象的序列化和反序列化來實現(xiàn)深拷貝。首先,將原始對象序列化成字節(jié)數(shù)組,然后再將字節(jié)數(shù)組反序列化成新的對象。這樣可以保證復(fù)制出的新對象與原始對象完全獨立,不會相互影響。
總結(jié):
淺拷貝和深拷貝是Java中常用的兩種對象拷貝方式。淺拷貝只會復(fù)制對象內(nèi)部的基本數(shù)據(jù)類型和引用類型變量的引用,而深拷貝會將對象內(nèi)部所有的基本類型和引用類型都復(fù)制一份。使用clone()方法和重寫clone()方法可以實現(xiàn)淺拷貝,使用對象序列化或手動復(fù)制可以實現(xiàn)深拷貝。在實現(xiàn)對象拷貝時需要根據(jù)具體情況選擇合適的拷貝方式,以保證復(fù)制出的新對象能夠滿足應(yīng)用需求。
到此這篇關(guān)于Java中淺拷貝與深拷貝的文章就介紹到這了,更多相關(guān)Java淺拷貝與深拷貝內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MybatisPlus查詢數(shù)據(jù)日期格式化問題解決方法
MyBatisPlus是MyBatis的增強工具,支持常規(guī)的CRUD操作以及復(fù)雜的聯(lián)表查詢等功能,這篇文章主要給大家介紹了關(guān)于MybatisPlus查詢數(shù)據(jù)日期格式化問題的解決方法,需要的朋友可以參考下2023-10-10Java中volatile關(guān)鍵字的作用是什么舉例詳解
這篇文章主要介紹了Java中volatile關(guān)鍵字的作用是什么的相關(guān)資料,volatile關(guān)鍵字在Java中用于修飾變量,提供可見性和禁止指令重排的特性,但不保證原子性,它通過內(nèi)存屏障實現(xiàn)這些特性,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2025-04-04Java中Collection和Collections的區(qū)別
Collection是一個集合接口,集合類的頂級接口,Collections是一個包裝類,本文主要介紹了Java中Collection和Collections的區(qū)別,具有一定的參考價值,感興趣的可以了解一下2024-04-04Springboot實現(xiàn)多數(shù)據(jù)源切換詳情
這篇文章主要介紹了Springboot實現(xiàn)多數(shù)據(jù)源切換詳情,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價值,感興趣的朋友可以參考一下2022-09-09