List.add 方法添加元素时只会添加最后一条元素的分析解决

  • 前言
  • 一、问题描述
  • 二、原因分析
    • 1.简化分析
    • 2.回归本题
  • 总结

前言

在之前编写业务代码时, 遇到了一个比较神奇的现象, 如标题中描述的那样:
在对list 集合使用 add/set 方法并且遍历的去添加对象时, 只会添加最后一个元素的问题 .
下面就进行简单的分析,

一、问题描述

现有一个需求:
在请求时携带一个map, 该map里面的key有几个. 那么, 在返回结果集 map中就需要将对应的 key 和 value 捞出来一起展示,
如果结果不止一个map, 则将这些map放入一个list中

  1. 模拟代码片如下

            //模拟请求Map<String, Object> requestMap = new HashMap<>();requestMap.put("id", "");requestMap.put("passwd", "");requestMap.put("userName", "");//模拟结果集Map<String, Object> resultMap = new HashMap<>();resultMap.put("id", "1");resultMap.put("passwd", "odd taxi");resultMap.put("userName", "小早川");Map<String, Object> resultMap2 = new HashMap<>();resultMap2.put("id", "2");resultMap2.put("passwd", "Brazilian war dance");resultMap2.put("userName", "白川");List<Map<String, Object>> resultListMap = new ArrayList<>();resultListMap.add(resultMap);resultListMap.add(resultMap2);//模拟响应List<Map<String, Object>> responseListMap = new ArrayList<>();Map<String, Object> responseMap = new HashMap<>();// 实现: 根据请求map中的 key, 返回所有结果集中含有请求map所带k的list.map集合for (Map<String, Object> resMap : resultListMap) {requestMap.forEach((k, v) -> {responseMap.put(k, resMap.get(k));});responseListMap.add(responseMap);}System.out.println("responseListMap = " + responseListMap);
    
  2. 结果演示
    可以看到, 在上面结果集 resultListMap遍历过程中, 我们根据请求 requestMap的key 去结果集中寻找key对应的value
    然后放入 responseMap, 因为结果集map 不止一个, 所以将其放入list 中.
    但是, 最后返回的list 中只有两条相同的数据, 而且都是最后插入的一条数据

二、原因分析

1.简化分析

  1. 为了将原来的问题简化, 我们可以在把问题简化下, 下面是简化之后的代码
        List<User> userList = new ArrayList<>(2);User u1 = new User();for (int i = 0; i < 5; i++) {u1.setId(i);u1.setPwd("odd taxi"+ i);u1.setUsername("小早川"+ i);userList.add(u1);}for (User user : userList) {System.out.println("user = " + user);}
  1. 由下图可知
    list.add 通过遍历去调用, 又是只加入最后一条元素, 而且遍历几遍就有几条相同的元素

  2. 对上述代码进行断点调试
    由我们对每次循环对象属性和 userList 中属性对比可知:
    在每次循环结束后, userList 中所有的数据都会变成最后一次遍历数据*遍历次数




结合上面问题和调试结果, 以及资料可知:
1. List 中的 add, set 方法在添加对象(Object) 或者是集合(Collection)时, 添加的是对对象的引用
因此, 如果在循环外声明要保存的对象或集合, 但是却在循环内赋值的话, 就会导致上述问题
2. 因为在循环外对象或者集合只声明了一次, 因此无论如何赋值, 只会保存最后一次赋值.
在循环内 list.add 方法添加的实际上只相当于对最后一次插入的对象或者集合的引用

  1. 基于上述分析, 我们先修改简化版代码: 只需将对象初始化放在循环内即可
        List<User> userList = new ArrayList<>(2);User u1 ;for (int i = 0; i < 5; i++) {u1 = new User();u1.setId(i);u1.setPwd("odd taxi"+ i);u1.setUsername("小早川"+ i);userList.add(u1);}for (User user : userList) {System.out.println("user = " + user);}

2.回归本题

