You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java深浅拷贝与clone()方法疑问:ArrayList克隆后修改不影响原列表?

深浅拷贝与Java ArrayList.clone() 解析

一、先搞懂深浅拷贝的核心区别

  • 浅拷贝:生成新对象,但对象内部的引用类型成员仍指向原对象的引用。简单说,新对象和原对象共享所有引用类型的子对象,修改子对象的内部状态会互相影响。
  • 深拷贝:生成新对象,同时递归复制所有引用类型的子对象,新对象和原对象完全独立,修改任何一方都不会影响另一方。

二、Java中.clone()的工作逻辑

Java的Object.clone()默认实现是浅拷贝,但具体行为完全取决于子类是否重写了clone()方法:

  • 如果子类没重写,直接用Object的clone,就是浅拷贝;
  • 如果子类重写时自己实现了深拷贝逻辑(比如递归复制所有引用成员),那它的clone就是深拷贝。
    这就是为什么你看到不同资料说法不一的原因——不同类的clone()实现不一样。

三、你的ArrayList代码为什么会有这样的输出?

ArrayList的clone()方法是浅拷贝,但你用的是Integer这种不可变类型,这是关键:

  1. ArrayList.clone()的本质:创建一个新的ArrayList对象,把原列表里的元素引用直接复制到新列表的元素数组中。也就是说,新列表和原列表的元素数组是两个不同的数组,但数组里的元素引用指向同一个对象。
  2. 但Integer是不可变类:当你调用list2.set(3, 287)时,并不是修改原来的Integer对象(值为23的那个),而是把list2的元素数组第3位的引用,换成了一个全新的Integer对象(值为287)。原列表的元素数组第3位还是指向原来的Integer(23),所以两者互不影响,输出自然是287和23。

换个可变类型试试,你就能看到浅拷贝的真实效果

如果用自定义的可变类替换Integer,代码如下:

class MyData {
    int value;
    MyData(int v) { this.value = v; }
}

public class Kopie {
    public static void main(String[] args) {
        ArrayList<MyData> list = new ArrayList<>();
        list.add(new MyData(23));
        
        ArrayList<MyData> list2 = (ArrayList<MyData>)list.clone();
        list2.get(0).value = 287; // 修改子对象的内部值
        
        System.out.println(list2.get(0).value); // 输出287
        System.out.println(list.get(0).value);  // 也输出287,这才是浅拷贝的体现
    }
}

这时候因为list和list2的元素指向同一个MyData对象,修改内部值会同时影响两个列表。

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 06:33:13