集合(一) - ArrayList

一、层级关系

clipboard.png

二、初始化方式

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

public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

第一个结论:ArrayList底层是数组

第二个结论:若用无参构造器的方式实例化ArrayList,只是声明了数组,还未分配空间

(2)List<String> list = new ArrayList<>(10);

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);
    }
}

private static final Object[] EMPTY_ELEMENTDATA = {};

补充第二结论:若用有参构造器的方式实例化ArrayList且initialCapacity大于0,则既声明了数组,也分配了空间

三、基本方法的使用

add

  • 流程图

clipboard.png

  • 源码解析
public boolean add(E e) {
    //校验数组容量,若空间不够则扩容复制生成一个新的数组
    ensureCapacityInternal(size + 1); 
    //赋值
    elementData[size++] = e;
    return true;
}

private void ensureCapacityInternal(int minCapacity) {
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}

/**
 * 若数组是通过无参构造器的方式实例化的话,返回的minCapacity为10,最后会通过grow方法复制生成一个大小为10的数组
 * 若数组是通过有参构造器的方式实例化的话,返回的minCapacity为当前要操作的数组下标,不建议声明小于10的数组空间,因为这样前几次add都要去扩容复制生成一个新的数组
 */
private void ensureExplicitCapacity(int minCapacity) {
    modCount++;

    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
    grow(minCapacity);
}

//扩容大小:原数组大小 + 原数组大小/2
private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
    newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
    newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    elementData = Arrays.copyOf(elementData, newCapacity);
}
  • 其它说明

    1. 初始化ArrayList时,不建议声明小于10的容量,因为这样前几次add都要去扩容复制生成一个新的数组
    2. Arrays.copyOf(T[] original, int newLength):该方法会创建一个新的数组

remove

  • 流程图

clipboard.png

  • 源码解析
public E remove(int index) {
    //检查index是否 >= size,若大于则报数组越界异常
    rangeCheck(index);

    modCount++;
    E oldValue = elementData(index);

    int numMoved = size - index - 1;
    if (numMoved > 0)
    System.arraycopy(elementData, index+1, elementData, index,
    numMoved);
    elementData[--size] = null; // clear to let GC do its work

    return oldValue;
}
  • 其它说明

    1. System.arraycopy - 浅复制
public static void arraycopy(
                             Object src,  //源数组
                             int srcPos,  //源数组要复制的起始位置
                             Object dest, //目标数组
                             int destPos, //目的数组放置的起始位置
                             int length   //复制长度
                             )

四、补充

  • ArrayList是线程不安全的,表现在多线程下add和remove可能会发生数组越界
  • 不要在foreach循环里进行元素的remove/add操作。remove元素请使用Iterator方式,如果并发操作,需要对Iterator对象加锁
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值