ArrayList原理分析(重点在于扩容)

首先,ArrayList定义只定义类两个私有属性:

/** 
      * The array buffer into which the elements of the ArrayList are stored. 
      * The capacity of the ArrayList is the length of this array buffer. 
      */  
     private transient Object[] elementData;  
   
     /** 
      * The size of the ArrayList (the number of elements it contains). 
      * 
      * @serial 
      */  
     private int size;
View Code

可知:elementData存储ArrayList内的元素,size表示它包含的元素的数量(不是指容量)。

注意:elementData用transient修饰,这表明当持久化ArrayList对象时,并不会保存它。

ArrayList是基于数组实现的,添加元素时,将某个位置的值设置为指定元素即可,但数组容量不够,如何扩容呢?

我们提供具体的方法来分析:

add方法:

// 将指定的元素添加到此列表的尾部。  
    public boolean add(E e) {
        ensureCapacity(size + 1); //判断容量是否足够,不够就扩容
        elementData[size++] = e;
        return true;
    }
View Code

那么扩容的核心在于ensureCapacity方法

ensureCapacity方法:

public void ensureCapacity(int minCapacity) {  
    modCount++;  
    int oldCapacity = elementData.length;  
    if (minCapacity > oldCapacity) {  //size+1即添加后的长度,判断如果添加,会不会过长
        Object oldData[] = elementData;  
        int newCapacity = (oldCapacity * 3)/2 + 1;  //1.5倍扩容
            if (newCapacity < minCapacity)  
                newCapacity = minCapacity;  
      // minCapacity is usually close to size, so this is a win:  
      elementData = Arrays.copyOf(elementData, newCapacity);  //将老数组拷贝一份到新数组
    }  
 }
View Code

可知:

1. 每次添加前都会判断是否会过长,会,则先扩容

2. 每次扩容都是1.5倍扩容,其实是1.5倍+1

3. 老数组通过Arrays.copyOf()拷贝一份到新数组

那么问题来了,每次扩容都是1.5倍是否会造成较大的空间浪费?

是的,所以建议在构造ArrayList实例时,就预估大小并指定其容量,以避免数组扩容的发生。或者根据实际需求,直接调用ensureCapacity方法来手动增加ArrayList实例的容量

猜你喜欢

转载自www.cnblogs.com/yanze/p/10083898.html