字符串和對象的深拷貝和淺拷貝

字符串和對象的深拷貝和淺拷貝

  • 【一】基本介紹
    • 【1】淺拷貝
    • 【2】深拷貝
  • 【二】字符串的拷貝
    • 【1】字符串的 “淺拷貝”
    • 【2】字符串的 “深拷貝”
  • 【三】對象的拷貝
    • 【1】淺拷貝(Shallow Copy)
    • 【2】深拷貝(Deep Copy)
  • 【四】字符串和對象拷貝的核心區別
  • 【五】介紹ObjectUtil的clone方法
    • 【1】ObjectUtil.clone的核心功能
    • 【2】使用案例
      • (1)基本類型與字符串拷貝
      • (2)數組拷貝(深拷貝)
      • (3)自定義對象拷貝
    • 【3】實現原理(Hutool為例)

【一】基本介紹

【1】淺拷貝

僅拷貝數據的 “表層”。對于基本數據類型(如int、float),直接拷貝值;對于引用類型(如對象、數組),僅拷貝引用地址(原對象和拷貝對象共享同一個引用對象)。

【2】深拷貝

拷貝數據的 “全部層級”。不僅拷貝基本類型的值,還會遞歸拷貝所有引用類型所指向的對象,原對象和拷貝對象完全獨立,互不影響。

【二】字符串的拷貝

字符串(String)是特殊的引用類型,其拷貝行為受不可變性影響(String類被final修飾,一旦創建不可修改)。

【1】字符串的 “淺拷貝”

本質是引用傳遞,由于字符串不可變,直接賦值或使用clone()(字符串的clone()方法返回自身)時,拷貝的是引用,但因不可變性,不會出現共享修改的問題。

String original = "hello";
String copy = original; // 拷貝引用(淺拷貝)// 字符串不可變:修改copy會創建新對象,不影響original
copy = "world"; 
System.out.println(original); // 輸出:hello(原對象未變)

特點:原字符串和拷貝字符串的引用指向同一對象,但因不可修改,看似 “安全”,實際仍是淺拷貝(共享引用)。

【2】字符串的 “深拷貝”

無需額外操作
由于字符串不可變,任何 “修改” 都會創建新對象,因此即使是淺拷貝,也能達到類似深拷貝的效果。若需顯式創建新字符串對象,可通過以下方式:

String original = "hello";
// 方式1:使用構造方法創建新對象(深拷貝效果)
String deepCopy1 = new String(original); 
// 方式2:使用intern()(但可能復用常量池對象,視情況而定)
String deepCopy2 = original.intern(); // 修改拷貝對象不會影響原對象(因不可變,實際是創建新對象)
deepCopy1 = deepCopy1 + "world"; 
System.out.println(original); // 輸出:hello(原對象未變)

特點:字符串的不可變性使得 “淺拷貝” 和 “深拷貝” 的區別被弱化 —— 無論哪種方式,修改拷貝都不會影響原對象,因此通常無需專門實現深拷貝。

【三】對象的拷貝

對象(如自定義類實例)是典型的引用類型,其拷貝需明確區分淺拷貝和深拷貝,否則可能因共享引用導致意外問題。

【1】淺拷貝(Shallow Copy)

僅拷貝對象本身和基本類型字段,引用類型字段僅拷貝引用(原對象和拷貝對象共享引用對象)。

(1)實現方式:
重寫Object類的clone()方法(需實現Cloneable接口)。
默認的clone()方法為淺拷貝。

(2)示例

