数组长度固定且支持基本类型,ArrayList可自动扩容但仅存对象;数组功能简陋需手动实现操作,ArrayList提供丰富方法并集成集合框架;两者随机访问均为O(1),但适用场景不同。

数组长度固定,ArrayList能自动扩容
Java里数组一旦用 new int[5] 创建,长度就锁死了。想加第6个元素?直接抛 ArrayIndexOutOfBoundsException。你得手动写逻辑:新建更大数组、用 Arrays.copyOf() 搬数据、再赋值——三步缺一不可。
而 ArrayList 调 add() 时完全不用操心容量。它默认初始容量是10,满后自动按1.5倍扩容(比如从10→15→22)。但注意:扩容本身是O(n)操作,频繁在循环里 add() 会反复复制数组,拖慢性能。
- 别在 for 循环里边遍历边
add(),容易触发多次扩容 - 如果已知最终大小(比如读取1000行文件),初始化时指定容量:
new ArrayList(1000) - 数组扩容必须自己实现;
ArrayList把这事封装了,但也藏了隐性开销
数组支持基本类型,ArrayList只能存对象
你可以写 int[] nums = {1, 2, 3},内存里就是三个连续的4字节整数。但 ArrayList 是非法的——泛型不接受基本类型。你只能写 ArrayList,这时每个 int 都会被自动装箱成 Integer 对象,存在堆上,还带对象头开销。
这意味着:高频数值计算(如矩阵运算、大量计数)用数组更快更省内存;而业务逻辑中处理“用户列表”“订单集合”这类天然是对象的概念,ArrayList 更自然。
立即学习“Java免费学习笔记(深入)”;
- 循环中反复读写
ArrayList会触发拆箱,有额外开销.get(i) - 用
int[]存百万级数字,内存占用约为ArrayList的 1/3~1/2 - 没有
ArrayList,这是Java泛型擦除导致的硬限制,不是语法疏漏
数组只有 length,ArrayList有一整套操作方法
数组除了 arr.length 和方括号索引(arr[i]),啥都没有。你要删一个元素?得自己挪后面所有值;要查某值是否存在?得手写遍历;要合并两个数组?得调 System.arraycopy() 或 Arrays.copyOf()。
ArrayList 直接提供 add()、remove(int index)、contains()、indexOf()、addAll()、removeIf() 等十几种方法。它实现了 List 接口,能无缝接入整个集合框架。
-
array.length是字段,list.size()是方法——别写成list.length,编译报错 -
remove(Object o)和remove(int index)同名重载,传int字面量(如remove(0))会删索引0,不是删值为0的元素 - 数组转
ArrayList别直接用Arrays.asList(arr)——它返回的是固定大小的List,add()会抛UnsupportedOperationException
访问速度几乎一样,但底层机制不同
两者通过索引访问都是 O(1):数组靠内存偏移直接取;ArrayList 底层也是数组(Object[] elementData),只是多了一次边界检查和一次引用解引用。实测差异通常在几纳秒内,日常开发可忽略。
真正影响性能的不是访问,而是场景错配:用 ArrayList 存十万 int 做累加,比用 int[] 慢2~3倍;反过来,用数组实现一个购物车功能,增删商品就得自己维护索引、搬数据、处理越界——代码复杂度飙升,且极易出错。
-
ArrayList.get(i)内部仍是elementData[i],没额外跳转 - 多线程环境下,两者都不安全:数组没同步逻辑,
ArrayList也不是线程安全的,需用Collections.synchronizedList()或CopyOnWriteArrayList - 数组是语言级结构,
ArrayList是类库级抽象——前者轻量可控,后者功能丰富但多了层封装
最常被忽略的一点:数组能声明并初始化多维(int[][] matrix = new int[3][3]),而 ArrayList 只有一维。你要“列表的列表”,得写 ArrayList,不仅啰嗦,空指针风险也更高。










