当前位置: 首页 > news >正文

Java 浅拷贝和深拷贝

浅拷贝

浅拷贝会创建一个新的对象,复制该对象的基本类型引用,但不复制该对象内的其他对象引用。一个对象要支持浅拷贝,需要实现Cloneable接口,不然在调用clone()方法时会抛出异常

    protected Object clone() throws CloneNotSupportedException {
        if (!(this instanceof Cloneable)) {
            throw new CloneNotSupportedException("Class " + getClass().getName() +
                                                 " doesn't implement Cloneable");
        }

        return internalClone();
    }

看个简单的demo

public class ShallowCopy implements Cloneable {
    int i = 10;
    String str = "ShallowCopy";
    Shallow shallow = new Shallow();

    public static class Shallow {
        String shallow = "shallow";
    }

    public static void testShallowCopy() {
        ShallowCopy shallowCopy = new ShallowCopy();
        try {
            ShallowCopy shallowCopyClone = (ShallowCopy) shallowCopy.clone();
            LogUtil.info("ShallowCopy", "(shallowCopy == shallowCopyClone) = " + (shallowCopy == shallowCopyClone));
            LogUtil.info("ShallowCopy", "(shallowCopy.equals(shallowCopyClone)) = " + (shallowCopy.equals(shallowCopyClone)));
            LogUtil.info("ShallowCopy", "(shallowCopy.shallow == shallowCopyClone.shallow) = " + (shallowCopy.shallow == shallowCopyClone.shallow));
            LogUtil.info("ShallowCopy", "(shallowCopy.shallow.equals(shallowCopyClone.shallow)) = " + (shallowCopy.shallow.equals(shallowCopyClone.shallow)));
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException(e);
        }
    }
}

打印结果如下

2025-03-13 16:53:25.564   (shallowCopy == shallowCopyClone) = false
2025-03-13 16:53:25.564   (shallowCopy.equals(shallowCopyClone)) = false
2025-03-13 16:53:25.564   (shallowCopy.shallow == shallowCopyClone.shallow) = true
2025-03-13 16:53:25.564   (shallowCopy.shallow.equals(shallowCopyClone.shallow)) = true

我们发现shallowCopyshallowCopyClone指向不同的对象,但是里面的shallow却是同一个。如果要实现两个shallowCopyshallowCopyClone两个完全不同的对象,也即是要实现深拷贝,有两个办法,下文介绍两种方法

深拷贝

  1. 内部的对象引用所属类也继承clone接口,重写clone()方法,例如
public class ShallowCopy implements Cloneable {
    int i = 10;
    String str = "ShallowCopy";
    Shallow shallow = new Shallow();

    @NonNull
    @Override
    protected Object clone() throws CloneNotSupportedException {
        ShallowCopy cloned = (ShallowCopy)super.clone();
        cloned.shallow = (Shallow)shallow.clone();
        return cloned;
    }

    public static class Shallow implements Cloneable {
        String shallow = "shallow";

        @NonNull
        @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    }

    public static void testShallowCopy() {
        ShallowCopy shallowCopy = new ShallowCopy();
        try {
            ShallowCopy shallowCopyClone = (ShallowCopy) shallowCopy.clone();
            LogUtil.info("ShallowCopy", "(shallowCopy == shallowCopyClone) = " + (shallowCopy == shallowCopyClone)); // false
            LogUtil.info("ShallowCopy", "(shallowCopy.equals(shallowCopyClone)) = " + (shallowCopy.equals(shallowCopyClone))); // false
            LogUtil.info("ShallowCopy", "(shallowCopy.shallow == shallowCopyClone.shallow) = " + (shallowCopy.shallow == shallowCopyClone.shallow)); // false
            LogUtil.info("ShallowCopy", "(shallowCopy.shallow.equals(shallowCopyClone.shallow)) = " + (shallowCopy.shallow.equals(shallowCopyClone.shallow))); // false
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException(e);
        }
    }
}

返回结果

