List 和 Map 的深浅克隆

Java对象深拷贝详解(List深拷贝) Java对象深拷贝详解(List深拷贝) 解决List复制到新的List时,新的List值错误问题 阅读详情

一、List 的浅克隆

List 是 Java 容器中最常用的顺序存储数据结构之一。有些时候将一组数据取出放到一个 List 对象中,但是可能会很多处程序要读取或者是修改。尤其是并发处理的话,显然有的时候一组数据是不够用的。这个时候通常会克隆出一个甚至多个 List 来执行更多的操作。

List<String> souString = new ArrayList<>();
souString.add("xxx1");
souString.add("xxx2");
souString.add("xxx3");

1️⃣使用List实现类的构造方法

List<String> tarString = new ArrayList<>(souString);

2️⃣遍历循环复制

List<String> tarString = new ArrayList<>();
for(int i = 0, l = souString.size(); i < l; i++){
 tarString.add(listString0.get(i));
}

3️⃣调用 Collections 的静态工具方法 Collections.copy

List<String> tarString = new ArrayList<>(
    Arrays.asList(new String[souString.size()]));
Collections.copy(tarString,souString);

4️⃣使用 System.arraycopy 方法进行复制

String[] strs = new String[souString.size()];
System.arraycopy(listString0.toArray(), 0, strs, 0, souString.size());
List<String> tarString = Arrays.asList(strs);

5️⃣使用 Stream 的方式 copy

List destList = srcList.stream().collect(Collectors.toList());

6️⃣使用 list.addAll()

List destList = new ArrayList();  
destList.addAll(srcList); 

【测试】试着改变 souString 的某一个元素的值,如果其他列表中的值没有受到影响那么就是复制成功了。

souString.set(0, "rock");
for(int i = 0, l = souString.size(); i < l; i++){    
  System.out.println("souString第"+i+"个值:"+souString.get(i));
  System.out.println("tarString第"+i+"个值:"+tarString.get(i));    
}

输出结果符合预期,这几个方法都实现了 list 的复制。修改本体并没有影响到复制体。但是对象呢?

二、List 的深克隆

创建一个 Pojo 类:

import java.io.Serializable; 
public class PojoStr implements Serializable{
    private String str = "";
    public String getStr(){
        return str;
    }
    public void setStr(String str){
        this.str = str;
    }
}

这个 Pojo 类只存储了一个字符串,同样可以模拟之前的几种复制方法,代码如下:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
 
public class Test {
    public static void main(String[] args) {
        List<PojoStr> souString = new ArrayList<>();
        PojoStr p1 = new PojoStr();
        p1.setStr("xxx1");
        souString.add(p1);
        PojoStr p2 = new PojoStr();
        p2.setStr("xxx2");
        souString.add(p2);
        PojoStr p3 = new PojoStr();
        p3.setStr("xxx3");
        souString.add(p3);
 
        List<PojoStr> tarString1 = new ArrayList<>(souString);
 
        List<PojoStr> tarString2 = new ArrayList<>();
        for(int i = 0, l = souString.size(); i < l; i++)
            tarString2.add(souString.get(i));
 
        List<PojoStr> tarString3 = new ArrayList<>(Arrays.asList(new PojoStr[souString.size()]));
        Collections.copy(tarString3,souString);
 
        PojoStr[] strs = new PojoStr[souString.size()];
        System.arraycopy(souString.toArray(), 0, strs, 0, souString.size());

        List<PojoStr> tarString4 = Arrays.asList(strs);
        souString.get(0).setStr("rock");
        for(int i = 0, l = souString.size(); i < l; i++) {
            System.out.println("souString第"+i+"个值:"+souString.get(i).getStr());
            System.out.println("tarString1第"+i+"个值:"+tarString1.get(i).getStr());
        }        
    }
}

由于本体表的某个数据的修改,导致后续的克隆表的数据全被修改了,这四种方法无一例外。也就是说对于自定义 POJO 类而言上述的四种方法都未能实现对元素对象自身的复制。复制的只是对象的引用或是说地址。

