为什么对一个ArrayList调用clear()会清空另一个ArrayList的元素?
错误原因
你遇到的问题本质是Java的引用传递机制:
- ArrayList属于引用类型,调用
result.add(list)时,不会复制list的内容存入result,仅会将list对象的内存地址(引用)存入result容器。 - 你的第二段代码全程只创建了1个ArrayList对象,result中存储的5个元素都是指向该对象的同一份引用。后续调用
list.clear()时,修改的是这个唯一对象的内容,因此result中所有引用指向的内容会同步被清空,最终输出全是空列表。 - 补充说明:result本身和list不是同一个引用,result是存储多个列表引用的外层容器,只是它内部的所有元素引用都指向了你创建的那一个list对象。
能否仅用一个ArrayList+clear实现需求
不能。你需要在result中存储5份内容不同的独立列表,本质上就需要5个独立的ArrayList对象,不可能仅靠一个对象存储多份不同的内容。
日常开发中不需要刻意避免循环内创建ArrayList,JVM对这类短期小对象的回收效率极高,新建的性能开销几乎可以忽略,提前做无意义的优化反而可能提升代码复杂度、降低性能。
如果是列表元素很多、想避免频繁扩容的场景,可以复用同一个list做内容填充,在存入result时做一次拷贝,本质还是创建了新对象,但可以复用原list的底层数组扩容结果,示例代码如下:
List<Integer> list = new ArrayList<>(); List<List<Integer>> result = new ArrayList<>(); for(int i = 1; i <= 5; ++i){ list.clear(); for(int j = 1; j <= i; ++j){ list.add(j); } // 存入时复制新对象,避免后续修改互相影响 result.add(new ArrayList<>(list)); } System.out.println(result);
ArrayList核心知识点整理
- 引用传递规则:Java中所有对象类型的赋值、传参、存入集合操作,传递的都是对象的内存地址,不是对象的内容副本。修改原对象后,所有持有该对象引用的位置都会同步感知到变化。
clear()方法的作用:仅将ArrayList底层数组的所有元素置为null,同时把size标记设为0,不会修改底层数组的内存地址,也不会生成新的对象。- 拷贝构造方法
new ArrayList<>(Collection c):会创建全新的ArrayList对象,将传入集合的元素复制到新对象的底层数组中,新对象和原集合完全独立,修改不会互相影响。 - 小对象优化:元素数量少的ArrayList创建成本极低,没有必要为了避免创建对象刻意修改逻辑,反而可能带来额外的复制开销。
内容的提问来源于stack exchange,提问作者Akshaya Amar
相关产品推荐
相关产品推荐

