Java集合“坑王”:ArrayList为啥越界还能浪?

提起ArrayList,新手总觉得它就是个"自动扩容的数组",随便add、get都不怕------直到遇到 IndexOutOfBoundsException ,才发现这货藏着不少小心机。今天咱扒一扒ArrayList的扩容黑科技,以及那些让你踩坑的细节!

一、先搞懂:ArrayList为啥能"自动变长"?

ArrayList底层是普通数组,默认初始容量是10。当添加元素导致数组满了,它会悄悄扩容:新容量=旧容量×1.5(源码里是 oldCapacity + (oldCapacity >> 1) ),然后把旧数组的数据复制到新数组。

看个简单例子,直观感受扩容:

java 复制代码
import java.util.ArrayList;

public class ArrayListDemo {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>(); // 初始容量10
        
        // 加10个元素,刚好填满初始数组
        for (int i = 0; i < 10; i++) {
            list.add("元素" + i);
        }
        
        // 第11个元素:触发扩容!新容量变成15
        list.add("触发扩容的元素");
        
        System.out.println("当前元素数量:" + list.size()); // 输出11
        System.out.println("能存但未用的容量:" + (list.size() < 15 ? 15 - list.size() : "已再次扩容")); // 输出4
    }
}

二、踩坑重灾区:size和capacity别搞混!

很多人以为 list.size() 是数组容量,其实大错特错:

  • size() :实际存储的元素数量(你add了多少个)
  • capacity :底层数组的长度(ArrayList内部用 elementData 数组,容量不对外暴露)

这就是为啥 get(10) 会报错------哪怕数组容量是15,只要你只存了11个元素,索引10是有效的,但索引11就越界:

java 复制代码
public static void main(String[] args) {
    ArrayList<String> list = new ArrayList<>();
    for (int i = 0; i < 11; i++) {
        list.add("元素" + i);
    }
    
    System.out.println(list.get(10)); // 正常输出:元素10
    list.get(11); // 直接抛IndexOutOfBoundsException!
}

三、实用技巧:提前指定容量,避免频繁扩容

如果知道要存多少元素,初始化时直接指定容量,能减少数组复制的性能损耗:

java 复制代码
// 已知要存1000个元素,直接指定容量
ArrayList<String> list = new ArrayList<>(1000);
// 后续add1000个元素,一次扩容都不会触发

最后划重点

  1. ArrayList扩容是"偷偷摸摸"的,扩容后旧数组会被GC回收;

  2. 越界异常看的是 size() ,不是底层数组容量;

  3. 大数据量场景一定要指定初始容量,优化性能。

相关推荐
z1234567898614 分钟前
2026最新两款AI编程工具深度对比实测
java·数据库·ai编程
GIS阵地22 分钟前
QgsSingleBandPseudoColorRenderer 完整详解(QGIS 3.40.13 C++)
开发语言·前端·c++·qt·qgis
刘较瘦_42 分钟前
AI 开发中的 Git Submodule 父子仓库模式:前后端分仓管理与协作实践
前端·github
yaoxin5211231 小时前
470. Java 反射 - Member 接口与 AccessFlag
java·开发语言·python
牧艺1 小时前
cos-design WeatherBackground:用 Canvas 做一个「会变天」的背景引擎
前端·canvas·视觉设计
OpenTiny社区1 小时前
深度解析 LSP 如何为 AI 装上“眼睛”
前端·ai编程
做个文艺程序员1 小时前
Linux第24篇:Java应用监控体系搭建:Prometheus+Grafana可视化运维
java·grafana·prometheus
布列瑟农的星空1 小时前
流程类SVG画布的通用开发范式
前端
fsssb1 小时前
Chromium 源码学习笔记(七):那些跨进程的调用,底下都是同一个东西——Mojo
前端
MichaelJohn2 小时前
从零星白屏到“启发式缓存”,记录一次刚接手屎山的惊险排查
前端