在 Java 中,ArrayList 内部是通过一个数组来存储元素的,是一个数组结构的存储容器。当向一个 ArrayList 中添加元素时,如果当前数组已经满了,就需要扩容。 

       

java 中Arraylist 大小增长方式 java arraylist扩容机制_数据

java 中Arraylist 大小增长方式 java arraylist扩容机制_ci_02

集合的继承关系图 

一、面试回答

( ArrayList 的扩容机制原理 ) 

        面试官好,ArrayList 是一个数组结构的存储容器,默认情况下,设置数组长度是 10. 当然我们也可以在构建 ArrayList 对象的时候自己指定初始长度。 随着在程序里面不断的往 ArrayList 中添加数据,当添加的数据达到 10 个的时候, ArrayList 就没有多余容量可以存储后续的数据。 这个时候 ArrayList 会自动触发扩容。 扩容的具体流程很简单, 1. 首先,创建一个新的数组,这个新数组的长度是原来数组长度的 1.5 倍。 2. 然后使用 Arrays.copyOf 方法把老数组里面的数据拷贝到新的数组里面。 扩容完成后再把当前要添加的元素加入到新的数组里面,从而完成动态扩容的过程。 以上就是我对这个我对这个问题的理解! 

或者不直接问: ArrayList 扩容是在第10个元素还是第11个元素触发的 ?

        在 Java 中,ArrayList 的扩容是在添加第11个元素时触发的,当 ArrayList 中的元素数量达到了其初始容量(默认为 10)时,ArrayList 会自动扩容,新的容量为原来的 1.5 倍。当然也可以在创建 ArrayList 对象时指定其初始容量,以避免频繁的扩容操作。

二、源码理解(Debug模式)

import java.util.ArrayList;
@SuppressWarnings({"all"})
public class ArrayListSource {

    public static void main(String[] args) {

        //解读源码
        //注意,注意,注意,Idea 默认情况下,Debug 显示的数据是简化后的,如果希望看到完整的数据
        //需要做设置. //使用无参构造器创建 ArrayList 对象
        ArrayList list = new ArrayList();
//        ArrayList list = new ArrayList(8);
        //使用 for 给 list 集合添加 1-10 数据
        for (int i = 1; i <= 10; i++) {
            list.add(i);
        }
        //使用 for 给 list 集合添加 11-15 数据
        for (int i = 11; i <= 15; i++) {
            list.add(i);
        }
        list.add(100);
        list.add(200);
        list.add(null);
    }
}

F7 

单步调试进行下一步,遇到方法会进入方法内,同一行有多个方法时可以用左右键选择;

F8 

单步调试,进行下一步,不会进入方法内;

Alt+Shift+F7

强制进入方法内;

Shift+F8  

直接跳出方法;

F9

跳到下一个断点或者直接执行完程序

java 中Arraylist 大小增长方式 java arraylist扩容机制_数据_03

 

首先进入ArrayList的构造器,看到  elementData 第一次初始化的时候就是一个空数组

java 中Arraylist 大小增长方式 java arraylist扩容机制_数据_04

java 中Arraylist 大小增长方式 java arraylist扩容机制_开发语言_05

接下来进入到for循环,第一次进去会把int 给类型转化,进行一个装箱操作。 

 

java 中Arraylist 大小增长方式 java arraylist扩容机制_数组_06

然后在添加的时候 ,先执行了判断这个要添加的这个 e 的大小是否达到要求,满足了再将e放入

java 中Arraylist 大小增长方式 java arraylist扩容机制_数据_07

 

java 中Arraylist 大小增长方式 java arraylist扩容机制_数组_08

 第一次返回的一定是 10 (是规定好的了)

java 中Arraylist 大小增长方式 java arraylist扩容机制_数据_09

 


拿到 minCapacity 然后再进入到  ensureExplicitCapacity 其中modCount 表示被修改的次数(这里主要防止有多个线程同时去修改,如果有,则会抛出异常)


 

java 中Arraylist 大小增长方式 java arraylist扩容机制_java_10

只有当  elementData 的大小小于10的时候就调用grow 方法进行扩容。

 

java 中Arraylist 大小增长方式 java arraylist扩容机制_ci_11

 先把传进来的数组大小赋值给一个变量 oldCapacity ,然后按照原先数组的1.5倍进行扩容(右移一位,相当于除以2) 而 Arrays.copyOf 其实就是数组的复制。

java 中Arraylist 大小增长方式 java arraylist扩容机制_java_12

即得到了 10个 elementData 的空元素

java 中Arraylist 大小增长方式 java arraylist扩容机制_java_13

 

ArrayList 的扩容机制是在添加元素时判断当前数组大小是否已经满了,如果已经满了,则创建一个新的更大的数组,并将原来的元素全部复制到新的数组中。具体的扩容规则如下:

  1. 当添加元素后,size 大小已经等于或超过了数组的容量 capacity 时,就会触发扩容操作。
  2. 扩容的大小默认情况下为原数组大小的一半。比如原数组大小为 10,那么扩容后的数组大小为 15。
  3. 如果扩容后的大小还是不够,那么就以添加元素的数量作为扩容大小,即新数组的大小为 oldCapacity + (oldCapacity >> 1) + 1。

        需要注意的是,ArrayList 中的数组无法动态地调整大小,因此每次扩容都需要创建新的数组和复制元素,这可能会带来一些性能损失。为了避免频繁扩容,我们可以在使用 ArrayList 时尽量预估元素数量,初始化时指定一个合适的初始容量。

在实际使用中,我们可以通过指定初始容量和适当的预估来优化扩容操作,以提高性能。