• Java 如何实现 List<String> 的深拷贝?


      对于 List<String> 的深拷贝,Java 有几种方法可以实现,分述如下。

    一、List<String> 的深拷贝
    1.1 循环遍历复制
    	public static void main(String[] args) {
            List<String> fruits = new ArrayList<>();
            fruits.add("Banana");
            List<String> copyFruits = new ArrayList<>();
            for (String fruit : fruits) {
                copyFruits.add(fruit);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    1.2 利用构造器,使用 List 实现类的构造方法

      复制一个 List 的简单方法,是使用以一个集合作为参数的构造函数。

    	public static void main(String[] args) {
            List<String> fruits = new ArrayList<>();
            fruits.add("Banana");
            List<String> copyFruits = new ArrayList<>(fruits);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    1.3 使用 list.addAll() 方法
    	public static void main(String[] args) {
            List<String> fruits = new ArrayList<>();
            fruits.add("Banana");
            List<String> copyFruits = new ArrayList<>();
            copyFruits.addAll(fruits);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    1.4 使用 java.util.Collections.copy() 方法

      Collections 类有多种返回集合的静态方法,其中一个是 copy() 方法,它需要一个源列表和一个至少和源列表一样长的目标列表。该方法将源列表中的所有元素复制到目的列表中。复制后,源列表和目的列表中的元素的索引将是相同的。目的列表必须足够长,以容纳所有复制的元素。如果目标列表长度长于此,目标列表中的其余元素将不受影响。

    	public static void main(String[] args) {
            List<String> fruits = new ArrayList<>();
            fruits.add("Banana");
            List<String> copyFruits = new ArrayList<>();
            copyFruits.add("1");
            copyFruits.add("2");
            Collections.copy(copyFruits, fruits);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    1.5 使用 Java 8 Stream API 将 List 复制到另一个 List 中
    	public static void main(String[] args) {
            List<String> fruits = new ArrayList<>();
            fruits.add("Banana");
            List<String> copyFruits = fruits.stream().collect(Collectors.toList());
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    1.6 在 JDK 10 中的使用方式

      JDK 10 在线调试网址:https://lightly.teamcode.com/

    	public static void main(String[] args) {
            List<String> fruits = new ArrayList<>();
            fruits.add("Banana");
            List<String> copyFruits = List.copyOf(fruits);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    二、浅拷贝方法实现 List<String> 深拷贝的原因探究

      在本文中,我们已经探讨了 6 种不同的方法来将一个 List<String> 复制到另一个 List<String> 中,实现了 List<String> 的深拷贝,并附上了 Java 测试代码。
      但是在笔者的另一篇文章 《Java 如何复制 List ?》一文中,本文中提到的方法 1.1 - 1.6 都是浅拷贝方法,但是实际测试时,在拷贝 List<String> 时,却达到了深拷贝的效果,为什么?
      探究这个问题,要从 String 源码出发。String 类是不可变的类,被 “final” 关键字修饰,其类定义如下所示。

    public final class String
        implements java.io.Serializable, Comparable<String>, CharSequence {}
    
    • 1
    • 2

      对于一个 String 而言,如果修改了其值,该对象的地址会发生变化,相当于将原来的对象拷贝了一个副本,并修改了副本的值,详见 《Java 打印对象的地址》。
      在本文中,修改了原 List 对象中某索引的值之后,原 List 该节点的指向地址已经变化,但是拷贝后的 list 地址依然指向旧地址,其效果看上去就是实现了深拷贝(但本质上依然是浅拷贝),详见下述测试代码及输出。

    	public static void main(String[] args) {
            List<String> fruits = new ArrayList<>();
            fruits.add("Banana");
            fruits.add("grape");
            System.out.println(fruits);
            System.out.println(System.identityHashCode(fruits.get(0)));
            System.out.println(System.identityHashCode(fruits.get(1)));
            List<String> copyFruits = new ArrayList<>(fruits);
            System.out.println(copyFruits);
            System.out.println(System.identityHashCode(copyFruits.get(0)));
            System.out.println(System.identityHashCode(copyFruits.get(1)));
            fruits.set(0, "apple");
            System.out.println(fruits);
            System.out.println(System.identityHashCode(fruits.get(0)));
            System.out.println(System.identityHashCode(fruits.get(1)));
            System.out.println(copyFruits);
            System.out.println(System.identityHashCode(copyFruits.get(0)));
            System.out.println(System.identityHashCode(copyFruits.get(1)));
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

      上述测试代码输出:

    [Banana, grape]
    1392838282
    523429237
    [Banana, grape]
    1392838282
    523429237
    [apple, grape]
    664740647
    523429237
    [Banana, grape]
    1392838282
    523429237
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
  • 相关阅读:
    【算法面试必刷Java版十三】判断一个链表是否为回文结构
    Mesh--学习笔记
    ArcGIS Pro中的回归分析浅析(下)地理加权回归工具(GWR)使用&小结
    【2023双非保研】信管跨保计算机大类的记录(东南、川大、重大、东北、西电、南理工、杭高院、河海、东华、天大等)
    OpenCV实现“蓝线挑战“特效
    企业电子招标采购系统源码Spring Boot + Mybatis + Redis + Layui + 前后端分离 构建企业电子招采平台之立项流程图
    模型预处理层介绍(1) - Discretization
    Vue-Resource发送get-post-jsonp请求
    微软 687 亿美元收购游戏巨头动视暴雪,将成为继腾讯、索尼后的第三大游戏公司
    语法基础(数组)
  • 原文地址:https://blog.csdn.net/piaoranyuji/article/details/125485410