Java ArrayList clone() 和深拷贝示例

培训教学 潘老师 7个月前 (10-09) 240 ℃ (0) 扫码查看

在 Java 中,ArrayList.clone() 方法创建一个列表的浅拷贝,其中只复制了对象引用。如果我们在第一个 ArrayList 中更改列表项的对象状态,那么更改后的对象状态也将反映在克隆的列表中。

为了防止两个列表都反映出更改,我们应该显式创建列表的深拷贝。

1.使用 ArrayList.clone() 创建浅拷贝

clone() 方法创建一个新的 ArrayList,然后将备份数组复制到克隆的数组中。它创建了给定 ArrayList 的浅拷贝。在浅拷贝中,原始列表和克隆列表都引用内存中的相同对象。让我们看看 clone 方法的内部实现。

public Object clone() {
    try {
        ArrayList<?> v = (ArrayList<?>) super.clone();
        v.elementData = Arrays.copyOf(elementData, size);
        v.modCount = 0;
        return v;
    } catch (CloneNotSupportedException e) {
        // this shouldn't happen, since we are Cloneable
        throw new InternalError(e);
    }
}

以下 Java 程序使用 clone() 方法创建一个 ArrayList 的浅拷贝。

ArrayList<String> arrayListObject = new ArrayList<>(List.of("A", "B", "C", "D"));
ArrayList<String> arrayListClone =  (ArrayList<String>) arrayListObject.clone();

2.创建 ArrayList 的深拷贝

创建列表的深拷贝并不直观。Java 默认不支持深拷贝,因此我们必须手动修改代码以实现类和集合的深拷贝。在列表的深拷贝中,从两个列表引用的项在内存中是不同的实例。

2.1. 启用列表项的深拷贝

要创建一个类的深拷贝,将所有类成员分为两类:可变和不可变类型。

  • 所有不可变字段成员可以直接使用,无需特殊处理,例如基本类型、包装类和 String 类。
  • 对于所有可变字段成员,我们必须创建成员的新对象并将其值分配给克隆的对象。

思路是从 clone() 方法中返回类的不可变副本。请查看以下类中的重写 clone() 方法。

public class Employee implements Cloneable {
    private Long id;
    private String name;
    private Date dob;        //Mutable field
    public Employee(Long id, String name, Date dob) {
        super();
        this.id = id;
        this.name = name;
        this.dob = dob;
    }
    //Getters and setters
    @Override
    protected Object clone() throws CloneNotSupportedException {
        Employee clone = null;
        try  {
            clone = (Employee) super.clone();
            // new date object to cloned method
            clone.setDob((Date) this.getDob().clone());
        }
        catch (CloneNotSupportedException e)  {
            throw new RuntimeException(e);
        }
        return clone;
    }
    @Override
    public String toString() {
        return "Employee [id=" + id + ", name=" + name + ", dob=" + dob + "]";
    }
}

2.2. 深拷贝 Java 集合

创建集合的深拷贝相对容易。我们需要创建集合的新实例,并将给定集合中的所有元素逐个复制到克隆的集合中。注意,我们将元素的克隆复制到克隆的集合中。

ArrayList<Employee> employeeList = new ArrayList<>();
ArrayList<Employee> employeeListClone = new ArrayList<>();
Collections.copy(employeeList, employeeListClone);

2.3. 示例

Java 程序创建 ArrayList 的深拷贝。

ArrayList<Employee> employeeList = new ArrayList<>();
employeeList.add(new Employee(1l, "adam", new Date(1982, 02, 12)));
ArrayList<Employee> employeeListClone = new ArrayList<>();
Collections.copy(employeeList, employeeListClone);
//Modify the list item in cloned list - it should affect the original list item
employeeListClone.get(0).setId(2l);
employeeListClone.get(0).setName("brian");
employeeListClone.get(0).getDob().setDate(13);;
System.out.println(employeeList);
System.out.println(employeeListClone);

请注意,即使在更改 employeeListClone 中的 Employee 对象的值后,原始的 employeeList 也没有发生更改。

[Employee [id=1, name=adam, dob=Sun Mar 12 00:00:00 IST 3882]]
[Employee [id=2, name=brian, dob=Mon Mar 13 00:00:00 IST 3882]]

以上就是Java ArrayList clone() 和深拷贝示例的全部内容。


版权声明:本站文章,如无说明,均为本站原创,转载请注明文章来源。如有侵权,请联系博主删除。
本文链接:https://www.panziye.com/teach/9377.html
喜欢 (0)
请潘老师喝杯Coffee吧!】
分享 (0)
用户头像
发表我的评论
取消评论
表情 贴图 签到 代码

Hi,您需要填写昵称和邮箱!

  • 昵称【必填】
  • 邮箱【必填】
  • 网址【可选】