iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > JAVA >Java对象深拷贝详解(List深拷贝)
  • 613
分享到

Java对象深拷贝详解(List深拷贝)

java 2023-09-04 15:09:18 613人浏览 八月长安
摘要

1、Java中拷贝的概念 在Java语言中,拷贝一个对象时,有浅拷贝与深拷贝两种 浅拷贝:只拷贝源对象的地址,所以新对象与老对象共用一个地址,当该地址变化时,两个对象也会随之改变。 深拷贝:拷贝对象的所有值,即使源对象发生任何改变,拷贝的值

1、Java中拷贝的概念

在Java语言中,拷贝一个对象时,有浅拷贝与深拷贝两种

浅拷贝:只拷贝源对象的地址,所以新对象与老对象共用一个地址,当该地址变化时,两个对象也会随之改变。

深拷贝:拷贝对象的所有值,即使源对象发生任何改变,拷贝的值也不会变化。

在User类的基础上,介绍两种浅拷贝案列

User类:

@Datapublic class User {    private String name;    private Integer age;}

案列①:普通对象的浅拷贝

package com.shuizhu.study;//浅拷贝案例1public class Study01 {    public static void main(String[] args) {        User user1 = new User();        user1.setName("张三");        user1.setAge(18);        User user2 = user1;        System.out.println("user1未改变前,user2的名字为:" + user2.getName());        user1.setName("李四");        System.out.println("user1未改变前,user2的名字为:" + user2.getName());    }}

结果:改变user1后,user2的值也随之变化

案列②:List浅拷贝(这也是我们平时项目中,经常遇到的情况)

package com.shuizhu.study;import java.util.ArrayList;import java.util.List;import java.util.stream.Collectors;//Java浅拷贝案列2public class Study02 {    public static void main(String[] args) {        List list1 = new ArrayList<>();        User user1 = new User();        user1.setName("张三");        user1.setAge(18);        User user2 = new User();        user2.setName("李四");        user2.setAge(19);        list1.add(user1);        list1.add(user2);        //TODO 以下是开发中,经常发生的浅拷贝        //方式1:通过new ArrayList方式,把list01拷贝给list02        List list2 = new ArrayList<>(list1);        System.out.println("list1未改变前,list2的结果为:" + list2);        //方式2:通过addAll方法,把list01拷贝给list02        List list3 = new ArrayList<>();        list3.addAll(list1);        System.out.println("list1未改变前,list3的结果为:" + list3);        //方式3:通过stream流的方式,把list01拷贝给list02        List list4 = list1.stream().collect(Collectors.toList());        System.out.println("list1未改变前,list4的结果为:" + list4);        //改变list1集合中的user1对象        System.out.println("--------------------------------------------");        user1.setName("老六");        user1.setAge(78);        System.out.println("list1改变后,list2的结果为:" + list2);        System.out.println("list1改变后,list3的结果为:" + list3);        System.out.println("list1改变后,list4的结果为:" + list4);    }}

结果:对List的3种拷贝,其实都是浅拷贝,当源集合中对象发生改变时,新的List也会随之变化

2、常见的深拷贝方式

  1. 构造函数方式(new的方式)
  2. 重写clone方法
  3. Apache Commons Lang序列化
  4. Gson序列化
  5. Jackson序列化

2.1、构造函数方式

这种方式就是创建一个新的对象,然后通过源对象的get方法与新对象set方法,把源对象的值复制新对象,这里就不再演示了。

缺点:在拷贝的对象数量较少时,可以使用,但是对象数量过多时,会大大增加系统开销,开发中应避免使用。

2.2、重写clone方法

步骤:

1>需要拷贝对象的类,去实现Cloneable接口

2>重写clone方法

3>使用"对象.clone()"的方式进行拷贝

根据上面的案列,进行对应的改造:

首先是User实体类 ,如下:

@Datapublic class User implements Cloneable{    private String name;    private Integer age;    @Override    protected User clone() throws CloneNotSupportedException {        return (User) super.clone();    }}

改造案列①:

package com.shuizhu.study;//Java深拷贝案列public class Study03 {    public static void main(String[] args) throws CloneNotSupportedException {        User user1 = new User();        user1.setName("张三");        user1.setAge(18);        User user2 = user1.clone();        System.out.println("user1未改变前,user2的名字为:" + user2.getName());        user1.setName("李四");        System.out.println("user1未改变前,user2的名字为:" + user2.getName());    }}

结果:当user1改变后,user2的值不会改变

改造案列②:List类型深拷贝