解析:
List 自身是一个对象,在存储类类型的时候,只负责存储地址。而存储基本类型的时候,存储的就是实实在在的值。其实上边的案例也说明了这点,因为修改 PojoStr-List 的时候直接的修改了元素本身而不是使用的 ArrayList 的 set(index,object) 方法。所以纵然有千千万万个 List,元素还是那么几个。无论是重新构造,Collections 的复制方法,System 的复制方法,还是手动去遍历,结果都一样,这些方法都只改变了 ArrayList 对象的本身,简单的添加了几个指向老元素的地址,而没做深层次的复制。(压根没有 new 新对象的操作出现。)当然有的时候,确实需要将这些元素也都复制下来而不是只是用原来的老元素。然而很难在 List 层实现这个问题。毕竟依照 Java 的语言风格,也很少去直接操作这些埋在堆内存中的数据,所有的操作都去针对能找到它们的地址了。地址没了自身还会被 GC 干掉。所以只好一点点的去遍历去用 new 创建新的对象并赋予原来的值。

如何深克隆?方法如下:
注:前提是 T 如果是 Pojo 类的话,必须实现序列化接口,这是对象进入 IO 流的基本要求
1️⃣【使用序列化方法】

@SuppressWarnings("unchecked")
public static <T> List<T> deepCopy(List<T> src) {
    try (ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
         ObjectOutputStream outputStream = new ObjectOutputStream(byteOut);
    ) {
        outputStream.writeObject(src);
        try (ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
             ObjectInputStream inputStream = new ObjectInputStream(byteIn);
        ) {
            return (List<T>) inputStream.readObject();
        }
    } catch (Exception e) {
        ThrowableUtils.getString(e);
    }
    return Collections.emptyList();
}

2️⃣【clone方法】

public class A implements Cloneable {
    public String name[];
    public A(){ name=new String[2]; }
    public Object clone() {
        A o = null;
        try {
            o = (A) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        } return o;
    }
}
for(int i=0;i<n;i+=){
    copy.add((A)src.get(i).clone());
}

三、Map 的深克隆

public class CopyMap {
    public static void main(String[] args) {
        Map<String, Integer> map11 = new HashMap<String, Integer>();
        map11.put("key1", 1);
        Map<String, Integer> map22 = map11;
        map11.put("key1", 3);
        System.out.println(map11);
        System.out.println(map22);
        System.out.println("------------------------------");
 
        Map<String, Integer> map1 = new HashMap<String, Integer>();
        map1.put("key1", 1);
        Map<String, Integer> map2 = new HashMap<String, Integer>();
        map2.putAll(map1);
        map1.put("key1", 3);
        System.out.println(map1);
        System.out.println(map2);
        System.out.println("------------------------------");

        Map<String, Dog> map3 = new HashMap<String, Dog>();
        Dog dog1 = new Dog("Dog1");
        map3.put("key1", dog1);
        Map<String, Dog> map4 = new HashMap<String, Dog>();
        map4.putAll(map3);
        System.out.println(map4);
        map3.get("key1").setName("dog3");
        System.out.println(map4);
        System.out.println("------------------------------");
 
        Map<String, Dog> map5 = new HashMap<String, Dog>();
        Dog dog5 = new Dog("Dog5");
        map5.put("key5", dog5);
        Map<String, Dog> map6 = (Map<String, Dog>) deepClone(map5);
        System.out.println(map6);
        map5.get("key5").setName("Dog7");
        System.out.println(map6);
    }
 
    public static Object deepClone(Object obj) {
        try {// 将对象写到流里
            ByteArrayOutputStream bo = new ByteArrayOutputStream();
            ObjectOutputStream oo = new ObjectOutputStream(bo);
            oo.writeObject(obj);// 从流里读出来
            ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
            ObjectInputStream oi = new ObjectInputStream(bi);
            return (oi.readObject());
        } catch (Exception e) {
            return null;
        }
    }
 }
 
