返回

Java ArrayList 复制:复制对象还是指向同一个对象?

java

Java ArrayList 复制:理解指向相同对象还是副本

简介

在 Java 中,当我们使用赋值运算符(=)时,它将一个对象的引用(指针)从一个变量复制到另一个变量。这适用于简单类型(例如 int、double、boolean)和引用类型(例如 ArrayList、String、Object)。对于引用类型,赋值操作仅复制引用(指针),而不是复制对象本身。这意味着原始对象和副本引用指向同一个对象。任何对副本所做的更改也会反映在原始对象上。

问题:l1 和 l2 指向相同对象还是副本?

List<Integer> l1 = new ArrayList<Integer>();
for (int i = 1; i <= 10; i++) {
    l1.add(i);
}

List l2 = l1;
l2.clear();

在上面的示例中,l1 是一个 ArrayList 对象,其中包含从 1 到 10 的数字。l2 被赋予对 l1 的引用。现在,l1l2 都引用同一个 ArrayList 对象。调用 l2.clear() 会清空 l1l2 引用的 ArrayList 对象,因为它们指向同一个对象。

避免修改原始对象

要避免修改原始对象,你可以创建一个该对象的副本。对于 ArrayList,你可以使用以下方法之一:

  • 使用 ArrayList 构造函数创建副本: List<Integer> l2 = new ArrayList<>(l1);
  • 使用 Collections.copy() 方法: List<Integer> l2 = new ArrayList<>(); Collections.copy(l2, l1);
  • 使用流和 Collectors.toList() 方法: List<Integer> l2 = l1.stream().collect(Collectors.toList());

通过使用这些方法,你可以创建一个 ArrayList 的新副本,该副本与原始 ArrayList 独立。对副本所做的任何更改都不会影响原始对象。

使用 Stream 复制的优势

使用流来复制 ArrayList 有以下优点:

  • 可读性: 流表达式更易于阅读和理解。
  • 可定制: 你可以使用流进行过滤、映射和其他转换,以创建你需要的特定副本。
  • 效率: 流操作是惰性的,这意味着它们仅在需要时才执行。这在处理大型集合时可以提高效率。

结论

了解 Java 中 ArrayList 复制的行为对于避免意外修改原始对象至关重要。通过使用创建副本的方法,你可以确保对副本所做的更改不会影响原始对象。使用流来复制 ArrayList 提供了额外的优势,包括可读性、可定制性和效率。

常见问题解答

  1. 如何检查两个 ArrayList 是否指向同一个对象?
    • 您可以使用 == 运算符比较两个 ArrayList 的引用。如果引用相同,则它们指向同一个对象。
  2. 为什么避免修改原始对象很重要?
    • 修改原始对象可能会产生意外的后果,特别是当多个变量引用同一个对象时。
  3. 何时应该创建一个副本而不是修改原始对象?
    • 当您想要对对象进行更改但不想影响原始对象时,就应该创建一个副本。
  4. 有哪些其他方法可以避免修改原始对象?
    • 除了创建副本之外,你还可以使用不可变集合,例如 Collections.unmodifiableList().
  5. 在哪些情况下使用流来复制 ArrayList 更合适?
    • 当您需要对 ArrayList 进行过滤、映射或其他转换时,使用流来复制 ArrayList 更合适。