You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何复制ArrayList<object>以解除两列表间的关联?

如何复制ArrayList使修改B不影响A?

兄弟,你遇到的是浅拷贝的典型问题!当你用new ArrayList<>(A)初始化B的时候,其实只是把A里的对象引用复制了一份到B中——两个列表里的元素指向的是同一个内存对象。所以只要你修改B里的可变对象(比如自定义类实例),A里的对应元素自然也会跟着变。下面分情况给你解决办法:

1. 如果你的元素是不可变类型(比如String、Integer、Long)

这种情况其实用普通的浅拷贝就完全够用!因为不可变对象本身没法被修改,你最多是在B里添加/删除元素,或者替换成新的对象,这时候完全不会影响A。举个例子:

ArrayList<String> A = new ArrayList<>(Arrays.asList("a", "b", "c"));
ArrayList<String> B = new ArrayList<>(A);
B.set(0, "x"); // 替换元素,A还是["a","b","c"],完全不受影响

除了new ArrayList<>(A),你也可以用流来复制:A.stream().collect(Collectors.toList()),效果一样。

2. 如果你的元素是自定义可变类(比如自己写的User、Order类)

这时候必须做深拷贝——也就是把每个元素都复制出一个全新的对象,而不是只复制引用。这里有几种常用的实现方式:

方法一:让自定义类实现Cloneable接口,重写clone()方法

先给你的类加上克隆能力:

class User implements Cloneable {
    private String name;
    private int age;

    // 构造器、getter、setter省略

    @Override
    protected User clone() throws CloneNotSupportedException {
        // 如果类里还有其他可变对象(比如ArrayList成员),这里要递归克隆
        return (User) super.clone();
    }
}

然后复制列表的时候,逐个克隆元素:

ArrayList<User> A = new ArrayList<>();
// 假设A里已经存入了若干User对象
ArrayList<User> B = new ArrayList<>();
for (User user : A) {
    try {
        B.add(user.clone());
    } catch (CloneNotSupportedException e) {
        e.printStackTrace();
    }
}

方法二:给自定义类写拷贝构造器

在你的类里添加一个接收自身对象的构造器,专门用来复制实例:

class User {
    private String name;
    private int age;

    // 普通构造器
    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // 拷贝构造器
    public User(User other) {
        this.name = other.name; // String是不可变的,直接赋值就行
        this.age = other.age;
        // 如果有其他可变成员(比如ArrayList),也要在这里做复制
    }
}

然后用流来批量复制:

ArrayList<User> B = A.stream()
                     .map(User::new) // 用拷贝构造器创建新对象
                     .collect(Collectors.toCollection(ArrayList::new));

方法三:序列化/反序列化(适合复杂嵌套对象)

如果你的类实现了Serializable接口,可以通过序列化把整个列表转成字节流,再反序列化回来,这样得到的就是完全独立的深拷贝:

public static <T extends Serializable> ArrayList<T> deepCopy(ArrayList<T> original) {
    try {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(original);
        oos.flush();
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        return (ArrayList<T>) ois.readObject();
    } catch (IOException | ClassNotFoundException e) {
        e.printStackTrace();
        return null;
    }
}

使用时直接调用:ArrayList<User> B = deepCopy(A);

总结

核心就是区分浅拷贝和深拷贝:

  • 元素是不可变类型:浅拷贝足够,随便用new ArrayList<>(A)或者流复制
  • 元素是可变自定义类:必须做深拷贝,确保每个元素都是全新的实例

内容的提问来源于stack exchange,提问作者Atras

火山引擎 最新活动