2025-03-13 17:14:09.906   (shallowCopy == shallowCopyClone) = false
2025-03-13 17:14:09.906   (shallowCopy.equals(shallowCopyClone)) = false
2025-03-13 17:14:09.906   (shallowCopy.shallow == shallowCopyClone.shallow) = false
2025-03-13 17:14:09.906   (shallowCopy.shallow.equals(shallowCopyClone.shallow)) = false

但这个方法有个弊端,就是如果引用对象的链路比较深,例如 A 引用 B,B 引用 C,C 引用 D,甚至更深,就需要重写很多clone()方法,不易于维护.

值得注意的是Shallow类里面的shallow变量,它是一个String类型的对象引用,但是却可以不用实现clone接口实现深拷贝。原因是String是不可变的,修改String类型都会返回一个新对象,参考文档String 基础知识

  1. 使用Serializable序列化实现深拷贝

需要注意的是引用对象的类型也要实现Serializable接口,不然后报错

public class ShallowCopy implements Cloneable, Serializable {
       public static class Shallow implements Cloneable, Serializable {
           
       }
}

如果Shallow没有实现Serializable接口,则会出现java.io.NotSerializableException。接着使用IO实现序列化和反序列化

    public ShallowCopy deepClone() {
        ShallowCopy deepClone = null;
        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(this);

            ByteArrayInputStream bio = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bio);
            deepClone = (ShallowCopy) ois.readObject();
        } catch (IOException | ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
        return deepClone;
    }

结果打印

    public static void testDeepCopy() {
        ShallowCopy shallowCopy = new ShallowCopy();
        ShallowCopy shallowCopyDeepClone = shallowCopy.deepClone();
        LogUtil.info("ShallowCopy", "(shallowCopy == shallowCopyDeepClone) = " + (shallowCopy == shallowCopyDeepClone)); // false
        LogUtil.info("ShallowCopy", "(shallowCopy.equals(shallowCopyDeepClone)) = " + (shallowCopy.equals(shallowCopyDeepClone))); // false
        LogUtil.info("ShallowCopy", "(shallowCopy.shallow == shallowCopyDeepClone.shallow) = " + (shallowCopy.shallow == shallowCopyDeepClone.shallow)); // false
        LogUtil.info("ShallowCopy", "(shallowCopy.shallow.equals(shallowCopyDeepClone.shallow)) = " + (shallowCopy.shallow.equals(shallowCopyDeepClone.shallow))); // false
    }

相关文章:

  • 【空间插值】地理加权回归模型(GWR, Geographically Weighted Regression)
  • Windows 发票闪印 PrintPDF-v3.6.10-第三方发票打印辅助工具,无需安装阅读器即可使用
  • 使用 ESP32 和 Python 进行手势识别
  • 蓝桥与力扣刷题(蓝桥 等差数列)
  • Word中把参考文献引用改为上标
  • Linux上位机开发实战(按钮响应)
  • AI绘画软件Stable Diffusion详解教程(10):图生图进阶篇(局部手绘修正)
  • Python 正则表达式模块 re
  • 「基于大模型的智能客服系统」语义理解、上下文记忆与反馈机制设计
  • 实现悬浮按钮拖动,兼容h5和微信小程序
  • LinPEAS 使用最佳实践指南
  • Profinet转Profinet以创新网关模块为核心搭建西门子和欧姆龙PLC稳定通讯架构案例​
  • 中级软件设计师2004-2024软考真题合集下载
  • 【每日学点HarmonyOS Next知识】嵌套组件、装饰器报错、迭代列表刷新、单位换算、tabs组件生命周期
  • 使用GPTQ量化Llama-3-8B大模型
  • stm32F103RCT6+ModBus之RTU
  • SpringBoot学生宿舍管理系统的设计与开发
  • 谷粒商城:性能压测JVM堆区
  • 前端学习笔记(三)——ant-design vue表单传递数据到父页面
  • 【从零开始学习计算机科学】数据库系统(十)XML、XPATH、XQuery与XML数据库
  • 网站服务器环境搭建/搜索关键词排名工具
  • 上海手机网站制作公司/百度推广电话客服
  • 福建住建设厅官方网站/百度关键词代做排名
  • 做新浪微博网站需要/关键词优化技巧
  • 网站建设公司赚钱/台州关键词优化平台
  • 网站开发师职责/百度账号一键登录