0

0

Java中如何防止对象的浅拷贝带来的问题_重写clone实现深拷贝

P粉602998670

P粉602998670

发布时间:2026-03-12 12:47:31

|

331人浏览过

|

来源于php中文网

原创

重写 clone() 仍为浅拷贝,因 Object.clone() 仅复制字段值,对引用类型不递归拷贝;需手动深拷贝可变引用字段,否则修改副本会影响原对象。

java中如何防止对象的浅拷贝带来的问题_重写clone实现深拷贝

为什么重写 clone() 很容易还是浅拷贝

因为默认的 Object.clone() 只复制对象本身字段,对引用类型字段不做递归复制——哪怕你加了 implements Cloneable,也只解除了抛异常的限制,不改变复制行为。

常见错误现象:clone() 后修改副本里的集合或嵌套对象,原对象跟着变;或者两个对象的 hashCode() 一样但 equals() 返回 false,说明内部引用没断开。

  • 必须手动对每个可变引用字段调用其自身的 clone() 或新建副本(比如用 new ArrayList(originalList)
  • 如果字段是第三方类且没实现 Cloneable,不能直接调 field.clone(),得用构造器、静态工厂或序列化等替代方案
  • 注意循环引用:A 引用 B,B 又引用 A,手动深拷贝时容易栈溢出或无限递归

如何安全地在 Java 中重写 clone()

核心原则:所有可变的引用字段,必须显式深拷贝;基本类型和不可变类(如 StringLocalDateTime)可直接赋值。

使用场景:需要快速创建独立副本、且对象结构相对稳定(字段不多、嵌套不深),又不想引入额外依赖(如 Apache Commons Lang)。

立即学习Java免费学习笔记(深入)”;

  • 声明类为 implements Cloneable,否则 super.clone() 会抛 CloneNotSupportedException
  • 重写方法签名必须是 public Object clone(),返回类型不能窄化为子类(Java 5+ 支持协变返回,但底层仍需强转)
  • 调用 super.clone() 获取原始字段副本,再逐个替换引用字段为深拷贝结果
  • 如果字段是数组,Arrays.copyOf()clone() 数组本身是浅的,元素仍是原引用——需遍历处理每个元素
public class Person implements Cloneable {
    private String name;
    private List<String> hobbies;
    
    @Override
    public Object clone() throws CloneNotSupportedException {
        Person cloned = (Person) super.clone();
        cloned.hobbies = new ArrayList<>(this.hobbies); // 深拷贝 List
        return cloned;
    }
}

比重写 clone() 更可靠的选择有哪些

因为 clone() 机制本身有设计缺陷(违反构造逻辑、类型不安全、与 final 字段冲突),多数现代项目倾向避开它。

Bolt.new
Bolt.new

Bolt.new是一个免费的AI全栈开发工具

下载

性能/兼容性影响:序列化深拷贝慢且要求所有字段可序列化;构造器方式清晰但字段多时冗长;Lombok 的 @Builder(toBuilder = true) 生成的 toBuilder().build() 是浅拷贝,不能直接用。

  • 用拷贝构造器(copy constructor):明确、可控、支持泛型和 final 字段,例如 new Person(original)
  • 用静态工厂方法:如 Person.copyOf(original),便于后续扩展校验或转换逻辑
  • 必要时用 JSON 序列化反序列化(如 Jackson 的 readValue(writeValueAsBytes(obj), type)),但要注意 transient 字段丢失、日期格式、自定义序列化器缺失等问题

哪些情况根本不能靠 clone() 解决

不是所有“复制”需求都适合走 clone() 路线,尤其当对象状态依赖外部资源或运行时上下文时。

容易踩的坑:以为重写了 clone() 就一劳永逸,结果在并发环境下因未同步共享缓存字段而出错;或忽略了代理对象(如 Hibernate 的懒加载实体)、持有线程局部变量的对象。

  • 对象包含 ThreadLocalSocketConnection 等资源句柄——复制无意义,应重新初始化
  • 使用了 CGLIB 或 JDK 动态代理的对象,clone() 会丢失代理逻辑,得到的是裸对象
  • 字段含 lambda 表达式或方法引用:它们可能捕获了外部对象,深拷贝无法自动重建这种闭包关系

复杂点在于,深拷贝从来不只是“复制字段”,而是“重建语义等价的独立实例”。一旦对象图里混入不可控状态、外部依赖或动态行为,就得按具体场景设计复制策略,而不是指望一个通用 clone() 方法兜底。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
json数据格式
json数据格式

JSON是一种轻量级的数据交换格式。本专题为大家带来json数据格式相关文章,帮助大家解决问题。

456

2023.08.07

json是什么
json是什么

JSON是一种轻量级的数据交换格式,具有简洁、易读、跨平台和语言的特点,JSON数据是通过键值对的方式进行组织,其中键是字符串,值可以是字符串、数值、布尔值、数组、对象或者null,在Web开发、数据交换和配置文件等方面得到广泛应用。本专题为大家提供json相关的文章、下载、课程内容,供大家免费下载体验。

546

2023.08.23

jquery怎么操作json
jquery怎么操作json

操作的方法有:1、“$.parseJSON(jsonString)”2、“$.getJSON(url, data, success)”;3、“$.each(obj, callback)”;4、“$.ajax()”。更多jquery怎么操作json的详细内容,可以访问本专题下面的文章。

335

2023.10.13

go语言处理json数据方法
go语言处理json数据方法

本专题整合了go语言中处理json数据方法,阅读专题下面的文章了解更多详细内容。

82

2025.09.10

hibernate和mybatis有哪些区别
hibernate和mybatis有哪些区别

hibernate和mybatis的区别:1、实现方式;2、性能;3、对象管理的对比;4、缓存机制。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

158

2024.02.23

Hibernate框架介绍
Hibernate框架介绍

本专题整合了hibernate框架相关内容,阅读专题下面的文章了解更多详细内容。

94

2025.08.06

Java Hibernate框架
Java Hibernate框架

本专题聚焦 Java 主流 ORM 框架 Hibernate 的学习与应用,系统讲解对象关系映射、实体类与表映射、HQL 查询、事务管理、缓存机制与性能优化。通过电商平台、企业管理系统和博客项目等实战案例,帮助学员掌握 Hibernate 在持久层开发中的核心技能。

39

2025.09.02

Hibernate框架搭建
Hibernate框架搭建

本专题整合了Hibernate框架用法,阅读专题下面的文章了解更多详细内容。

72

2025.10.14

C# ASP.NET Core微服务架构与API网关实践
C# ASP.NET Core微服务架构与API网关实践

本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

76

2026.03.11

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 4.3万人学习

C# 教程
C# 教程

共94课时 | 11.2万人学习

Java 教程
Java 教程

共578课时 | 81万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号