class Address { // 引用類型(地址類)String city;public Address(String city) { this.city = city; }
}class Person implements Cloneable { // 實現Cloneable接口String name; // 基本類型(String是特殊引用類型,但不可變)int age; // 基本類型Address address; // 引用類型public Person(String name, int age, Address address) {this.name = name;this.age = age;this.address = address;}// 重寫clone()實現淺拷貝@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone(); // 默認淺拷貝}
}// 測試淺拷貝
public class ShallowCopyDemo {public static void main(String[] args) throws CloneNotSupportedException {Address addr = new Address("Beijing");Person original = new Person("Alice", 20, addr);// 淺拷貝Person copy = (Person) original.clone();// 1. 基本類型和不可變引用類型(String):修改拷貝不影響原對象copy.name = "Bob";copy.age = 21;System.out.println(original.name); // 輸出:Alice(原對象name未變)System.out.println(original.age);  // 輸出:20(原對象age未變)// 2. 引用類型(Address):修改拷貝的引用對象,原對象受影響copy.address.city = "Shanghai";System.out.println(original.address.city); // 輸出:Shanghai(原對象address被修改)}
}

結論:淺拷貝中,引用類型字段(如Address)的修改會同時影響原對象和拷貝對象(因共享引用)。

【2】深拷貝(Deep Copy)

完全拷貝對象及其所有引用類型字段指向的對象,原對象和拷貝對象完全獨立。

(1)實現方式:
方式 1:重寫clone()方法時,對引用類型字段也進行clone()(遞歸淺拷貝)。
方式 2:通過序列化(Serializable)將對象轉為字節流,再反序列化為新對象。
方式 3:使用 JSON 工具(如 Jackson、Gson)將對象轉為 JSON 字符串,再解析為新對象。

(2)示例一:遞歸 clone 實現深拷貝

class Address implements Cloneable { // 引用類型實現CloneableString city;public Address(String city) { this.city = city; }@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone(); // Address的淺拷貝}
}class Person implements Cloneable {String name;int age;Address address;public Person(String name, int age, Address address) {this.name = name;this.age = age;this.address = address;}// 重寫clone()實現深拷貝:對引用類型字段也進行clone@Overrideprotected Object clone() throws CloneNotSupportedException {Person copy = (Person) super.clone(); // 先淺拷貝Person本身copy.address = (Address) this.address.clone(); // 再拷貝引用類型Addressreturn copy;}
}// 測試深拷貝
public class DeepCopyDemo {public static void main(String[] args) throws CloneNotSupportedException {Address addr = new Address("Beijing");Person original = new Person("Alice", 20, addr);// 深拷貝Person copy = (Person) original.clone();// 修改拷貝的引用類型字段copy.address.city = "Shanghai";System.out.println(original.address.city); // 輸出:Beijing(原對象不受影響)}
}

(3)示例二:序列化實現深拷貝

import java.io.*;class Address implements Serializable { // 需實現SerializableString city;public Address(String city) { this.city = city; }
}class Person implements Serializable { // 需實現SerializableString name;int age;Address address;// 深拷貝方法:序列化+反序列化public Person deepCopy() throws IOException, ClassNotFoundException {// 序列化ByteArrayOutputStream bos = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(bos);oos.writeObject(this);// 反序列化ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());ObjectInputStream ois = new ObjectInputStream(bis);return (Person) ois.readObject();}
}// 測試
public class SerializationDemo {public static void main(String[] args) throws Exception {Person original = new Person("Alice", 20, new Address("Beijing"));Person copy = original.deepCopy();copy.address.city = "Shanghai";System.out.println(original.address.city); // 輸出:Beijing(完全獨立)}
}

結論:深拷貝中,原對象和拷貝對象的所有字段(包括引用類型)完全獨立,修改互不影響。

【四】字符串和對象拷貝的核心區別

(1)字符串(String)
拷貝引用,因不可變性,修改時會創建新對象,原對象不受影響。與淺拷貝效果一致(因不可變性,無需遞歸拷貝) 不可變性導致 “淺拷貝即安全”,無需專門深拷貝

(2)對象(引用類型)
引用類型字段共享引用,修改會相互影響。完全拷貝所有層級,修改互不影響 需顯式實現深拷貝(如遞歸clone、序列化)

(3)適用場景
1-淺拷貝:適用于對象中僅包含基本類型或不可變引用類型(如String),或需共享引用對象的場景(如多對象共享配置信息)。
2-深拷貝:適用于對象包含可變引用類型(如自定義類、數組),且需完全隔離原對象和拷貝對象的場景(如多線程操作、數據備份)。

【五】介紹ObjectUtil的clone方法

在 Java 工具類中,ObjectUtil通常是一個自定義或第三方工具類(如 Hutool、Apache Commons 等),用于簡化對象操作,其中clone方法用于實現對象的拷貝。不同工具類的clone方法實現可能略有差異,但核心功能都是封裝對象克隆的復雜邏輯,提供更簡潔的 API。以下以Hutool 工具類庫的ObjectUtil.clone方法為例,詳細介紹其功能、用法和特性

【1】ObjectUtil.clone的核心功能

ObjectUtil.clone方法的主要作用是快速實現對象的深拷貝或淺拷貝,無需手動處理Cloneable接口、序列化等底層細節,簡化對象拷貝的代碼實現。
Hutool 的ObjectUtil中,clone方法通過判斷對象類型,自動選擇最優的拷貝方式:

(1)對于基本類型、字符串(String)等不可變類型,直接返回原值(因不可變特性,無需拷貝)。
(2)對于數組,遞歸拷貝數組元素(深拷貝)。
(3)對于實現Cloneable接口的對象,調用其clone()方法(可能是淺拷貝,取決于對象自身實現)。
(4)對于實現Serializable接口的對象,通過序列化 + 反序列化實現深拷貝。
(5)對于普通對象,嘗試通過反射拷貝字段(深拷貝)。

【2】使用案例

(1)基本類型與字符串拷貝

import cn.hutool.core.util.ObjectUtil;public class CloneDemo {public static void main(String[] args) {// 字符串拷貝(因不可變,直接返回引用,但不影響安全性)String str = "hello";String strClone = ObjectUtil.clone(str);System.out.println(str == strClone); // true(共享引用,因不可變安全)// 基本類型包裝類拷貝Integer num = 123;Integer numClone = ObjectUtil.clone(num);System.out.println(num == numClone); // true(Integer常量池復用)}
}

(2)數組拷貝(深拷貝)

import cn.hutool.core.util.ObjectUtil;public class ArrayCloneDemo {public static void main(String[] args) {int[] arr = {1, 2, 3};int[] arrClone = ObjectUtil.clone(arr);arrClone[0] = 100;System.out.println(arr[0]); // 1(原數組不受影響,深拷貝)}
}

(3)自定義對象拷貝

假設存在自定義類User(實現Serializable接口以支持深拷貝)

import java.io.Serializable;class User implements Serializable {private String name;private int age;private Address address; // 引用類型字段// 構造方法、getter、setter省略
}class Address implements Serializable {private String city;// 構造方法、getter、setter省略
}

使用ObjectUtil.clone實現深拷貝:

import cn.hutool.core.util.ObjectUtil;public class ObjectCloneDemo {public static void main(String[] args) {Address addr = new Address("Beijing");User user = new User("Alice", 20, addr);// 深拷貝User userClone = ObjectUtil.clone(user);// 修改拷貝對象的引用字段userClone.getAddress().setCity("Shanghai");// 原對象不受影響(深拷貝成功)System.out.println(user.getAddress().getCity()); // Beijing}
}

【3】實現原理(Hutool為例)

ObjectUtil.clone的底層邏輯大致分為以下步驟:
(1)判斷對象類型:
若為null,直接返回null。
若為基本類型或字符串,返回原值(利用不可變性)。
若為數組,遞歸拷貝每個元素(數組的深拷貝)。

(2)嘗試克隆方式:
若對象實現Cloneable接口,調用其clone()方法(注意:若對象自身clone()是淺拷貝,結果仍為淺拷貝)。
若對象實現Serializable接口,通過序列化(ObjectOutputStream)和反序列化(ObjectInputStream)生成新對象(深拷貝)。
若以上均不滿足,通過反射拷貝對象的所有字段(包括私有字段),遞歸處理引用類型字段(深拷貝)。

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

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

相關文章

4.5 優化器中常見的梯度下降算法

梯度下降算法(Gradient Descent)的數學公式可以通過以下步驟嚴格表達:1. 基本梯度下降(Batch Gradient Descent) 目標:最小化損失函數L(θ)\mathcal{L}(\theta)L(θ),其中 θ\thetaθ是模型參數…

AM1.5G AAA穩態太陽光模擬器特點

光譜匹配度AM1.5G AAA穩態太陽光模擬器的光譜分布嚴格匹配國際標準IEC 60904-9中的AM1.5G光譜(波長范圍300-4000nm),確保與自然太陽光的偏差在25%以內(AAA級標準)。光譜匹配度通過精密濾光片和氙燈或LED組合光源實現&a…

OSPF開放式最短路徑優先

1OSPF簡介(1)OSPF英文全稱Open Shortest Path First (開放式最短路徑優先)(2)OSPF是IETF 開發的一種鏈路狀態路由協議,使用基于帶寬的度量值。(3)OSPF采用SPF算法計算路由,從算法上保…

Lua(模塊與包)

Lua 模塊的基本概念Lua 中的模塊是一個由函數、變量組成的代碼庫,通常保存在獨立的 .lua 文件中。模塊通過 return 語句導出其內容,供其他腳本調用。模塊化設計可以提高代碼復用性,便于管理。創建模塊模塊通常以 .lua 文件形式存在&#xff0…

1. boost::asio之socket的創建和連接

網絡編程基本流程 網絡編程的基本流程對于服務端是這樣的 服務端 1)socket——創建socket對象。 2)bind——綁定本機ipport。 3)listen——監聽來電,若在監聽到來電,則建立起連接。 4)accept——再創建一個…

WPF 控制動畫開關

記錄一種實現方式:第一步:首先定義一個靜態類,提供依賴屬性,進而方便在xaml中實現綁定:public static class AnimationBehavior{// 定義附加屬性public static readonly DependencyProperty IsAnimatingProperty Depen…

元素豎向的百分比設定是相對于父容器的高度嗎?

元素豎向的百分比設定是相對于父容器的高度嗎? 核心問題 在CSS中,當設置元素的豎向屬性(如height、padding-top等)為百分比值時,其計算基準是父容器的高度還是寬度? 權威結論height屬性 百分比值基于父容器…

web3.0怎么入局

Web3.0(第三代互聯網)融合了區塊鏈、去中心化應用(DApps)、NFT、DAO等新興技術,給個人和機構提供了許多全新的賺錢機會。入局 Web3.0 賺錢主要有以下幾種途徑,根據你的技術背景、資金能力和時間投入可以選擇適合自己的方式。 目錄 一、普通用戶賺錢方式(門檻低) 1. …

linux入門 相關linux系統操作命令(二)--文件管理系統 ubuntu22.04

以下有免費的4090云主機提供ubuntu22.04系統的其他入門實踐操作 地址:星宇科技 | GPU服務器 高性能云主機 云服務器-登錄 相關兌換碼星宇社區---4090算力卡免費體驗、共享開發社區-CSDN博客 兌換碼要是過期了,可以私信我獲取最新兌換碼!&a…

Python-初學openCV——圖像預處理(二)

目錄 一、圖像仿射變換 1、基本性質 二、cv2.warpAffine() 函數 1、圖像旋轉 2、圖像平移 3、圖像縮放 4、圖像剪切 三、 插值方法 1、最近鄰插值 2、雙線性插值 3、像素區域插值 4、雙三次插值 5、Lanczos插值 一、圖像仿射變換 仿射變換(Affine Tr…

醫療AI輕量化部署方案的深度梳理與優化路徑判研

摘要 醫療AI的快速發展為精準診斷、個性化治療和醫療資源優化提供了新機遇。然而,大規模模型的高計算復雜度和資源需求限制了其在資源受限環境(如邊緣設備、基層醫療機構)的應用。本文系統梳理了醫療AI輕量化部署的核心技術體系,包括模型壓縮、參數高效微調(PEFT)、邊緣-…

SSP通過SDK對接流量的原理與實現

一、核心概念解析 1.1 SSP(供應方平臺) 定義:SSP是程序化廣告生態中媒體方的核心工具,通過自動化技術幫助媒體(如網站、應用、視頻平臺)管理廣告資源、優化填充率并最大化廣告收益。核心功能:…

如何清理電腦c盤內存 詳細操作步驟

電腦使用時間不斷延長,許多用戶可能會遇到一個問題——C盤空間不足,導致系統運行緩慢或無法安裝新程序。如果C盤的存儲空間被大量占用,可能會影響到計算機的性能。本文將介紹幾種有效的方法,幫助你清理C盤內存,釋放空間…

ESP32的ADF詳解:5. Streams的API

一、算法流 (algorithm stream) 1. 初始化與配置API功能描述關鍵參數說明algo_stream_init()初始化算法流(AEC/AGC/NS/VAD)config->algo_mask 選擇算法組合config->sample_rate 設置采樣率(默認16kHz)config->partition_…

JavaScript對象鍵序問題解析

問題的發現: 我有一個接口返回一個json數據瀏覽器network里的Response里是從大到小排。 但Preview就是反過來的 問題的描述: 上面那個讓我發現瀏覽器處理對象或者json是會對其鍵值對做排序!!! 在JavaScript中&am…

pandas庫的數據導入導出,缺失值,重復值處理和數據篩選,matplotlib庫 簡單圖繪制

目錄 一.數據導入導出 1.CSV文件讀取與參數說明 2.Excel與TST文件讀取 3.數據導出操作 二.缺失值處理 1.填充缺失值 2.刪除缺失值【刪除整行數據】 三.重復值處理 四.數據篩選與條件查詢 1.邏輯判斷取數 2.字符匹配 3.邏輯運算: &(和&…

FPGA?如何實現另一個?FPGA?

如果你對 FPGA 有些了解,大概知道它的意思是“可編程邏輯器件”,可以把寫好的邏輯電路(通常是 Verilog/VHDL)通過工具綜合、布局布線、燒寫進去,讓一塊芯片變成“你想要的電路”。但如果我告訴你,現在有個開…

文思助手、新華妙筆 AI材料星的公文寫作深度測評

公文寫作一直都是體制內工作人員的日常核心任務,寫公文的難點不僅來自于對政策表述嚴謹性的高要求,也在于格式規范、內容深度以及效率壓力的多重考驗。隨著AI技術的發展,越來越多的文字輔助工具出現,很大程度的緩解了寫作壓力&…

Flutter開發環境搭建與工具鏈

Flutter開發實戰第1章:Flutter開發環境搭建與工具鏈1.1 Flutter簡介與優勢Flutter是Google推出的開源UI工具包,用于從單一代碼庫構建編譯為原生性能的移動、Web和桌面應用程序。Flutter的核心優勢包括:跨平臺一致性:一套代碼運行在…

io_uring:Linux異步I/O的革命性突破

目錄 1. io_uring是什么? io_uring核心優勢: 2. io_uring核心原理 2.1 雙環形緩沖區設計 2.2 關鍵數據結構 1、完成隊列CQ 2、提交隊列SQ 3、Params 3. io_uring工作流程 3.1 初始化階段 3.2 I/O操作流程 4. C代碼示例(原始系統調…