ArrayList默认容量为10是OpenJDK权衡内存与扩容开销的设定;扩容按1.5倍增长,频繁add小量元素会触发多次复制,预设容量可避免;扩容非线程安全;LinkedList随机访问O(n)远慢于ArrayList的O(1),仅首尾操作占优。
Java 中 ArrayList 初始化时不指定容量,底层 Object[] 数组默认长度为 10。这不是硬编码魔法值,而是 OpenJDK 源码里写死的 DEFAULT_CAPACITY = 10,权衡了内存占用与首次扩容开销。
扩容发生在 add() 时发现数组已满:新容量 = 旧容量 × 1.5(即 oldCapacity + (oldCapacity >> 1)),然后调用 Arrays.copyOf() 复制整个数组。这意味着:
ArrayList(1000) 可避免所有扩容ArrayIndexOutOfBoundsException
LinkedList 是双向链表实现,get(int index) 必须从头或尾遍历节点,时间复杂度 O(n),而 ArrayList 是数组,get() 是 O(1)。实测在 10 万元素下,LinkedList.get(50000) 比 ArrayList.get(50000) 慢 30 倍以上。
真正适合 LinkedList 的场景只有:addFirst()、addLast()、removeFirst()、removeLast() 这四类操作(O(1))。其他情况要注意:
add(int index, E element) 需先遍历到位置,再插入节点 —— 比 ArrayList 的同名方法更慢ArrayList 高约 40%Vector 的方法(如 add()、get())全部加了 synchronized,锁的是整个对象实例。这导致:
get())也要竞争同一把锁,吞吐量远低于无锁的 ArrayList
Vector 的单个方法同步无法保证原子性Collections.synchronizedList(new ArrayList()) 或更优的 CopyOnWriteArrayList(适用于读多写少)现代代码几乎见不到 Vector,除非维护 20 年前的遗留系统。
subList(int fromIndex, int toIndex) 不创建新集合,而是返回一个内部 SubList 视图,底层仍指向原 ArrayList 的同一数组。这意味着:
subList 调用 set()、remove()、add(),会直接修改原列表内容clear() 或扩容)会导致 subList 抛 ConcurrentModificationException
new ArrayList(list.subList(0, 5))
这个“视图非副本”的特性极易被忽略,尤其在多线程或嵌套调用中传参时,容易引发隐蔽的数据污染。