Java:對象的淺拷貝與深拷貝

目錄

一、概念

二、實現方式

2.1 淺拷貝(不推薦)

2.2 深拷貝

2.2.1 方法一:重寫?clone()?方法并遞歸克隆(常用)

2.2.2 方法二:通過序列化實現(更強大,但更重)

2.2.3?使用拷貝構造方法或拷貝工廠(推薦)


一、概念

淺拷貝 (Shallow Copy):只復制對象本身以及對象中的基本數據類型字段的值,而對于對象中的引用類型字段,則只復制其內存地址(即引用),而不復制引用的對象本身。

影響:原始對象和拷貝對象中的引用字段指向的是同一個堆內存中的子對象。修改其中一個對象的引用字段的內容,另一個對象的對應字段也會“看到”這個變化。

深拷貝 (Deep Copy):僅復制對象本身和基本數據類型字段的值,還會遞歸地復制所有引用類型字段所指向的對象,直到所有可達的對象都被復制。

影響:原始對象和拷貝對象完全獨立,它們所有的引用字段都指向不同的對象。修改其中一個對象的任何內容,都不會影響另一個對象。

二、實現方式

2.1 淺拷貝(不推薦)

實現方式:依靠Object?類的?clone()?方法。

實現條件:

  • 被拷貝的類實現?Cloneable?接口(這是一個標記接口,沒有方法)。

  • 被拷貝的類重寫?Object?的?clone()?方法,并在其中調用?super.clone()