package com.shuizhu.study;import java.util.ArrayList;import java.util.List;import java.util.stream.Collectors;//Java深拷贝案列public class Study04 {    public static void main(String[] args) {        List list1 = new ArrayList<>();        User user1 = new User();        user1.setName("张三");        user1.setAge(18);        User user2 = new User();        user2.setName("李四");        user2.setAge(19);        list1.add(user1);        list1.add(user2);        /        //通过clone方式,把list01拷贝给list02        List list2 = new ArrayList<>();          //TODO 当数据量多时,建议使用对象的方式,把List当做属性,然后拷贝哦到一个新的对象中,从而不需要循环,可以见Apache Commons Lang序列化深拷贝方式        list1.forEach(user->{            try {                list2.add(user.clone());            } catch (CloneNotSupportedException e) {                e.printStackTrace();            }        });        System.out.println("list1未改变前,list2的结果为:" + list2);                //改变list1集合中的user1对象        System.out.println("--------------------------------------------");        user1.setName("老六");        user1.setAge(78);        System.out.println("list1改变后,list2的结果为:" + list2);    }}

结果:list1中的每个对象通过clone()添加list2中,当list1中的对象改变时,list2不会改变

2.3 、Apache Commons Lang序列化

步骤:

1>导入Commons包

   org.apache.commons   commons-lang3   3:3.5

2>实体类实现Serializable接口

@Datapublic class User implements Serializable {    private String name;    private Integer age;}

3>调用SerializationUtils工具类,实现深拷贝(注意:SerializationUtils不能直接拷贝List类型)

案列如下:

案列①:对象深拷贝

package com.shuizhu.study2;import org.apache.commons.lang3.SerializationUtils;//Apache Commons Lang序列化实现对象的深拷贝public class Study01 {    public static void main(String[] args) {        User user1 = new User();        user1.setName("张三");        user1.setAge(18);        User user2 = SerializationUtils.clone(user1);        System.out.println("user1未改变前,user2的名字为:" + user2.getName());        user1.setName("李四");        System.out.println("user1改变后,user2的名字为:" + user2.getName());    }}

结果:user1的改变不会导致user2的改变,从而实现深拷贝

 

案列②:List类型深拷贝

(1)改造开始,我们先创建一个专门用于拷贝List类型的实体类

