• 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
  • 相关阅读:
    浅谈跨域安全
    开源安全的危机在于太相信 GitHub?——专访Apache之父&OpenSSF基金会总经理Brain Behlendorf...
    Unicorn 嵌入Android系统
    火热报名中 | 2天峰会、20+热门议题,AutoESG 2023数智低碳---中国汽车碳管理创新峰会亮点抢先看!
    4. SQL语法中的一些基本概念
    2023年【司钻(钻井)】及司钻(钻井)作业模拟考试
    C语言 || volatile
    2023考研需要考研人认真关注的4个考研常识
    【攻破css系列——第七天】属性值的计算
    数据库的级联删除
  • 原文地址:https://blog.csdn.net/piaoranyuji/article/details/125485410