简单说一下ArrayList的add机制,适合应试者表达的 文章目录第一步核心流程概述高浓度总结第二步细节拆解体现源码功底第三步性能与变种延伸拉开差距的加分项 答题锦囊面试官可能顺藤摸瓜的追问面试官问到ArrayList的add机制千万不要一上来就背源码而是要像讲故事一样把“正常放入 - 空间不足 - 扩容 - 搬家”的整个流程逻辑清晰地连贯起来。建议采用以下“标准三步走”的逻辑来回答既能精准命中考点又显得条理清晰。第一步核心流程概述高浓度总结话术“ArrayList的add()机制核心可以分为四个步骤检查容量、触发扩容可选、尾部插入、返回成功。简单来说每当我们调用add(E e)时它会先判断当前内部数组的剩余空间是否还装得下一个元素。如果够就直接挂在尾部如果不够就会先触发动态扩容然后再把元素放进去。”第二步细节拆解体现源码功底这里你需要把首次添加和后续扩容的细节抛出来这是面试官最想听到的懒加载延迟初始化如果我们用无参构造函数new ArrayList()为了节省内存此时底层其实是一个长度为 0 的空数组。只有在第一次调用add()时它才会真正分配内存直接初始化一个容量为10的数组。计算最小所需容量每次add时它的内部计数器size会加 1。JVM 会拿size 1作为“最小所需容量”去和当前数组的长度做对比。1.5 倍扩容如果size 1大于了数组长度就会调用grow()方法进行扩容。新数组的容量会变成原数组的1.5 倍。内存拷贝扩容时会通过Arrays.copyOf()底层是System.arraycopy在内存中开辟一块新的连续空间把老数据原封不动地“搬家”过去。第三步性能与变种延伸拉开差距的加分项主动聊一聊性能和add(index, element)能让面试官觉得你对数据结构有深度思考话术“除了最常用的尾部插入ArrayList还有一个重载的指定位置插入方法add(int index, E element)。它们的性能损耗是有很大区别的尾部插入在不触发扩容的情况下时间复杂度是O ( 1 ) O(1)O(1)效率极高。指定位置插入由于数组内存是连续的为了在中间腾出位置需要把目标位置后面的所有元素都往后挪动一位O ( n ) O(n)O(n)复杂度因此越往前面插入性能代价就越大。所以在实际开发中如果需要频繁在头部或中间插入元素我会优先考虑使用LinkedList。” 答题锦囊面试官可能顺藤摸瓜的追问ArrayList 是线程安全的吗不是。它的add()方法里包含多步操作如elementData[size] e实际上是先赋值再自增且没有加锁多线程并发add会导致数据覆盖或ArrayIndexOutOfBoundsException数组越界异常。怎么让它线程安全可以使用Collections.synchronizedList()包装或者在读多写少的高并发场景下使用CopyOnWriteArrayList。