根据上述思路我们去解决实际问题, 对比下修改前和修改后的代码

  1. 修改前
     //---------------------修改前---------------------//模拟请求Map<String, Object> requestMap = new HashMap<>();requestMap.put("id", "");requestMap.put("passwd", "");requestMap.put("userName", "");//模拟结果集Map<String, Object> resultMap = new HashMap<>();resultMap.put("id", "1");resultMap.put("passwd", "odd taxi");resultMap.put("userName", "小早川");Map<String, Object> resultMap2 = new HashMap<>();resultMap2.put("id", "2");resultMap2.put("passwd", "Brazilian war dance");resultMap2.put("userName", "白川");List<Map<String, Object>> resultListMap = new ArrayList<>();resultListMap.add(resultMap);resultListMap.add(resultMap2);//模拟响应List<Map<String, Object>> responseListMap = new ArrayList<>();Map<String, Object> responseMap = new HashMap<>();// 实现: 根据请求map中的 key, 返回所有结果集中含有请求map所带k的list.map集合for (Map<String, Object> resMap : resultListMap) {requestMap.forEach((k, v) -> {responseMap.put(k, resMap.get(k));});responseListMap.add(responseMap);}System.out.println("responseListMap = " + responseListMap);
  1. 修改后
        //---------------------修改后---------------------//模拟请求Map<String, Object> requestMap = new HashMap<>();requestMap.put("id", "");requestMap.put("passwd", "");requestMap.put("userName", "");//模拟结果集Map<String, Object> resultMap = new HashMap<>();resultMap.put("id", "1");resultMap.put("passwd", "odd taxi");resultMap.put("userName", "小早川");Map<String, Object> resultMap2 = new HashMap<>();resultMap2.put("id", "2");resultMap2.put("passwd", "Brazilian war dance");resultMap2.put("userName", "白川");List<Map<String, Object>> resultListMap = new ArrayList<>();resultListMap.add(resultMap);resultListMap.add(resultMap2);//模拟响应List<Map<String, Object>> responseListMap = new ArrayList<>();// 实现: 根据请求map中的 key, 返回所有结果集中含有请求map所带k的list.map集合for (Map<String, Object> resMap : resultListMap) {// 问题修改: 将 list 需要 add 的对象/集合 放到循环内进行初始化!!!Map<String, Object> responseMap = new HashMap<>();requestMap.forEach((k, v) -> {responseMap.put(k, resMap.get(k));});responseListMap.add(responseMap);}System.out.println("responseListMap = " + responseListMap);
  1. 可以看出仅仅是将list 中需要 add 的集合 responseMap 的初始化放到循环内, 问题就得到解决, 如下图所示

总结

1. List 中的 add, set 方法在添加对象(Object) 或者是集合(Collection)时, 添加的是对对象的引用
2. 在循环外声明对象或集合, 在循环内使用list.add 就会导致list 中引用的数据地址全部都是最后一次添加的元素地址
如果想要避免. 只需要将被add的对象/集合在循环内初始化即可


参考: https://blog.csdn.net/ww77889126/article/details/84952631

