Java中淺拷貝與深拷貝實(shí)例解析
前言
在Java中,對(duì)象的拷貝有兩種方式:淺拷貝和深拷貝。它們分別代表了不同的拷貝方式,拷貝出的新對(duì)象與原始對(duì)象之間存在一定的差異。本文將詳細(xì)介紹淺拷貝和深拷貝的概念、特點(diǎn)和實(shí)現(xiàn)方式,并且通過實(shí)例進(jìn)行解析。
一、淺拷貝
淺拷貝是指在對(duì)一個(gè)對(duì)象進(jìn)行拷貝時(shí),只拷貝對(duì)象本身和其中的基本數(shù)據(jù)類型,而不拷貝對(duì)象內(nèi)部的引用類型。因此,在淺拷貝的對(duì)象中,引用類型的變量指向的依舊是原始對(duì)象中的引用。
在Java中,實(shí)現(xiàn)淺拷貝可以使用Object類的clone()方法,或者手動(dòng)重寫類的clone()方法。下面是一個(gè)示例:
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 ? ? } }
在上述代碼中,我們定義了一個(gè)Person類和Address類。Person類中包含一個(gè)引用類型的成員變量address。使用Object類的clone()方法進(jìn)行拷貝,并且在Person類中實(shí)現(xiàn)了Cloneable接口,并重寫了clone()方法,使得Person類可以進(jìn)行拷貝。
在main函數(shù)中,我們創(chuàng)建了一個(gè)Person對(duì)象person1,其中包含一個(gè)Address對(duì)象。接著,我們使用person1的clone()方法創(chuàng)建了一個(gè)新的Person對(duì)象person2,并使用“==”判斷person1和person2是否是同一對(duì)象。結(jié)果為false,證明兩個(gè)對(duì)象是不同的。接下來,我們使用“==”判斷person1和person2中的address是否是同一對(duì)象,結(jié)果為true,即兩個(gè)對(duì)象的address成員變量指向的是同一個(gè)地址。
總的來說,淺拷貝只是將原始對(duì)象的引用類型成員變量復(fù)制到新的對(duì)象中,因此新對(duì)象中的引用類型成員變量與原始對(duì)象中的成員變量指向同一對(duì)象。如果原始對(duì)象中的引用類型成員變量發(fā)生變化,新對(duì)象中的引用類型成員變量也會(huì)隨之變化。
二、深拷貝
深拷貝是指在對(duì)一個(gè)對(duì)象進(jìn)行拷貝時(shí),不僅拷貝對(duì)象本身和其中的基本數(shù)據(jù)類型,同時(shí)也拷貝對(duì)象內(nèi)部的引用類型。因此,在深拷貝的對(duì)象中,引用類型的變量指向的是全新的對(duì)象。
在Java中,實(shí)現(xiàn)深拷貝的方式比較多,可以使用對(duì)象的序列化、手動(dòng)編寫clone()方法等。下面是一個(gè)使用對(duì)象序列化來實(shí)現(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; ? ? } }
在上述代碼中,我們定義了一個(gè)Person類和Address類,并且讓它們都實(shí)現(xiàn)了Serializable接口。在main函數(shù)中,我們創(chuàng)建了一個(gè)Person對(duì)象person1,其中包含一個(gè)Address對(duì)象。接著,我們使用deepCopy()方法創(chuàng)建了一個(gè)新的Person對(duì)象person2,并使用“==”判斷person1和person2是否是同一對(duì)象。結(jié)果為false,證明兩個(gè)對(duì)象是不同的。接下來,我們使用“==”判斷person1和person2中的address是否是同一對(duì)象,結(jié)果為false,即兩個(gè)對(duì)象的address成員變量指向的是不同的地址。
在上述代碼中,我們使用了一個(gè)deepCopy()方法來實(shí)現(xiàn)對(duì)象的深拷貝。該方法使用對(duì)象的序列化和反序列化來實(shí)現(xiàn)深拷貝。首先,將原始對(duì)象序列化成字節(jié)數(shù)組,然后再將字節(jié)數(shù)組反序列化成新的對(duì)象。這樣可以保證復(fù)制出的新對(duì)象與原始對(duì)象完全獨(dú)立,不會(huì)相互影響。
總結(jié):
淺拷貝和深拷貝是Java中常用的兩種對(duì)象拷貝方式。淺拷貝只會(huì)復(fù)制對(duì)象內(nèi)部的基本數(shù)據(jù)類型和引用類型變量的引用,而深拷貝會(huì)將對(duì)象內(nèi)部所有的基本類型和引用類型都復(fù)制一份。使用clone()方法和重寫clone()方法可以實(shí)現(xiàn)淺拷貝,使用對(duì)象序列化或手動(dòng)復(fù)制可以實(shí)現(xiàn)深拷貝。在實(shí)現(xiàn)對(duì)象拷貝時(shí)需要根據(jù)具體情況選擇合適的拷貝方式,以保證復(fù)制出的新對(duì)象能夠滿足應(yīng)用需求。
到此這篇關(guān)于Java中淺拷貝與深拷貝的文章就介紹到這了,更多相關(guān)Java淺拷貝與深拷貝內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MybatisPlus查詢數(shù)據(jù)日期格式化問題解決方法
MyBatisPlus是MyBatis的增強(qiáng)工具,支持常規(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)存屏障實(shí)現(xiàn)這些特性,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2025-04-04Java中Collection和Collections的區(qū)別
Collection是一個(gè)集合接口,集合類的頂級(jí)接口,Collections是一個(gè)包裝類,本文主要介紹了Java中Collection和Collections的區(qū)別,具有一定的參考價(jià)值,感興趣的可以了解一下2024-04-04Springboot實(shí)現(xiàn)多數(shù)據(jù)源切換詳情
這篇文章主要介紹了Springboot實(shí)現(xiàn)多數(shù)據(jù)源切換詳情,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,感興趣的朋友可以參考一下2022-09-09