Java深浅拷贝与clone()方法疑问:ArrayList克隆后修改不影响原列表?
深浅拷贝与Java ArrayList.clone() 解析
一、先搞懂深浅拷贝的核心区别
- 浅拷贝:生成新对象,但对象内部的引用类型成员仍指向原对象的引用。简单说,新对象和原对象共享所有引用类型的子对象,修改子对象的内部状态会互相影响。
- 深拷贝:生成新对象,同时递归复制所有引用类型的子对象,新对象和原对象完全独立,修改任何一方都不会影响另一方。
二、Java中.clone()的工作逻辑
Java的Object.clone()默认实现是浅拷贝,但具体行为完全取决于子类是否重写了clone()方法:
- 如果子类没重写,直接用Object的clone,就是浅拷贝;
- 如果子类重写时自己实现了深拷贝逻辑(比如递归复制所有引用成员),那它的clone就是深拷贝。
这就是为什么你看到不同资料说法不一的原因——不同类的clone()实现不一样。
三、你的ArrayList代码为什么会有这样的输出?
ArrayList的clone()方法是浅拷贝,但你用的是Integer这种不可变类型,这是关键:
- ArrayList.clone()的本质:创建一个新的ArrayList对象,把原列表里的元素引用直接复制到新列表的元素数组中。也就是说,新列表和原列表的元素数组是两个不同的数组,但数组里的元素引用指向同一个对象。
- 但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
相关产品推荐
相关产品推荐