List.add 方法添加元素时只会添加最后一条元素的问题与解决相关推荐

  1. 回味集合(三)ArrayList的add方法

    啥也不说了,直接撸源码: public class ArrayList<E> extends AbstractList<E>implements List<E>, ...

  2. thinkphp中mysql添加数据_thinkphp添加数据 add()方法

    thinkphpz内置的add()方法用于向数据库表添加数据,相当于SQL中的INSERT INTO 行为 添加数据 add 方法是 CURD(Create,Update,Read,Delete / ...

  3. HashSet中的add()方法( 二 )(详尽版)

    本篇接着上一篇:(详尽版)HashSet中的add()方法( 一 )(详尽版) 有些东西上一篇说过了,这里就不再赘述了,具体说一下再次添加与第一次添加的区别: import java.util.Has ...

  4. java数组末尾添加元素_java数组添加元素,java数组如何添加一个元素

    java数组如何添加元素 向数组里添加一个元素怎么添加,这儿总结有三种方法: 1.一般数组是不能添加元素的,因为他们在初始化时就已定好长度了,不能改变长度. 但有个可以改变大小的数组为ArrayLis ...

  5. 成功解决wps文档的论文中插入图片时只显示一半图片(两步教程完美搞定!)

    成功解决wps文档的论文中插入图片时只显示一半图片(两步教程完美搞定!) 目录 解决问题 解决思路 解决方法 解决问题 解决wps文档的论文中插入图片时只显示一半图片,如图所示, 解决

  6. wordpress添加html媒体文件,WordPress“添加媒体”文件时只显示上传到当前文章的附件图片...

    最近子凡把很大一部分精力都分散在了泪雪建站的改版和泪雪网的运营中去了,随着泪雪网的定位和内容的新增,网站也需要有很多细节的升级,而在今天就给大家分享一个 WordPress 如何在编辑文章时" ...

  7. Easyui中使用jquery或js动态添加元素时出现的样式失效的解决方法

    Easyui中使用jquery或js动态添加元素时出现的样式失效的解决方法 在添加完之后,可以使用 $.parser.parse();这个方法进行处理: (1) 对整个页面重新渲染: $.parser ...

  8. classList属性配合内置方法add()、remove()、toggle(),添加或删除某个类,以此改变CSS样式

    文章目录 知识储备 1.正则表达式 2.Syntax上需要注意的问题 3.属于多个类的情况下,样式的覆盖情况 方法一:改变内联样式 方法二: `classList`属性配合`add()`.`remov ...

  9. spring启动时只执行一次的方法实现

    spring项目如何在启动项目是执行一些操作,在spring中能通过那些操作实现这个功能呢. 1.方法一 我在spring的配置文件中添加上这条,这个配置只能在启动项目是执行一遍.  还有一点 要注意 ...

最新文章

  1. 《构建可扩展的Web站点》书评
  2. Vim快捷输出查找寄存器的内容(去除\,\和\V)
  3. 3.1.5 动态分区分配算法
  4. windows下安装配置mongodb
  5. Java学习小程序(10)三个等级的才字母游戏
  6. 音乐雷达 shazam算法_具有10亿首Shazam音乐识别功能的数据可视化
  7. Firefox 使用 Chrome 浏览器的 PDF 和 Flash 插件
  8. Linux常用shell脚本
  9. html+css+js 实现鼠标拖尾效果(源码)
  10. npm下载依赖失败并报错
  11. MYSQL命令行闪退问题解决
  12. 黑客游戏之Monyer系列
  13. 借助 Lucene.Net 构建站内搜索引擎(上)
  14. Mac 下JDK 1.8 下载地址
  15. 登录网络计算机提示用户名错误,局域网访问共享时提示登录失败:未知的用户名或错误密码 怎么回事...
  16. 网络爬虫学习第二弹:requests库的使用
  17. TIOBE 2月榜单出炉:排行榜前8位在过去七年中排名没有变化,是否意味着编程语言没有变化?
  18. 判断一个整数是否为回文数
  19. asp身份证号与姓名验证,asp身份证真伪查询,asp身份证核查代码
  20. NOJ-1401 乘车费用 题解要点

热门文章

  1. linux 增量备份文件,[转载]linux 文件增量备份  用tar实现
  2. CAD图纸无法正常缩放怎么办?如何解决?
  3. 3dm显卡测试软件,3DMark新版发布:全球第一个DirectX 12测试工具
  4. 小程序移植公众号网页,laravel,vue
  5. redis:地理位置信息geo
  6. 唐伯虎怎么才能快速找到秋香-二分查找算法
  7. 电商的千人千面系统,这样搞比较靠谱
  8. Google人脸识别系统Facenet paper解析
  9. 夏敏捷的24部著作(2019年)
  10. kpu.h文件研究(完善中)