数组长度固定且类型协变,集合可动态扩容、支持泛型编译期检查;集合提供丰富语义化操作但有对象开销,数组更适合高性能底层场景。

集合能动态扩容,数组长度固定
数组在创建时就必须指定 length,之后无法改变;而 ArrayList、LinkedList 等集合内部通过扩容机制(如 Arrays.copyOf())自动处理容量增长。这意味着你不需要预估数据量——插入超限时不会抛 ArrayIndexOutOfBoundsException,而是悄悄复制并扩大底层数组。
但要注意:频繁扩容有代价。ArrayList 默认扩容 1.5 倍,每次扩容都涉及内存分配和元素拷贝;如果已知大概规模,建议构造时传入初始容量:
new ArrayList(1024);
集合支持泛型,数组类型检查更晚
Java 数组是协变的(String[] 是 Object[] 的子类型),导致运行时才暴露类型问题:
Object[] arr = new String[1];而泛型集合在编译期就拦截:
arr[0] = new Integer(1); // 运行时报 java.lang.ArrayStoreException
ArrayList这大幅降低list = new ArrayList<>();
list.add(123); // 编译错误:incompatible types
ClassCastException 出现在生产环境的概率。
不过泛型有类型擦除,运行时无法获取 E 的真实类型;而数组保留组件类型信息,可用 arr.getClass().getComponentType() 获取。
立即学习“Java免费学习笔记(深入)”;
集合提供丰富操作接口,数组依赖工具类或手写循环
对常见需求,集合直接封装了语义化方法:list.removeIf(x -> x.startsWith("tmp"))、set.contains(obj)、map.computeIfAbsent(key, k -> new HashSet());而数组只能靠 Arrays.asList(arr).removeIf(...) 包一层,或者手动遍历 + 标记 + 复制——不仅啰嗦,还容易出边界错或并发修改异常。
关键差异点:
-
ArrayList.indexOf()是 O(n) 查找,和手写循环等价;但HashSet.contains()平均 O(1),远快于遍历数组 -
Arrays.sort()只支持基本类型或Comparable,而Collections.sort(list, comparator)支持任意比较逻辑 - 没有内置「数组去重」方法,但
new LinkedHashSet(list)一行搞定且保持顺序
数组更适合高性能/底层场景,集合有对象开销
如果你在写高频数值计算、网络协议解析或 GC 敏感模块,原始数组仍是首选:int[] 直接存值,无装箱/拆箱、无对象头、无引用间接寻址;而 ArrayList 存的是堆上 Integer 对象引用,内存占用大、访问慢、还触发 GC。
这种差距在百万级数据下非常明显:
- 存一千万个整数:
int[10_000_000]占约 38MB;ArrayList轻松破 200MB - 连续访问性能:原始数组可被 JVM 做栈上分配、循环展开甚至向量化;集合迭代器多一层虚方法调用和边界检查
-
byte[]可直接用于ByteBuffer、FileChannel,集合必须转成数组才能对接底层 API
真正需要权衡的不是“该不该用集合”,而是“这个场景是否值得为抽象性牺牲控制力和效率”。比如 DTO 层用 List 没问题,但游戏引擎的顶点缓冲区必须用 float[]。









