arraylist.sublist()返回原列表的共享视图而非副本,修改子列表会直接影响原列表,原列表结构性修改会使子列表抛concurrentmodificationexception。

Java 中 ArrayList.subList(int fromIndex, int toIndex) 返回的是原列表的一个视图(view),不是独立副本。这意味着对子列表的操作会直接影响原列表,反之亦然——这是最关键的注意事项。
subList 返回的是“共享底层数组”的视图
调用 subList 不会创建新 ArrayList 或复制元素,而是返回一个内部的 SubList 对象(继承自 AbstractList),它持有一个指向原 ArrayList 的引用,并记录起始/结束索引。
因此:
- 修改子列表中的元素(如
set(i, x))等价于修改原列表对应位置的元素; - 在子列表上执行
add()或remove(),会直接改变原列表的结构(长度、元素顺序); - 原列表的结构性修改(如
add()、remove()、clear())会使已存在的子列表抛出ConcurrentModificationException(即使单线程)。
常见误操作及后果示例
以下代码看似安全,实则危险:
// ❌ 错误:原列表后续修改导致子列表失效
ArrayList<string> list = new ArrayList(Arrays.asList("a", "b", "c", "d"));
List<string> sub = list.subList(1, 3); // ["b", "c"]
list.add("e"); // 结构性修改
System.out.println(sub.get(0)); // 运行时抛出 ConcurrentModificationException</string></string>
再比如:
// ❌ 错误:向子列表添加元素,实际改了原列表
List<string> sub = list.subList(1, 3);
sub.add("x"); // 相当于在原 list 索引 3 处插入 "x"
System.out.println(list); // [a, b, c, x, d] —— 原列表已变</string>
安全使用 subList 的正确姿势
若需要真正独立的子列表副本,请显式构造新 ArrayList:
-
读多写少场景:直接用
subList视图,节省内存和时间; -
需要独立修改:包装成新列表:
new ArrayList(list.subList(from, to)); -
避免并发结构修改:确保在子列表生命周期内,原列表不发生
add、remove、clear、retainAll等结构性操作; -
注意边界:
fromIndex必须 ≥ 0,toIndex≤ 原列表 size,且fromIndex ≤ toIndex,否则抛IndexOutOfBoundsException。
subList 的典型合理用途
它最适合用于临时切片、只读遍历、配合 Collections 工具方法等轻量场景:
- 排序某一段:
Collections.sort(list.subList(2, 5)); - 批量设置值:
subList.replaceAll(x -> x.toUpperCase()); - 作为参数传递给只读处理逻辑(明确约定不修改结构)。
不复杂但容易忽略细节。理解“视图”本质,就能避开大多数陷阱。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











