文
章
目
录
章
目
录
在 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() 和深拷贝示例的全部内容。