源码学习(1) ArrayList源码分析

296 阅读3分钟

代码版本: JDK 1.8

  1. ArrayList实例化(为以下两种)
** 第1种:
/** * 无参构造函数。 创建一个长度为0的数组 此时并不会初始化容量 */
public ArrayList() {    
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
** 第2种:
/** 指定集合长度创建ArrayList  等于0和无参构造函数一样  */
public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
        }
    }

数组初始化之后,下一步就是增加元素了 !

  1. add方法
public boolean add(E e) {
    // 判断数组容量情况  size+1是本次添加元素所需容量
    ensureCapacityInternal(size + 1);  // 👇下面进入此方法
    elementData[size++] = e;
    return true;
}
/** @param minCapacity  需要的最小容量 */
private void ensureCapacityInternal(int minCapacity) {
    //返回需要容量 该方法就是比较个大小
    int c = calculateCapacity(elementData, minCapacity);
    // 扩容  👇下面进入此方法(下一代码块)
    ensureExplicitCapacity(c);
    /** ------------------  calculateCapacity()方法  -------------------------- ****
      * private static int calculateCapacity(Object[] elementData, int minCapacity) {
      * if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
      *     return Math.max(DEFAULT_CAPACITY, minCapacity);
      * }
      * return minCapacity;
      * ------------------ ------------------ ------------------ ------------------ /
}

扩容逻辑在这里 👈👈

private void ensureExplicitCapacity(int minCapacity) {
    modCount++;
    // 判断容量大小,如果容量大于数组长度  进入扩容逻辑
    if (minCapacity - elementData.length > 0){
        // 存储原始容量
        int oldCapacity = elementData.length;
        // 新容量扩容1.5倍
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        // 扩容后的容量比需要的容量还小,就需要直接使用需要的容量扩容
        if (newCapacity - minCapacity < 0)
            // 新容量 = 需要的最小的容量
            newCapacity = minCapacity;
        // 扩容容量大于int最大值  使用int最大值
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // 把原数组数据放入新数组
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
}

add方法代码就这些

  1. 增加完了,开始查询。很简单,为了完整性,代码也贴出来。 ArrayList是基于数组实现的,所以查询速度很快,增删元素效率就比较低了(下次整理出来LinkedList)
public E get(int index) {
    if (index >= size)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    return (E) elementData[index];
}
  1. 删除
public E remove(int index) {
    E oldValue = elementData(index);
    int numMoved = size - index - 1;
    if (numMoved > 0)
        // ★★  代码就在这里一句话    
        System.arraycopy(elementData, index+1, elementData, index,numMoved);
    //最后一个元素置空
    elementData[--size] = null;
    return oldValue;
}

解释下

System.arraycopy(src, srcPos, dest, destPos,length);   

  • Object src : 原数组

  • int srcPos : 从元数据的起始位置开始   

  • Object dest : 目标数组   

  • int destPos : 目标数组的开始起始位置   

  • int length : 要copy的数组的长度

大概意思是 从srcPos位置 拿length个数据,放在dest数组的destPos下标的位置,按拿的顺序排序放

src{0,1,2,3,4,5} 
——> System.arraycopy(src, 3, dest, 2, 2);
dest {0,1,3,4,4,5}
  1. 修改(就是替换下)
public E set(int index, E element) {
    E oldValue = elementData(index);
    elementData[index] = element;
    return oldValue;
}
  1. 按照指定位置增加元素
public void add(int index, E element) {
    if (index > size || index < 0)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    ensureCapacityInternal(size + 1);  // 该方法上面有说明
    // 这个在删除元素那里有  很简单
    // 把index位置之后的所有数据下标➕1,然后index位置赋值为element
    System.arraycopy(elementData, index, elementData, index + 1,
            size - index);
    // 赋值
    elementData[index] = element;
    size++;
}

End!!! ArrayList还是很简单,那就从一个最简单的开始吧。如有不对的地方,欢迎指正。

第一次写文章,真的是挺费劲的。下次看看整理下LinkedList,