字符串和对象的深拷贝和浅拷贝

字符串和对象的深拷贝和浅拷贝

  • 【一】基本介绍
    • 【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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈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代码示例(原始系统调…