Java中淺拷貝與深拷貝實(shí)例解析
前言
在Java中,對(duì)象的拷貝有兩種方式:淺拷貝和深拷貝。它們分別代表了不同的拷貝方式,拷貝出的新對(duì)象與原始對(duì)象之間存在一定的差異。本文將詳細(xì)介紹淺拷貝和深拷貝的概念、特點(diǎn)和實(shí)現(xiàn)方式,并且通過(guò)實(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)重寫(xiě)類的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接口,并重寫(xiě)了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ì)象是不同的。接下來(lái),我們使用“==”判斷person1和person2中的address是否是同一對(duì)象,結(jié)果為true,即兩個(gè)對(duì)象的address成員變量指向的是同一個(gè)地址。
總的來(lái)說(shuō),淺拷貝只是將原始對(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)編寫(xiě)clone()方法等。下面是一個(gè)使用對(duì)象序列化來(lái)實(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ì)象是不同的。接下來(lái),我們使用“==”判斷person1和person2中的address是否是同一對(duì)象,結(jié)果為false,即兩個(gè)對(duì)象的address成員變量指向的是不同的地址。
在上述代碼中,我們使用了一個(gè)deepCopy()方法來(lái)實(shí)現(xiàn)對(duì)象的深拷貝。該方法使用對(duì)象的序列化和反序列化來(lái)實(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()方法和重寫(xiě)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)文章
20秒教你學(xué)會(huì)java?List函數(shù)排序操作示例
這篇文章主要為大家介紹了20秒教你學(xué)會(huì)List函數(shù)排序操作示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-09-09
Java中的定時(shí)任務(wù)調(diào)度Quartz舉例詳解
這篇文章主要介紹了Java中的定時(shí)任務(wù)調(diào)度Quartz的相關(guān)資料,Quartz是Java平臺(tái)上的一個(gè)強(qiáng)大且靈活的任務(wù)調(diào)度庫(kù),廣泛應(yīng)用于企業(yè)級(jí)應(yīng)用中,本文介紹了Quartz的基本概念、核心組件、使用步驟和示例,幫助你更好地利用Quartz進(jìn)行定時(shí)任務(wù)調(diào)度,需要的朋友可以參考下2024-12-12
簡(jiǎn)單實(shí)現(xiàn)Java驗(yàn)證碼功能
這篇文章主要為大家詳細(xì)介紹了簡(jiǎn)單實(shí)現(xiàn)Java驗(yàn)證碼功能的代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-05-05
java數(shù)據(jù)類型轉(zhuǎn)換之自動(dòng)類型轉(zhuǎn)換和強(qiáng)制類型轉(zhuǎn)換詳解
在 Java 中,數(shù)據(jù)類型轉(zhuǎn)換用于將一種基本數(shù)據(jù)類型的值轉(zhuǎn)換為另一種基本數(shù)據(jù)類型,主要分為自動(dòng)類型轉(zhuǎn)換(隱式轉(zhuǎn)換)?和強(qiáng)制類型轉(zhuǎn)換(顯式轉(zhuǎn)換)?兩種,下面小編就為大家簡(jiǎn)單介紹一下吧2025-11-11
RabbitMQ在微服務(wù)架構(gòu)中的落地:消息推送?/?解耦?/?削峰填谷
本文介紹了RabbitMQ在微服務(wù)架構(gòu)中的三大應(yīng)用場(chǎng)景:消息推送、服務(wù)解耦和削峰填谷,通過(guò)實(shí)際代碼示例展示了如何在實(shí)際項(xiàng)目中應(yīng)用RabbitMQ實(shí)現(xiàn)這些模式,感興趣的朋友一起看看吧2026-05-05
Java替換視頻背景音樂(lè)的實(shí)現(xiàn)示例
FFmpeg 是一個(gè)強(qiáng)大的開(kāi)源多媒體處理工具,被廣泛應(yīng)用于音視頻的錄制、轉(zhuǎn)碼、編輯等方面,本文主要介紹了Java替換視頻背景音樂(lè),具有一定的參考價(jià)值,感興趣的可以了解一下2024-03-03