package com.shuizhu.study2;import java.io.Serializable;import java.util.List;@Datapublic class UserCopyDTO implements Serializable {//必须实现Serializable接口    private List users;}

(2)拷贝List类型

package com.shuizhu.study2;import org.apache.commons.lang3.SerializationUtils;import java.util.ArrayList;import java.util.List;//Apache Commons Lang序列化实现List的深拷贝public class Study02 {    public static void main(String[] args) {        List list1 = new ArrayList<>();        User user1 = new User();        user1.setName("张三");        user1.setAge(18);        User user2 = new User();        user2.setName("李四");        user2.setAge(19);        list1.add(user1);        list1.add(user2);        //使用UserCopyDTO对象,专门用于拷贝List类型数据,不需要再去遍历list1         UserCopyDTO userCopyDTO = new UserCopyDTO();        userCopyDTO.setUsers(list1);        //通过Apache Commons Lang序列化方式,把list01拷贝给list02        UserCopyDTO clone = SerializationUtils.clone(userCopyDTO);        List list2 = clone.getUsers();        System.out.println("list1未改变前,list2的结果为:" + list2);        //改变list1集合中的user1对象        System.out.println("--------------------------------------------");        user1.setName("老六");        user1.setAge(78);        System.out.println("list1改变后,list2的结果为:" + list2);    }}

结果:

 2.4、Gson序列化

步骤:

导入Gson依赖

    com.Google.code.gson    gson    2.8.5

2>创建Gson对象,使用该对象进行深拷贝(实体类不再需要实现Serializable接口)

案例如下:只演示对象的深拷贝,LIst类型的深拷贝与之前的流程是相似的

package com.shuizhu.study3;import com.google.gson.Gson;//Gson序列化实现对象的深拷贝public class Study01 {    public static void main(String[] args) {        User user1 = new User();        user1.setName("张三");        user1.setAge(18);        Gson gson = new Gson();        User user2 = gson.fromJSON(gson.tojson(user1), User.class);        System.out.println("user1未改变前,user2的名字为:" + user2.getName());        user1.setName("李四");        System.out.println("user1改变后,user2的名字为:" + user2.getName());    }}

重点:

结果:

 

 2.5、Jackson序列化

该方式与Gson原理、使用方式相似,但是Jackson序列化深拷贝,要求拷贝的对象必须有无参构造函数

步骤:

1>导入Jackson依赖

    com.fasterxml.jackson    core    2.2.2    com.fasterxml.jackson    databind    2.2.2

2>创建ObjectMapper对象,进行深拷贝(用法与Gson一致)

package com.shuizhu.study4;import com.fasterxml.jackson.databind.ObjectMapper;import java.io.IOException;//Jackson序列化实现对象的深拷贝public class Study01 {    public static void main(String[] args) {        User user1 = new User();        user1.setName("张三");        user1.setAge(18);        ObjectMapper mapper = new ObjectMapper();        User user2 = null;        try {            user2 = mapper.readValue(mapper.writeValueAsString(user1), User.class);        } catch (IOException e) {            e.printStackTrace();        }        System.out.println("user1未改变前,user2的名字为:" + user2.getName());        user1.setName("李四");        System.out.println("user1改变后,user2的名字为:" + user2.getName());    }}

重点:

结果:

 

3、总结

方式优点缺点
构造函数1. 底层实现简单 2. 不需要引入第三方包 3. 系统开销小 4. 对拷贝类没有要求,不需要实现额外接口和方法1. 可用性差,每次新增成员变量都需要新增新的拷贝构造函数
重载clone()方法

底层实现较简单 2. 不需要引入第三方包 3. 系统开销小

追求性能的可以采用该方式

1. 可用性较差,每次新增成员变量可能需要修改clone()方法 2. 拷贝类(包括其成员变量)需要实现Cloneable接口
Apache Commons Lang序列化1. 可用性强,新增成员变量不需要修改拷贝方法1. 底层实现较复杂 2. 需要引入Apache Commons Lang第三方jar包 3. 拷贝类(包括其成员变量)需要实现Serializable接口 4. 序列化与反序列化存在一定的系统开销
Gson序列化1. 可用性强,新增成员变量不需要修改拷贝方法 2. 对拷贝类没有要求,不需要实现额外接口和方法1. 底层实现复杂 2. 需要引入Gson第三方JAR包 3. 序列化与反序列化存在一定的系统开销
Jackson序列化1. 可用性强,新增成员变量不需要修改拷贝方法1. 底层实现复杂 2. 需要引入Jackson第三方JAR包 3. 拷贝类(包括其成员变量)需要实现默认的无参构造函数 4. 序列化与反序列化存在一定的系统开销

 

 

 

 

 

来源地址:https://blog.csdn.net/weixin_42675423/article/details/128260074

--结束END--

本文标题: Java对象深拷贝详解(List深拷贝)

本文链接: https://www.lsjlt.com/news/393783.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Java对象深拷贝详解(List深拷贝)
    1、Java中拷贝的概念 在Java语言中,拷贝一个对象时,有浅拷贝与深拷贝两种 浅拷贝:只拷贝源对象的地址,所以新对象与老对象共用一个地址,当该地址变化时,两个对象也会随之改变。 深拷贝:拷贝对象的所有值,即使源对象发生任何改变,拷贝的值...
    99+
    2023-09-04
    java
  • java对象拷贝之深拷贝与浅拷贝
    要实现对象拷贝必须实现一个Cloneable接口,如果不实现这个接口就会产生一个CloneNotSupportedException异常。其实这个接口一个方法都没有,因此这类接口常被称作标记接口。Object 中有一个clone() 方法实...
    99+
    2016-12-31
    java入门 java 对象 深拷贝 浅拷贝
  • Java中浅拷贝和深拷贝详解
    目录Java浅拷贝深拷贝实现浅拷贝实现深拷贝Java浅拷贝深拷贝 浅拷贝和深拷贝涉及到了Object类中的clone()方法 实现浅拷贝 浅拷贝的实现需要类重写clone()方法 ...
    99+
    2022-11-12
  • JS对象复制(深拷贝和浅拷贝)
    目录一、浅拷贝1、Object.assign(target,source,source...)2、扩展运算符(spread)二、深拷贝1、使用对象序列化 JSON.stringify...
    99+
    2022-11-12
  • Java的深拷贝和浅拷贝深入了解
    关于Java的深拷贝和浅拷贝,简单来说就是创建一个和已知对象一模一样的对象。可能日常编码过程中用的不多,但是这是一个面试经常会问的问题,而且了解深拷贝和浅拷贝的原理,对于Java中的...
    99+
    2022-11-13
  • JavaScript中深拷贝与浅拷贝详解
    目录1 浅拷贝概念2 深拷贝概念3 浅拷贝的实现方式3.1 Object.assign()3.2 Array.prototype.concat()3.3 Array.pro...
    99+
    2022-11-13
  • Golang中深拷贝与浅拷贝详解
    目录什么是深拷贝?什么是浅拷贝?示例代码小结什么是深拷贝? 深拷贝(Deep Copy)是指原对象与拷贝的新对象互相独立,对其中任何一个对象的改动都不会对另外一个对象造成影响。值类型...
    99+
    2023-05-19
    Golang 深拷贝与浅拷贝 Golang深拷贝 Golang浅拷贝 Golang拷贝
  • Java中深拷贝,浅拷贝与引用拷贝的区别详解
    目录引用拷贝浅拷贝深拷贝小结引用拷贝 引用拷贝: 引用拷贝不会在堆上创建一个新的对象,只 会在栈上生成一个新的引用地址,最终指向依然是堆上的同一个对象。 //实体类 public c...
    99+
    2022-11-13
  • Java对象复制(直接赋值,浅拷贝,深拷贝)
    目录 Java对象复制1,直接赋值2,浅拷贝3,深拷贝4,序列化拷贝 Java对象复制 将一个对象的引用复制给另一个对象,一共有三种方式。第一种是直接赋值,第二种方式是浅拷贝,第三种是...
    99+
    2023-08-31
    java
  • C++拷贝构造函数(深拷贝与浅拷贝)详解
    对于普通类型的对象来说,它们之间的复制是很简单的,例如:int a=88;int b=a; 而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量。下面看一个类对象拷贝...
    99+
    2022-11-15
    拷贝构造函数 深拷贝 浅拷贝
  • Java Cloneable接口的深拷贝与浅拷贝详解
    目录Cloneable接口源码浅拷贝案例Pet类定义Person类定义浅拷贝问题-代码测试深拷贝案例Pet类重写clone()方法Person的clone()方法中调用Pet的clo...
    99+
    2022-11-13
  • Java Cloneable接口的深拷贝与浅拷贝详解
    Java中的Cloneable接口是一个标记接口,用于标识一个类可以被克隆。该接口没有定义任何方法,但是在使用clone()方法进行...
    99+
    2023-08-17
    Java
  • JavaScript深拷贝与浅拷贝实现详解
    目录对于基本类型数据对于引用类型数据实现深拷贝简单版够用版structuredClone对于基本类型数据 可以说都是深拷贝。 对于引用类型数据 对于引用类型数据,浅拷贝 后,因为浅拷...
    99+
    2022-11-13
    JavaScript深拷贝与浅拷贝 JS深拷贝与浅拷贝
  • java中的浅拷贝与深拷贝
    1、什么叫Java浅拷贝?浅拷贝是会将对象的每个属性进行依次复制,但是当对象的属性值是引用类型时,实质复制的是其引用,当引用指向的值改变时也会跟着变化。2、什么叫Java深拷贝?深拷贝复制变量值,对于引用数据,则递归至基本类型后,再复制。深...
    99+
    2021-10-17
    java教程 java 浅拷贝 深拷贝
  • Golang切片和数组拷贝详解(浅拷贝和深拷贝)
    目录golang切片和数组拷贝基础什么是浅拷贝和深拷贝?golang数组和切片的区别Golang中的值传递和引用传递golang数组拷贝数组和切片拷贝总结golang切片和数组拷贝 ...
    99+
    2023-05-17
    Golang切片和数组拷贝 golang切片拷贝 golang数组拷贝
  • js深拷贝和浅拷贝的深入讲解
    目录浅拷贝实现方法方法一:Object.assign方法二:扩展运算符方式方法三:concat和slice 浅拷贝数组深拷贝实现方法方法一:乞丐版(JSON.stringify和JS...
    99+
    2022-11-13
  • Python 的赋值,浅拷贝和深拷贝详解
    目录先明确几点赋值浅拷贝深拷贝总结 先明确几点 不可变类型:该数据类型对象所指定内存中的值不可以被改变。 (1)、在改变某个对象的值时,由于其内存中的值不可以被改变,所以,会把原来...
    99+
    2022-11-12
  • 什么是Java浅拷贝和深拷贝
    这篇文章主要讲解了“什么是Java浅拷贝和深拷贝”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“什么是Java浅拷贝和深拷贝”吧!问题“如果你有一个对象, 并...
    99+
    2022-10-19
  • 深入理解python中的浅拷贝和深拷贝
    在讲什么是深浅拷贝之前,我们先来看这样一个现象: a = ['scolia', 123, [], ] b = a[:] b[2].append(666) print a print b 为什么我只对...
    99+
    2022-06-04
    和深 python
  • 怎么理解python指针拷贝,浅拷贝和深拷贝
    本篇内容主要讲解“怎么理解python指针拷贝,浅拷贝和深拷贝”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“怎么理解python指针拷贝,浅拷贝和深拷贝”吧!首先对于不可变类型int,strin...
    99+
    2023-06-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作