对于 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 利用构造器,使用 List 实现类的构造方法

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

	public static void main(String[] args) {
        List<String> fruits = new ArrayList<>();
        fruits.add("Banana");
        List<String> copyFruits = new ArrayList<>(fruits);
    }
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.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.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.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);
    }
二、浅拷贝方法实现 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 {}

  对于一个 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)));
    }

  上述测试代码输出:

[Banana, grape]
1392838282
523429237
[Banana, grape]
1392838282
523429237
[apple, grape]
664740647
523429237
[Banana, grape]
1392838282
523429237
Logo

科技之力与好奇之心,共建有温度的智能世界

更多推荐