class Dog implements Serializable {
    private String name;
    public Dog(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override public String toString() {
        return "Dog{" + "name='" + name + '\'' + '}';
    }
}
List集合的复制方式 如果要进行深拷贝(deep copy),即创建一个完全独立的新List,其中的元素是原始对象的副本而不是引用,那么需要自行实现深拷贝的逻辑。因此,在多线程环境下进行List集合复制时,需要确保对原始List集合的访问是线程安全的,例如使用线程安全的集合类或者添加适当的同步机制。以上两种复制方式都是浅拷贝(shallow copy),即如果List集合中存储的是对象引用,那么复制后的新List中的元素仍然是原始对象的引用,而不是对象的副本。因此,如果修改了原始对象,这些修改也会反映到复制后的List中。 阅读详情

相关推荐

Java 中 List 的 N 种深拷贝方式

不同的深拷贝方法各有优缺点,选择合适的方法取决于具体的应用场景。使用是实现深拷贝最直接的方式。使用 Stream API 提供了更简洁的语法。好啦,今天的分享就到这里。我们下次再见!👋🏻。

java专栏 3544

JAVA Map 的复制

https://www.cnblogs.com/Marydon20170307/p/9132042.html https://www.cnblogs.com/Marydon20170307/p/9131893.html MAP 实现 拷贝的方法有3种: = ----浅拷贝 .putAll() ----深拷贝 原始手动赋值 ----深拷贝 1、= 和.putAll() 经实际编码测试,参考文章有错:= 是浅拷贝,putAll() 是深拷贝。 与MAP , HashMap 无关。 public class

qq_46416934的博客 698

WIFI基础入门--802.11g--增强速率物理层ERP--15

WIFI基础入门--802.11--增强速率物理层--191.802.11g的组件保护机制 1.802.11g的组件 802.11g其实是将好几种物理层规范合而为一。虽然统称为增强速率物理层(Extended Rate PHY简称ERP),但是实际上ERP有好几种不同的方式: ERP-DSSS与ERP-CCK 这两种模式向下兼容于原始直接序列规范(1Mbps与2Mbps),以及所提到的802.11...

香蕉一号 4616

Java克隆复制一个新的List集合的方法

在Java开发中,有时候我们为了源List集合的数据不被修改,如果采用类似“new_list = old_list”这种形式来复制克隆一个新的List集合是绝对不行的,所以我们得采用下面的三种方法来复制一个新的List集合。 Java克隆复制ArrayList等List集合的方法一: Java中克隆复制一个List可以在创建List对象时通过将源List集合以参数的形式传入即可,代码如下:importjava.util.ArrayList; importjava.util.Arrays; importjav

web15285868498的博客 6458

Kaggle时间序列竞赛金牌方案解析与实战指南

本文深度解析了Kaggle时间序列竞赛的金牌方案,揭示了其成功不仅依赖先进模型,更在于系统工程思维。文章系统阐述了从数据理解、特征工程到模型集成与后处理的全流程,并重点剖析了分层建模、自定义损失函数、时序交叉验证等核心技巧,为参赛者提供了从理论到实战的完整指南。

weixin_29196315的博客 355

jmeter问题系列:Begin size 0 is not equal to fixed size 5

Begin size 0 is not equal to fixed size 5 ,问题的解决

雨水的早晨的博客 2411

List的多种克隆方式

List&lt;object&gt; list1 = new List&lt;object&gt;{"a","b","c"};1. var list2 = new List&lt;object&gt;(list1);2. var list3 = list1.FindAll( (str)=&gt; true );3. var list4 = list1.GetRange(0,list1

txh9123的专栏 6134

[华中科技计组实验]logisim完成单周期5级流水MIPS CPU

[华中科技计组实验]logisim完成单周期5级流水MIPS32 CPU hu~,终于完成了,真是费劲呐 支持24条指令,5级流水线,可以对分支指令处理,寄存器冲突处理,指令ROM为1K,数据RAM为1M,32位MIPS指令集CPU 但是… 大量使用比较器造成硬件开销巨大,测试一下发现这尼玛真是个老爷车还没单周期跑的快,自己电脑cpu占百分之八九十只能跑到20多赫兹,一个走马灯跑了半天,可优化空间太大了,写了那么多天造成这个破样,有点悲剧。。。 先放个图大伙参考就行了,要是有人想听思路的话接下来再更 .

zrc的博客 1万+

Map复制给新Map时,用 “=、clone、还是putAll”?论Map的深复制和浅复制

目录使用场景尝试过的办法“=”赋值使用.putAll()方法使用.clone()方法测试用例测试用例源码 使用场景 在我们最初使用map复制开发业务代码时,通常会踩到深浅复制(拷贝)这个坑里,比如我,在Map复制时 (如:Map<String, String> new_Map = old_Map) 出现过以下两类问题: 1.使用Map<String, String> new...

陈哈哈的菜园子 1万+

正点原子ATK-LORA-01无线串口代码移植+STM32F103C8T6(标准库)

目录 一、ATK-LORA-01无线串口资料 二、代码移植 1.分析 (1)usart3(也可以是其他的串口)用于接收数据的串口 usart.h (2)time3(也可以是其他的定时器)用于时序的设置 (3)lora.c 三、演示 1.主机(发送方) (1)主机接线 (2)主机代码(发送方) (3)主机实物 插上无线串口通电即可发送​ 2.从机(接收方) (1)从机接线(LORA与主机相同) (2)从机代码(接收方) (3)从机实物 接上TTL和LORA并通电即...

m0_56942354的博客 8963

《QGIS快速入门与应用基础》223:纸张大小与方向(A4/A3/自定义)

本文详细介绍了QGIS布局页面设置的核心操作,重点讲解了纸张大小与方向的设置方法。文章首先指出页面设置是地图排版的基础前提,强调合理设置可避免导出打印时出现尺寸不符等问题。随后详细说明了三种打开页面设置面板的方式,并重点解析了纸张设置的要点:标准预设纸张(A4/A3等)适用于大多数场景,提供国内常用规格对照表;自定义纸张则需谨慎使用,需注意单位选择和尺寸限制。通过界面标注图和操作步骤示意图,帮助用户掌握正确的设置方法,确保最终出图符合规范要求。文章特别提醒新手要优先使用标准预设纸张,避免常见错误,为后续地图

LuckyHanMo的博客 343

React学习32(深浅克隆之Immutable.js)

深克隆 immutable Map List

xiaojian044的博客 1295

【LIN总线测试】——LIN主节点物理层测试

LIN总线是基于UART/SCI(通用异步收发器/串行接口)的低成本串行通讯协议。其目标定位于车身网络模块节点间的低端通信,主要用于智能传感器和执行器的串行通信,而这正是CAN总线的带宽和功能所不要求的部分。本章节主要介绍LIN主节点物理层如何测试?

测试领域技术分享 5527

Java List的深度克隆

关于java List的深度克隆 List是java容器中最常用的顺序存储数据结构之一。有些时候我们将一组数据取出放到一个List对象中,但是可能会很多处程序要读取他或者是修改他。尤其是并发处理的话,显然有的时候有一组数据有的时候是不够用的。这个时候我们通常会复制出一个甚至多个克隆List来执行更多的操作。 常见的List的克隆方式有很多,下面我们来列举几种常见的List复制的方式: (首先...

weixin_30881367的博客 1849

OpenHarmony 显示Display驱动全栈解析:DisplayLayer + Gralloc + Gfx 三位一体,打造高性能图形底座

OpenHarmony Display显示驱动模块是系统图形渲染和显示功能的基础组件,负责管理显示设备、图层渲染、内存分配等核心功能。该模块采用HDI(Hardware Driver Interface)设计架构,为上层图形服务提供统一的显示能力接口,实现了显示设备的初始化、图层管理、内存分配与映射、硬件加速等关键功能。DisplayLayer:负责显示图层的管理, 包括图层创建、显示属性设置、图层填充及刷新等操作;

m0_67505153的博客 313

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

java将map中的值复制到另一个map中

需要将一个sourceMap中设置的属性值copy到另一个targetMap中去,要求在sourceMap中没有设置的值,targetMap要保持不变,并且支持List中有Map的情况的复制。**解决方案:**递归复制map中的值,List中如果是map的话则继续递归复制值。

qq_44079295的博客 4436

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

java List深拷贝

不管是new ArrayList(array);还是array.stream().collect(Collectors.toList()); 都做不到List array的深拷贝。

beConcentration的博客 9734

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

Java深拷贝和浅拷贝Map对象

目录 1 将Map深拷贝到另一个Map对象当中 2 浅拷贝Map 1 将Map深拷贝到另一个Map对象当中 今天赋值的时候遇到的小坑 相关文章推荐: Java克隆方式避免频繁创建对象优化方案 https://blog.csdn.net/ZGL_cyy/article/details/126556907 1.需求说明 将一个MapA对象中所有的键值对完全拷贝到另一个MapB对象中; 另一个MapB对象中原来的键值保持不变(不受影响); 拷贝成功后MapB对象当中的内容将不再随着MapA中内容的变化而

赵广陆 5366

List的深度克隆

在完成ArrayList的复制的时候,发现通过list.addAll()方法复制的List中的对象,和原来List 中的对象是同一个地址,这意味着你修改复制的list中的一个对象,那么原来list 中的对象也会跟着变化!这称为浅克隆,在很多地方浅克隆,不能实现我们需求。深度克隆,是指在复制list的时候,list 中的对象,也都是新的对象(和原list中的对象地址不同) 1.深度复制的代码(据说

KunGGG的博客 1519

java克隆map_Java HashMap clone()方法

Java HashMap clone()方法java.util.HashMap.clone()用于返回此HashMap实例的浅表副本:键和值本身不会被克隆。1 语法public Object clone()2 参数无3 返回值返回此映射的浅表副本。4 示例package com.yiidian;/*** 一点教程网: http://www.yiidian.com*//*** java.util....

weixin_34094525的博客 3288

List的复制(浅拷贝与深拷贝)

开门见山的说,List的复制其实是很常见的,List其本质就是数组,而其存储的形式是地址如图所示,将List 0列表复制时,其实相当于List0的内容复制给了List1,java中相同内容的数组指向同一地址,即进行浅拷贝后List0与List1指向同一地址。造成的后果就是,改变List1的同时也会改变List0,因为改变List1就是改变List1所指向地址的内容,由于List0也指向同一地址,所以List0与List1一起改变。

qq_42296835的博客 6488

java集合深度复制_Java深度复制List内容。

最近在工作的时候,有一个小需求,需要复制List的内容,然后会改变其中的数据,但是试了几种复制的方法,都是将原有的数据和复制后的数据都改变了,都没有达到我想要的效果。其中涉及到了 “浅复制”和“深复制”的概念,这里不多说,可以参考这篇浅复制和深复制。我只记录了这一个深复制的代码,网上找的其它的深复制,好像不起作用。下面是代码:/*** 深度拷贝* @param src* @param <&g...

weixin_42340136的博客 1385

java map 克隆_HashMap对象的深层克隆

1.java.util.HashMap 的 clone 方法是浅层copy,clone出来的对象,仅仅是原来对象的一个引用,并且对克隆出来的对象进行操作是无效的。下面是个例子:importjava.util.HashMap;importjava.util.Iterator;importjava.util.Map;/***@authorhzp**/public classTest {/***@par...

weixin_42392054的博客 1913

Java List中内容的深复制

探讨如何对Java List中内容的深复制,结论是把List中的对象进行clone(),或者序列化的方法可以达到目的,而把List本身(对象的容器)进行clone()是不行的。

我的博客 5967

Map深克隆与浅克隆问题

对元素是map的list进行深拷贝 1)先准备一个list,装有两个map,map的键值是基本数据类型 List list=new ArrayList<Map<String,String>>(); HashMap<String, String> map=new HashMap<String, String>(); map.put("1", "one"); map.put("2", "two"); map.put("3", "three

xc6588的博客 2151
上一篇: Map 的遍历
下一篇: ConcurrentHashMap、Hashtable、HashMap
JFS_Study
博客等级 码龄6年 363粉丝 359原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JFS_Study

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值