编程语言
首页 > 编程语言> > ArrayList 源码分析

ArrayList 源码分析

作者:互联网

ArrayList 原理

ArrayList的优缺点

源码分析

构造方法

在ArrayList中,默认的构造方法,直接初始化一个ArrayList实例的话,会将内部的数组做成一个默认的空数组{}private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};,它有一个默认的初始化的数组的大小的值,默认为10,也就是我们可以认为它默认的数组初始化的大小就是只有10个元素
对于ArrayList,如果要玩好的话,一般来说,你应该都不是使用这个默认的构造函数,你构造一个ArrayList的话,基本上来说就是默认它里面不会有太频繁的插入、移除元素的操作,大体上他里面有多少元素,你应该可以推测一下
基本上最好是给ArrayList构造的时候,给一个比较靠谱的初始化的数组大小,比如说,100个数据,1000个数据,避免数组太小,往里面塞入数据的时候,导致数据不断的扩容,不断的搞新数组

boolean add(E e)

public boolean add(E e) {
      ensureCapacityInternal(size + 1);  // Increments modCount!!
      elementData[size++] = e;
      return true;
 }

你每次往ArrayList中插入数据的时候,都会判断一下,当前数组是否塞满了,如果塞满了,此时就会自动扩容,然后将老数组中的元素拷贝到新数组中,确保说数组一定是可以承受足够多的元素的,扩容的方法是grow(),扩容的大小为int newCapacity = oldCapacity + (oldCapacity >> 1);

E set(int index, E element)

public E set(int index, E element) {
    // 用于检测索引是否超出元素大小,超出就报IndexOutOfBoundsException
    rangeCheck(index);
    // 替换索引位置的元素
    E oldValue = elementData(index);
    elementData[index] = element;
    // 返回索引所在的老的数据
    return oldValue;
}

private void rangeCheck(int index) {
   if (index >= size)
      throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

void add(int index, E element)

public void add(int index, E element) {
    // 判断索引是否越界
    rangeCheckForAdd(index);
    // 该方法确保数组是否满了,若满了再次添加的时候会调用grow()进行扩容
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    // 进行数组的拷贝
    // 5个参数
    // 第一个参数是要被复制的数组
    // 第二个参数是被复制的数字开始复制的下标
    // 第三个参数是目标数组,也就是要把数据放进来的数组
    // 第四个参数是从目标数据第几个下标开始放入数据
    // 第五个参数表示从被复制的数组中拿几个数值放到目标数组中
    // eg:
    // 数组1:int[] arr = { 1, 2, 3, 4, 5 };
    // 数组2:int[] arr2 = { 5, 6,7, 8, 9 };
    // 运行:System.arraycopy(arr, 1, arr2, 0, 3);
    // 得到
    // int[] arr2 = { 2, 3, 4, 8, 9 };
    // 表示的是从数组arr中下标为1的位置取出3个数据,放到数组arr2中从下标为2的位置,放入3个数据。
    System.arraycopy(elementData, index, elementData, index + 1,
                     size - index);
    elementData[index] = element;
    size++;
}

private void rangeCheckForAdd(int index) {
    if (index > size || index < 0)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

E get(int index)

public E get(int index) {
    // 判断数组是否越界
    rangeCheck(index);
    // 直接返回索引位置的元素
    return elementData(index);
}

E remove(int index)

public E remove(int index) {
    // 判断索引是否超出数组大小
    rangeCheck(index);
    // 查资料说这是 记录modCount的修改次数
    modCount++;
    E oldValue = elementData(index);
    // 需要挪动的元素的个数
    int numMoved = size - index - 1;
    if (numMoved > 0)
        // 数组的拷贝,见add()源码分析
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
    // 将移动后最后一个位置设为 null
    elementData[--size] = null; // clear to let GC do its work

    return oldValue;
}

源码分析的总结

remove()、add(index,element)这两个方法,都会导致数组的拷贝,大量元素的挪动,这种基于数组来做这种随机位置的插入和删除,性能都不是太高
add()、add(index,element)这两个方法,都可以会导致数组需要扩容,数组长度是固定的,默认初始大小是10个元素,如果不停的往数组里赛数据,可能会导致瞬间数组不停的扩容,影响系统性能
set()、get()定位到随机位置,替换那个元素,或者是获取那个元素,这个其实还是比较靠谱的,基于数组来实现随机位置的定位,性能还是很高的

标签:分析,index,elementData,int,ArrayList,元素,源码,数组
来源: https://www.cnblogs.com/xiaoyangabc/p/16210208.html