public class Person implements Cloneable {private String name;        // String (不可變對象,可視為基本類型)private int age;            // 基本類型private Address address;    // 引用類型// 構造方法、getters、setters 省略...@Overridepublic Object clone() throws CloneNotSupportedException {// 直接調用Object的clone()方法,完成基本數據類型和引用地址的復制return super.clone();}
}public class Address {private String city;private String street;// 構造方法、getters、setters...
}public class TestShallowCopy {public static void main(String[] args) throws CloneNotSupportedException {Address addr = new Address("北京", "長安街");Person original = new Person("張三", 25, addr);// 進行淺拷貝Person copied = (Person) original.clone();System.out.println(original == copied);       // false,是兩個不同的對象System.out.println(original.getName() == copied.getName()); // true,String池或同一對象(可能)System.out.println(original.getAddress() == copied.getAddress()); // true!關鍵在這里:引用指向同一個Address對象// 修改拷貝對象的引用類型成員copied.getAddress().setCity("上海");// 原始對象的address也被修改了!System.out.println(original.getAddress().getCity()); // 輸出:上海}
}

2.2 深拷貝

2.2.1 方法一:重寫?clone()?方法并遞歸克隆(常用)

// 1、讓 Address 類也變得可克隆(實現 Cloneable 并重寫 clone())
public class Address implements Cloneable {private String city;private String street;// ... 其他代碼 ...@Overridepublic Object clone() throws CloneNotSupportedException {return super.clone();}
}// 2、在 Person 的 clone() 方法中,不僅調用 super.clone(),還要手動克隆 address 字段
public class Person implements Cloneable {private String name;private int age;private Address address;// ... 其他代碼 ...@Overridepublic Object clone() throws CloneNotSupportedException {// 1. 先調用super.clone()完成淺拷貝Person copied = (Person) super.clone();// 2. 對引用類型字段,手動調用其clone()方法進行深拷貝copied.address = (Address) this.address.clone();// 3. 返回深拷貝后的對象return copied;}
}// 3、測試
public class TestDeepCopy {public static void main(String[] args) throws CloneNotSupportedException {Address addr = new Address("北京", "長安街");Person original = new Person("張三", 25, addr);Person copied = (Person) original.clone();System.out.println(original.getAddress() == copied.getAddress()); // false!現在是不同的Address對象// 修改拷貝對象的addresscopied.getAddress().setCity("上海");// 原始對象的address不受影響System.out.println(original.getAddress().getCity()); // 輸出:北京System.out.println(copied.getAddress().getCity());   // 輸出:上海}
}

2.2.2 方法二:通過序列化實現(更強大,但更重)

前提:所有涉及到的類都必須實現?java.io.Serializable?接口。

import java.io.*;public class DeepCopyUtil {@SuppressWarnings("unchecked")public static <T extends Serializable> T deepCopy(T object) {try (ByteArrayOutputStream baos = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(baos)) {// 將對象寫入字節流oos.writeObject(object);oos.flush();try (ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());ObjectInputStream ois = new ObjectInputStream(bais)) {// 從字節流中讀出新的對象return (T) ois.readObject();}} catch (IOException | ClassNotFoundException e) {throw new RuntimeException("Deep copy failed", e);}}
}// Person和Address類都需要實現Serializable接口
public class Person implements Serializable { ... }
public class Address implements Serializable { ... }// 使用工具類進行深拷貝
Person original = new Person(...);
Person copied = DeepCopyUtil.deepCopy(original); // 完美的深拷貝

優點:無需關心對象內部復雜的引用結構,序列化機制會自動完成所有遞歸復制。
缺點:性能開銷比?clone()?方法大;所有相關類都必須實現?Serializable?接口。

2.2.3?使用拷貝構造方法或拷貝工廠(推薦)

這是一種非常推薦的方式,它不依賴?Cloneable?接口,代碼更清晰,也更靈活。

  • 拷貝構造方法:接受一個同一類型的參數,并據此構造一個新對象。

  • 拷貝工廠:一個靜態方法,用于完成拷貝。

public class Person {private String name;private int age;private Address address;// 拷貝構造方法public Person(Person other) {this.name = other.name;this.age = other.age;// 對引用類型,調用其拷貝構造方法進行深拷貝this.address = new Address(other.address); // 假設Address也有拷貝構造方法}// 拷貝工廠 (靜態方法)public static Person newInstance(Person other) {return new Person(other);}
}public class Address {private String city;private String street;// Address的拷貝構造方法public Address(Address other) {this.city = other.city;this.street = other.street;}
}// 使用
Person original = new Person(...);
Person copied = new Person(original); // 使用拷貝構造方法
// 或
Person copied2 = Person.newInstance(original); // 使用拷貝工廠

優點:代碼意圖明確,易于控制和擴展,是《Effective Java》推薦的方式。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/96640.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/96640.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/96640.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

佰鈞成 社招 一面

1. “評估需求、排期”的工作流程&#xff1f; “我的工作流程一般是這樣的&#xff1a; 需求評審&#xff1a; 首先會和產品、后端同學一起過需求&#xff0c;確保我完全理解了業務背景和要實現的價值&#xff0c;而不僅僅是功能點。技術方案設計&#xff1a; 之后&#xff0c…

最短路徑問題(圖論)

1 Floyd 作用&#xff1a; 求圖中所有頂點之間的最短路徑&#xff0c;包括有向圖或者無向圖&#xff0c;權重正負皆可&#xff0c;用來一次性求所有點之間的最短路徑。 思路是 通過逐步擴大中間層&#xff0c;使得最短路徑不斷被更新&#xff0c;直到中間層擴大到n位置&#…

2025年8月新算法—云漂移優化算法(Cloud Drift Optimization Algorithm, CDO)

1、簡介 這項研究介紹了云漂移優化&#xff08;數位長&#xff09;算法&#xff0c;這是一種創新的自然啟發的元啟發式方法來解決復雜的優化問題。CDO模仿受大氣力影響的云粒子的動態行為&#xff0c;在探索和利用之間取得了微妙的平衡。它具有自適應權重調整機制&#xff0c;可…

VS Code進行.NET開發時使用斷點和熱重載

VS Code 調試熱重載 1. VS Code 設置 安裝擴展&#xff1a;C#、C# Dev Kit設置中搜索hot reload&#xff0c;選擇C#開發工具包&#xff0c;把下圖的幾項全部打勾2. 啟動項目&#xff08;僅用左側“運行和調試”&#xff09; 打開解決方案&#xff0c;選你的啟動項目的“.NET La…

mysqlbinlog解析命令

解析 MySQL Binlog 詳細信息的命令以下是解析 MySQL Binlog 詳細信息的常用命令&#xff1a;1. 基本 binlog 解析命令# 查看 binlog 文件內容&#xff08;基本格式&#xff09; mysqlbinlog /var/lib/mysql/mysql-bin.000001# 查看特定時間段的 binlog mysqlbinlog --start-dat…

算法訓練營day60 圖論⑩ Bellman_ford 隊列優化算法、判斷負權回路、單源有限最短路(修改后版本)

增加對最短路徑的優化算法、負權回路、單源有限最短的講解 Bellman_ford 隊列優化算法 -------------------------------------------------------------------------------- 8.24更新&#xff1a;該算法是針對帶負值的最短路徑的優化算法&#xff0c;核心通過隊列來實現&…

Python 學習(十六) 下一代 Python 包管理工具:UV

目錄1. UV 介紹1.1 什么是UV&#xff1f;1.2 UV的核心優勢1.3 UV和其他工具對比1&#xff09;UV vs. pipvirtualenv2&#xff09;UV vs. Conda3&#xff09;UV vs. Poetry4&#xff09;功能對比表2. UV的安裝與常用命令2.1 安裝UV1&#xff09;使用官方安裝腳本&#xff08;推薦…

Redis學習筆記 ----- 緩存

一、什么是緩存 緩存&#xff08;Cache&#xff09;是數據交換的緩沖區&#xff0c;是存儲數據的臨時地方&#xff0c;一般讀寫性能較高。 &#xff08;一&#xff09;緩存的作用 降低后端負載&#xff1a;減少對數據庫等后端存儲的直接訪問壓力。提高讀寫效率&#xff0c;降低…

React響應式鏈路

文章目錄響應式鏈路的核心環節1.狀態定義與初始化2.狀態更新觸發&#xff08;狀態變更&#xff09;3.調度更新&#xff08;Scheduler&#xff09;4.重新渲染&#xff08;Render 階段&#xff09;5.協調&#xff08;Reconciliation&#xff09;與 Fiber 架構6.提交更新&#xff…

軟件設計師——計算機網絡學習筆記

一、計算機網絡 網絡基礎 1. 計算機網絡的分類2. 網絡拓撲結構 總線型(利用率低、干擾大、價格低) 星型(交換機形成的局域網、中央單元負荷大) 環型(流動方向固定、效率低擴充難) 樹型(總線型的擴充、分級結構) 分布式(任意節點連接、管理難成本高)一般來說&#xff0c;辦公室局…

1200 SCL學習筆記

一. IF. 如果。下面是一個起保停IF #I_start AND NOT #I_stop THEN //如果I_start接通 和 I_stop沒有接通#Q_run : 1; //輸出Q_run 接通 ELSIF #I_stop THEN //如果I_stop接通#Q_run : 0; //。。。。。。 END_IF;二. CASECASE…

單例模式與線程池

1. 單例模式單例模式是一種常用的設計模式&#xff0c;它確保一個類只有一個實例&#xff0c;并提供一個全局訪問點來獲取這個實例。這種模式在需要控制資源訪問、管理共享狀態或協調系統行為時非常有用。單例模式的核心特點&#xff1a;私有構造函數&#xff1a;防止外部通過n…

Chrome和Edge如何開啟暗黑模式

Edge和Chrome瀏覽器都提供了實驗性功能&#xff0c;可以通過修改實驗性設置來開啟暗黑模式。 在瀏覽器地址欄中輸入edge://flags/&#xff08;Edge&#xff09;或chrome://flags/&#xff08;Chrome&#xff09;。在搜索框中輸入“dark”&#xff0c;找到與暗黑模式相關的選項。…

【科研繪圖系列】浮游植物的溶解性有機碳與初級生產力的關系

禁止商業或二改轉載,僅供自學使用,侵權必究,如需截取部分內容請后臺聯系作者! 文章目錄 介紹 數據準備 數據處理 溶解性有機碳(DOC)與初級生產力(NPP)的關系 溶解性有機碳(DOC)與光照強度(PAR)的關系 數據可視化 加載R包 數據下載 導入數據 畫圖1 畫圖2 總結 系統信…

IDEA相關的設置和技巧

IDEA相關的設置和技巧 我的博客對應文章地址 1.布局設置 IDEA的布局自定義程度很高&#xff0c;頂部工具欄&#xff0c;側邊欄都可以隨意定制&#xff0c;設置好的布局方案可以保存&#xff0c;在新項目中快速使用 1.1 工具欄設置 [!tip] 舉個例子&#xff1a;比如我要在頂部…

AWS Lambda 完全指南:解鎖無服務器架構的強大力量

在云計算的發展浪潮中,無服務器(Serverless) 架構已然成為構建現代應用的新范式。而在這場變革的中心,AWS Lambda 作為開創性的 Function-as-a-Service (FaaS) 服務,徹底改變了我們部署和運行代碼的方式。 本文將帶您深入探索 AWS Lambda,從核心概念、工作原理到高級實踐…

人工智能時代下普遍基本收入(UBI)試驗的實踐與探索——以美國硅谷試點為例

一、硅谷UBI試驗的最新進展&#xff08;2025年&#xff09;1. 試驗規模與資金來源圣克拉拉縣試點&#xff1a;硅谷所在地圣克拉拉縣針對脫離寄養家庭的年輕人開展UBI試驗&#xff0c;每月發放1000美元補貼&#xff0c;持續1-2年&#xff0c;覆蓋約60名參與者&#xff0c;成本約…

云計算之云主機Linux是什么?有何配置?如何選?

一、云環境如何選擇Linux發行版 1.1、Linux在各個領域的發展 Linux在各個領域的發展序號Linux發展領域說明1Linux在服務器領域的發展目前Linux在服務器領域已經占據95%的市場份額&#xff0c;同時Linux在服務器市場的迅速崛起&#xff0c;已經引起全球IT產業的高度關注&#xf…

XCVU13P-2FHGB2104E Xilinx(AMD)Virtex UltraScale+ FPGA

XCVU13P-2FHGB2104E 是 Xilinx&#xff08;AMD&#xff09;Virtex UltraScale FPGA 系列中的一款高性能芯片&#xff0c;適用于需要大量邏輯資源、高帶寬和高速數據傳輸的應用場景。作為該系列中的旗艦產品&#xff0c;XCVU13P-2FHGB2104I 結合了強大的處理能力和靈活的可編程性…

自動化單詞例句獲取系統設計方案

方案一 (網絡爬蟲) 這個方案的核心思路是:創建一個自動化的腳本,該腳本會讀取你 MongoDB 中的單詞,然后去一個免費的在線詞典網站上抓取這些單詞的例句,最后將抓取到的例句存回你的 MongoDB 數據庫中對應的單詞條目下。 一、 核心思路與技術選型 自動化腳本: 我們將使用 P…