集合支持动态扩容与丰富操作接口,数组长度固定且无内置方法;ArrayList自动扩容、HashSet查值平均O(1),而Arrays.asList和List.of返回不可变视图,误调add/remove会抛异常。

集合能动态扩容,数组必须手动搬数据
数组创建后 length 就锁死了,想加一个元素?得 new 一个更大的数组,再用 System.arraycopy() 把老数据拷过去——这不仅写起来啰嗦,还容易漏掉边界判断或引用丢失。而 ArrayList 调用 add() 时自动触发扩容(Java 17+ 是按 oldCapacity + (oldCapacity >> 1) 增长),HashMap 插入超阈值后也自动翻倍扩容并重哈希。
- 常见错误:用
Arrays.asList(arr)返回的列表调add()或remove()→ 抛UnsupportedOperationException(它只是数组的包装视图,非真正可变集合) - 实操建议:预估数据量时,显式传初始容量,比如
new ArrayList(1024),避免前几次add()频繁复制数组 - 注意:
List.of(1,2,3)是不可变集合,底层仍是固定数组,试图修改会直接抛异常
集合提供丰富操作接口,数组只能靠手写或工具类
数组没有内置的 contains()、removeIf()、sort() 或流式处理能力;要查某个值是否存在,你得写循环或调 Arrays.stream(arr).anyMatch(...) ——性能差还冗长。而集合天然支持这些:
-
ArrayList.contains(x)是 O(n),但HashSet.contains(x)是平均 O(1) list.removeIf(x -> x 一行删负数,数组做不到-
map.merge(key, 1, Integer::sum)累计频次,数组没键值抽象层 - 陷阱:基本类型数组(如
int[])无法直接转成List,Arrays.asList(intArr)会把整个数组当一个元素(返回List)
集合统一操作契约,数组类型耦合太深
数组类型声明即绑定死:String[]、double[]、MyObj[] 各自为政,没法用同一套逻辑泛化处理;而所有 Collection 子类都实现 size()、isEmpty()、iterator(),配合泛型还能静态检查类型安全。
- 典型场景:写一个通用统计方法,参数用
Collection extends Number>就能同时接收ArrayList、HashSet,但没法接受int[]或double[] - 代价:集合只能存对象,基本类型会自动装箱(
int → Integer),高频增删易引发 GC 压力;真要极致性能且数据量大,别硬套集合,该用int[]还是得用 - 兼容提示:Java 10+ 的
var list = new ArrayList可省略左侧泛型,但数组仍必须写全(); String[] arr
什么时候坚持用数组反而更合理
别迷信“集合更高级”,以下情况数组才是更稳、更快、更省的选择:
立即学习“Java免费学习笔记(深入)”;
- 存储大量基本类型数值(如图像像素、科学计算向量)→ 避免百万级
Integer对象堆内存开销 - 作为底层容器被反复读写(如游戏帧缓冲、实时音视频采样)→ 数组连续内存 + 无方法调用开销,访问延迟稳定
- 与 JNI/C 交互(如
ByteBuffer.array())→ JVM 直接暴露原始内存地址,集合无法穿透 - 关键路径中对 GC 敏感(如金融交易撮合引擎)→ 数组不产生中间对象,规避 STW 风险
真正难的不是选集合还是数组,而是意识到:集合封装的是「行为抽象」,数组暴露的是「内存事实」。用错一层,后面十层优化都白搭。







