Java对象复制(直接赋值,浅拷贝,深拷贝)

2023-10-26

Java对象复制

将一个对象的引用复制给另一个对象,一共有三种方式。第一种是直接赋值,第二种方式是浅拷贝,第三种是深拷贝,这三种方式实际上都是为了拷贝对象。

1,直接赋值

为了测试方便,新建两个类,没有实际的业务功能,只是为了测试。

//用了lombok插件,生成get,set方法,有参构造与无参构造
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private Integer id;
    private String name;
    private Integer age;
    private Student student;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {
    private Integer id;
    private Integer score;
}
public class CopyTest {
    public static void main(String[] args) {
        Student student = new Student(1, 80);
        User user = new User(1, "zhangSan", 25, student);
        User newUser=user;
        System.out.println(newUser.toString());
        user.setAge(26);
        newUser.setName("zhangSan1");
        System.out.println(newUser.toString());
    }
}

输出:

User(id=1, name=zhangSan, age=25, student=Student(id=1, score=80))
User(id=1, name=zhangSan1, age=26, student=Student(id=1, score=80))

直接赋值相当于是指针赋值,newUser和user这两个对象都是指向同一个地址,只要其中任何一个改变相应的值,两个都会一起变化。

2,浅拷贝

创建一个新对象,然后将当前对象的非静态字段复制到该对象,如果字段是值类型,那么对该字段进行复制;如果该字段是引用类型的话,则复制引用但不复制引用的对象。 因此,原始对象及其副本引用同一个对象。
浅拷贝需要继承Cloneable接口,重写clone()方法。

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Cloneable {
    private Integer id;
    private String name;
    private Integer age;
    private Student student;

    @Override
    public Object clone(){
        try{
            return (User) super.clone();
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }
}
public class CopyTest {
    public static void main(String[] args) {
        Student student = new Student(1, 80);
        User user = new User(1, "zhangSan", 25, student);
        User newUser = (User) user.clone();//浅拷贝
        System.out.println(newUser.toString());
        //使用这种方式修改student引用,newUser是不会跟着变得,因为创建了一个新的Student类对象,而不是改变原对象的实例值
        //user.setStudent(new Student(2, 90));
        student.setScore(90);
        System.out.println(newUser.toString());
    }
}

输出:

User(id=1, name=zhangSan, age=25, student=Student(id=1, score=80))
User(id=1, name=zhangSan, age=25, student=Student(id=1, score=90))

可以发现原对象user中的Student实例值改变后,拷贝对象newUser中的student实例值也跟着变了,说明是同一个引用。

3,深拷贝

深拷贝不仅复制对象本身,而且复制对象包含的引用指向的所有对象。

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student implements Cloneable {
    private Integer id;
    private Integer score;

    @Override
    public Object clone(){
        try{
            return (Student) super.clone();
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Cloneable {
    private Integer id;
    private String name;
    private Integer age;
    private Student student;

    @Override
    public Object clone() {
        User user = null;
        try {
            user = (User) super.clone();
        } catch (Exception e) {
            e.printStackTrace();
        }
        user.student = (Student) student.clone();//调用student的clone方法
        return user;
    }
}
public class CopyTest {
    public static void main(String[] args) {
        Student student = new Student(1, 80);
        User user = new User(1, "zhangSan", 25, student);
        User newUser = (User) user.clone();//浅拷贝
        System.out.println(newUser.toString());
        //user.setStudent(new Student(2, 90));//使用这种方式修改student引用,newUser是不会跟着变得,因为创建了一个新的Student类对象,而不是改变原对象的实例值
        student.setScore(90);
        System.out.println(newUser.toString());
    }
}

输出:

User(id=1, name=zhangSan, age=25, student=Student(id=1, score=80))
User(id=1, name=zhangSan, age=25, student=Student(id=1, score=80))

原user对象中student引用的实例值改变了,拷贝后的对象中引用的实例值没有变,说明它们两个不是同一个引用。

4,序列化拷贝

在Java语言里深复制一个对象,常常可以先使对象实现Serializable接口,然后把对象(实际上只是对象的一个拷贝),写到一个流里,再从流里读出来,便可以重建对象。

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student implements Serializable {
    private Integer id;
    private Integer score;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {
    private Integer id;
    private String name;
    private Integer age;
    private Student student;
}
public class CopyTest {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Student student = new Student(1, 80);
        User user = new User(1, "zhangSan", 25, student);
        //ByteArrayOutputStream:    可以捕获内存缓冲区的数据,转换成字节数组。
        //ByteArrayInputStream: 可以将字节数组转化为输入流
        ByteArrayOutputStream bo = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(bo);
        objectOutputStream.writeObject(user);//将user对象,以字节数组的形式写入到内层缓冲区中
        ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
        ObjectInputStream objectInputStream = new ObjectInputStream(bi);
        User newUser = (User) objectInputStream.readObject();//反序列化,生成对象(深拷贝)
        student.setScore(90);
        System.out.println(user);
        System.out.println(newUser);
    }
}

输出:

User(id=1, name=zhangSan, age=25, student=Student(id=1, score=90))
User(id=1, name=zhangSan, age=25, student=Student(id=1, score=80))
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java对象复制(直接赋值,浅拷贝,深拷贝) 的相关文章

随机推荐

  • Latex单行/多行公式居中/左对齐

    一 单行公式居中 代码如下 示例 begin equation label eq1 y kx b end equation 输出 二 单行公式左对齐 代码如下 示例 begin flalign label eq2 y kx b end fl
  • js数组常用的方法

    js数组的相关语法 一 数组的声明 1 标准式写法 2 白话式写法 二 数组的赋值 1 在建立数组的时候直接赋值 2 根据键值进行赋值 三 数组的取值 四 concat 数组拼接方法 五 join 数组转化为字符串 六 reverse 数组
  • jenkins安装pmd对代码进行静态分析

    1 在Jenkins的插件管理中 安装PMD Plugin插件 2 在被编译的代码中 增加如下配置 1 顶级pom中 在dependencyManagement中增加对PMD插件的依赖
  • 类的构造函数,拷贝构造函数

    C Primer 类的构造函数 拷贝构造函数 在说这些内容之前 先说以下几个内容 内置类型 算术类型 整型 字符 布尔型 浮点型 和空类型 空类型不对应具体的值 仅用于一些特殊的场合 1 初始化 当对象再创建时获得了一个特定的值 我们说这个
  • linux文本处理常用命令,Linux文本处理常用命令

    Linux文本处理常用命令 grep sed printf awk cut sort 1 grep 按行查找字符 输出包含字符的行 用法grep key test txt cat test txt grep key 参数含义及示例 n输出结
  • 常用测试平台

    目录 测试用例管理 bug管理平台 代码管理平台 持续集成管理平台 流程管理平台 1 测试用例管理 jira 推荐方案 定制性很强 redmine 推荐方案 开源 活跃 定制性很强 testlink 流行的测试用例管理平台 体验不太好 其他
  • 每日一题面试题 - 持续更新

    周一到周五更新 1 undefined和null的区别 20230614 undefined 1 声明了一个变量 但没有赋值 2 对象属性没有赋值 3 调用函数没有提供相应的参数 4 函数没有返回值 默认undefined 5 undefi
  • ps如何把自己的图与样机结合_Ps如何套用样机图?

    回答 步骤1 首先你需要寻找一些方便展示作品的实体图片 你可以拍几张 也可以从各大图片素材库寻找 我们这次教程的素材是从istock图库网下载的 步骤2 还要找一些你想要展示的图片或作品 我准备在名片上展示我的名字 笔记本电脑展示我的个人网
  • 【信号去噪】基于非线性滤波器实现语音自适应去噪附matlab代码

    1 简介 2 部分代码 function A construct operator T rho y if iscolumn y 1d L length y T 1 A zeros L 1 T 1 for i 1 T 1 take the i
  • 汇编:将表格写入到指定内存空间

    代码如下 assume cs code ds data es table ss stack data segment db 1975 1976 1977 1978 1979 1980 1981 1982 1983 db 1984 1985
  • asp二进制mysql_asp.net读取显示二进制图片从MySQL数据库

    ashx页面MemoryStreamstream newMemoryStream SqlConnectionconnection newSqlConnection 省略 try connection Open SqlCommandcomma
  • k8s混合部署 ? 多套集群统一管理?

    master 和 node 操作系统和内核不一样 在 Kubernetes 中 Master 和 Node 的操作系统和内核可以不同 Master 节点主要负责集群管理和控制 而 Node 节点主要负责容器的运行和管理 因此 Master
  • 二叉树:由中序、后序求先序

    文章目录 一 题目描述 二 代码 三 代码详解 1 getPos 2 dfs函数 基本的递归思路是 以下几点需要注意 一 pos 1是中序数组左子树的右端点 二 左子树右端点 三 几种变式 四 关于post R cnt R 1为什么不直接写
  • 关于CANoe的Panel使用介绍

    关于CANoe的Panel使用介绍 一 新建步骤 使用CANoe新建Panel工程的步骤如下 打开CANoe软件 在 Project 视图中 右键单击您想要创建Panel工程的CANoe配置文件 然后选择 New Panel Project
  • js的事件机制总结

    js的事件机制包括三个阶段 捕获 目标和冒泡 1 事件冒泡 微软提出了名为事件冒泡的事件流 事件冒泡可以形象地比喻为把一颗石头投入水中 泡泡会一直从水底冒出水面 也就是说 事件从最内层的元素开始发生 一直向上传播 直到document对象
  • 全球各国官方语言大盘点,英语不得不学哇。。。

    因国家和地区范围界定不同 官方语言只是个相对概念 具体而言是一个国家通用的正式语言或认定的正式语言 它是为适应管理国家事务的需要 在国家机关 正式文件 法律裁决及国际交往等官方场合中规定一种或几种语言为有效语言的现象 官方语言也是一个国家的
  • 统一日志处理切面

    import cn hutool core util StrUtil import cn hutool core util URLUtil import cn hutool json JSONUtil import com macro ma
  • 如何通过百度翻译实现整站网页翻译

    gt 通过百度翻译接口开通 小飞兔 整站翻译功能 英文网站翻译成中文网站 中文网站翻译成英文网站 本软件是通过百度翻译接口 将英文网页翻译成中文网页或中文网页翻译成英文网页 逐一翻译文本内容 并保持原页面的样式结构 一 下载软件https
  • python脚本——selenium自动化执行一些网页上的操作

    文章目录 一 说明 二 代码 三 用法总结 一 说明 通过python的selenium模块 自动化执行一些网页上的重复的无聊的工作 二 代码 usr bin python3 6 from time import sleep import
  • Java对象复制(直接赋值,浅拷贝,深拷贝)

    目录 Java对象复制 1 直接赋值 2 浅拷贝 3 深拷贝 4 序列化拷贝 Java对象复制 将一个对象的引用复制给另一个对象 一共有三种方式 第一种是直接赋值 第二种方式是浅拷贝 第三种是深拷贝 这三种方式实际上都是为了拷贝对象 1 直