Java的List的Clone竟然是浅拷贝
1. List克隆返回的是浅拷贝的集合
前一段时间,代码中用到了Clone,Java中自定义对象默认的Clone是浅拷贝,所以重写了自定义对象的clone方法,实现了深拷贝。没想到还有一个坑,ArrayList的Clone竟然也是浅拷贝,集合本来想当然的认为一定是深拷贝。
复现
写个小例子来复现下,下面是集合中存放的对象User,实现了Cloneable接口,并实现了深拷贝:
``` static class UserName implements Cloneable { public String fname; public String lname; public UserName(String fname, String lname) { this.fname = fname; this.lname = lname; } @Override protected UserName clone() throws CloneNotSupportedException { return (UserName) super.clone(); } }
static class User implements Cloneable { public UserName userName; public User(UserName name) { this.userName = name; } @Override protected User clone() throws CloneNotSupportedException { User user = (User) super.clone(); user.userName = userName.clone(); return user; } } ```
当我们克隆集合的时候:
private static void wrongListClone() { //初始化集合元素<小白> ArrayList<User> users = new ArrayList<>(); User user = new User(new UserName("小", "白")); users.add(user); //先克隆,然后改变原对象的值为<小黑>,输出发现克隆对象也跟着变为<小黑> List<User> usersClone = (ArrayList<User>) users.clone(); user.userName.lname = "黑"; usersClone.forEach(u -> System.out.println(u.userName.fname + u.userName.lname)); }
执行后输出<小黑>,说明克隆集合对象和原集合指向的是同一个对象。
小黑
2. 解决方案
需要自己实现集合的Clone,新建立一个集合,遍历源集合生成每个对象的Clone,放入新集合。
``` private static ArrayList cloneUsers(ArrayList users) throws CloneNotSupportedException { ArrayList cloneList = new ArrayList<>(); for (User u : users) { cloneList.add(u.clone()); } return cloneList; }
private static void rightListClone() throws CloneNotSupportedException { //初始化集合元素<小白> ArrayList users = new ArrayList<>(); User user = new User(new UserName("小", "白")); users.add(user); //先克隆,然后改变原对象的值为<小黑>,输出克隆对象依然为<小白> List usersClone = cloneUsers(users); user.userName.lname = "黑"; usersClone.forEach(u -> System.out.println(u.userName.fname + u.userName.lname)); } ```
执行后输出<小白>,说明克隆集合对象和原集合指向的是不同的对象,克隆功能正常。
小白
3. 可执行完整示例代码
``` import java.util.ArrayList; import java.util.List;
/** * Created by qryc on 2021/11/10 */ public class CloneDemo { public static void main(String[] args) throws Exception { wrongListClone(); rightListClone(); }
static class UserName implements Cloneable {
public String fname;
public String lname;
public UserName(String fname, String lname) {
this.fname = fname;
this.lname = lname;
}
@Override
protected UserName clone() throws CloneNotSupportedException {
return (UserName) super.clone();
}
}
static class User implements Cloneable {
public UserName userName;
public User(UserName name) {
this.userName = name;
}
@Override
protected User clone() throws CloneNotSupportedException {
User user = (User) super.clone();
user.userName = userName.clone();
return user;
}
}
private static void wrongListClone() {
//初始化集合元素<小白>
ArrayList<User> users = new ArrayList<>();
User user = new User(new UserName("小", "白"));
users.add(user);
//先克隆,然后改变原对象的值为<小黑>,输出发现克隆对象也跟着变为<小黑>
List<User> usersClone = (ArrayList<User>) users.clone();
user.userName.lname = "黑";
usersClone.forEach(u -> System.out.println(u.userName.fname + u.userName.lname));
}
private static ArrayList<User> cloneUsers(ArrayList<User> users) throws CloneNotSupportedException {
ArrayList<User> cloneList = new ArrayList<>();
for (User u : users) {
cloneList.add(u.clone());
}
return cloneList;
}
private static void rightListClone() throws CloneNotSupportedException {
//初始化集合元素<小白>
ArrayList<User> users = new ArrayList<>();
User user = new User(new UserName("小", "白"));
users.add(user);
//先克隆,然后改变原对象的值为<小黑>,输出克隆对象依然为<小白>
List<User> usersClone = cloneUsers(users);
user.userName.lname = "黑";
usersClone.forEach(u -> System.out.println(u.userName.fname + u.userName.lname));
}
}
```