ArrayList集合底层原理

ArrayList集合底层原理

1.利用空参构造创建的集合,在底层会创建一个默认长度为0的数组(elementData)

2.添加第一个元素时,底层会创建一个新的长度为10的数组

3.存满时,数组容量会扩容1.5倍

4.若依次添加多个元素,1.5倍还放不下,则新创建的数组的长度会以实际为准

说明:
第一种情况:

添加第一个元素

ArrayList<String> list=new ArrayList<> ();

当我们使用无参构造创建一个对象,JVM会在底层创建一个默认长度为0的数组,名字叫elementData,还有一个成员属性size。

size有两层含义: 1.集合中元素的个数 2.元素下次存入的位置。

 public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
​
private int size;       //size成员变量
 transient Object[] elementData; // elementData是一个数组,
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};      
 //将空数组DEFAULTCAPACITY_EMPTY_ELEMENTDATA 赋值给 elementData

 public boolean add(E e) {
        modCount++;
        add(e, elementData, size);
        return true;
    }

当我们使用: list.add("aaa"); 添加第一个元素,

e="aaa",调用 add(e, elementData, size) (其中第一个参数:要添加的元素,第二个参数:底层该数组的名称,第三个参数:集合的长度/元素下次应存入的位置).

执行以下代码:其中s=0, elementData.length=0,执行 elementData = grow(); 语句,表示数组扩容,调用grow()方法

private void add(E e, Object[] elementData, int s) {
        if (s == elementData.length)
            elementData = grow();
        elementData[s] = e;
        size = s + 1;
    }
​

执行下列代码:

 private Object[] grow() {
        return grow(size + 1);
    }

size + 1 = 0 +1 = 1,调用下面grow(1)

private Object[] grow(int minCapacity) {
        int oldCapacity = elementData.length;       //记录原来的老数组
        if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            int newCapacity = ArraysSupport.newLength(oldCapacity,
                    minCapacity - oldCapacity, /* minimum growth */
                    oldCapacity >> 1           /* preferred growth */);
            return elementData = Arrays.copyOf(elementData, newCapacity);
        } else {
            return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
        }   //DEFAULT_CAPACITY为 10 
    }
​
//private static final int DEFAULT_CAPACITY = 10;

minCapacity=1,oldCapacity = 0,第一次添加数据的时候,会执行这里的else语句,其中DEFAULT_CAPACITY默认容量为10,调用Math.max()方法,然后new,会创建一个长度为10的数组,然后 return 返回到 elementData = grow()调用处,继续执行 elementData[s] = e; size = s + 1; 语句添加元素,size加一。

第二种情况:

若我们已经向数组中添加了10个元素,“aaa”为第11个

ArrayList<String> list=new ArrayList<> ();

当我们使用无参构造创建一个对象,JVM会在底层创建一个默认长度为0的数组,名字叫elementData,还有一个成员属性size。

size有两层含义: 1.集合中元素的个数 2.元素下次存入的位置。

 public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
​
private int size;       //size成员变量
 transient Object[] elementData; // elementData是一个数组,
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};   
    //将空数组DEFAULTCAPACITY_EMPTY_ELEMENTDATA 赋值给 elementData

 public boolean add(E e) {
        modCount++;
        add(e, elementData, size);
        return true;
    }

当我们使用: list.add("aaa"); 添加第一个元素,

e="aaa",调用 add(e, elementData, size)(其中第一个参数:要添加的元素,第二个参数:底层该数组的名称,第三个参数:集合的长度/元素下次应存入的位置),

执行以下代码:其中s=11, elementData.length=10,执行 elementData = grow(); 语句,表示数组扩容,调用grow()方法

private void add(E e, Object[] elementData, int s) {
        if (s == elementData.length)
            elementData = grow();
        elementData[s] = e;
        size = s + 1;
    }
 

执行下列代码:

 private Object[] grow() {
        return grow(size + 1);
    }

size + 1 = 10 +1 = 11,调用下面grow(11)

private Object[] grow(int minCapacity) {
        int oldCapacity = elementData.length;       //记录原来的老数组
        if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            int newCapacity = ArraysSupport.newLength(oldCapacity,      //老容器
                    minCapacity - oldCapacity,      //理论上我们至少要新增的容量
                    oldCapacity >> 1  );        //默认新增的容量
            return elementData = Arrays.copyOf(elementData, newCapacity);
        } else {
            return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
        }   //DEFAULT_CAPACITY为 10 
    }
​
//private static final int DEFAULT_CAPACITY = 10;

minCapacity=11, oldCapacity=10, 执行if语句,调用方法 ArraysSupport. newLength (oldCapacity, minCapacity - oldCapacity, oldCapacity >> 1 ); 其中oldCapacity代表老容器的容量,minCapacity - oldCapacity)表示理论上我们至少要新增的容量,oldCapacity >> 1(表示老容器容量除以2,扩容1.5倍中 .5 的来源)表示默认新增的容量大小,

执行以下代码

public static int newLength(int oldLength, int minGrowth, int prefGrowth) {
      
        int prefLength = oldLength + Math.max(minGrowth, prefGrowth); // might overflow
        if (0 < prefLength && prefLength <= SOFT_MAX_ARRAY_LENGTH) {
            return prefLength;
        } else {
            // put code cold in a separate method
            return hugeLength(oldLength, minGrowth);
        }
    }

其中Math.max(minGrowth, prefGrowth)把我们至少要新增的容量和默认新增的容量大小进行比较

为啥呢:

因为在集合中,我们不仅仅一次添加一个元素,还可以一次添加多个元素

若我们调用addAll()方法,一次添加100个元素,那么minGrowth=100,这时候就以我们实际的元素个数来进行扩容

 int prefLength = oldLength + Math.max(minGrowth, prefGrowth);        
 //表示新数组真正的长度
  • 第一种情况:如果一次添加一个元素,那么第二个参数一定是1,表示此时数组只要扩容1个单位大小就可以了

  • 第二种情况:如果一次添加多个元素,假设为100个,那么第二个元素为100,表示此时数组需要扩容100个单位大小才可以

将新数组真正的长度prefLength 交给newCapacity,然后调用        Arrays.copyOf(elementData, newCapacity);        方法进行数组拷贝,该方法:

1.会根据第二个参数创建新的数组

2.把第一个参数中的所有数据,全部拷贝到新数组当中

然后 return 返回到 elementData = grow()调用处,继续执行 elementData[s] = e; size = s + 1; 语句添加元素,size加一。

  • 24
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值