java容器类:ArrayList

ArrayList是刚接触java用的最多的一个容器类,它也有很多的特点:

  • 自动扩容 实例化一个ArrayList对象以后,可以放任意多的对象进去,而不像数组,使用前必须声明大小,超过这个大小就会抛出数组越界的异常.
  • 检索速度快 速度快是相较于链表.链表要找到一个指定对象必须要对整条链进行遍历.而ArrayList只要知道索引就能很快得出结果,不需要费时进行遍历.

ArrayList的原理

ArrayList是List家族中的一员,继承了AbstractList.依赖于数组帮它存储数据,所以它本质上和数组没有区别,只是数组的升级版本.所以它可以像数组一样可以用索引来查找对象.
那么它是怎样实现自动扩容?当然就要先看看add方法了.

private transient Object[] elementData;//这是帮助ArrayList管理数据的数组对象

private static final int DEFAULT_CAPACITY = 10;//默认的容量为10

public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!! 这个方法中确认是否有必要扩容
    elementData[size++] = e;
    return true;
}

private void ensureCapacityInternal(int minCapacity) {
    if (elementData == EMPTY_ELEMENTDATA) {    //判断elementData对象是否为空
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);//取minCapacity和DEFAULT_CAPACITY之间最大的数作为数组的容量
    }

    ensureExplicitCapacity(minCapacity);//执行下一步方法
}

private void ensureExplicitCapacity(int minCapacity) {
    modCount++;

    // overflow-conscious code
    if (minCapacity - elementData.length > 0)//如果要求扩充的容量是否大于当前数组的长度
        grow(minCapacity);
}

private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;//原先的容量oldCapacity 
    int newCapacity = oldCapacity + (oldCapacity >> 1);//将要扩充的容量newCapacity 是原来的1.5倍
    if (newCapacity - minCapacity < 0)//如果newCapacity 反而比指定的容量minCapacity要小,那么扩充大小根据minCapacity来定
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)//如果newCapacity已经超出了最大范围,那么根据minCapacity来判断大小,这一步基本上不用关心,其实就是在扩充至1.5倍和minCapacity大小中选择
        newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    elementData = Arrays.copyOf(elementData, newCapacity);//这是ArrayList为什么能够扩容的原因.
}

public static <T> T[] copyOf(T[] original, int newLength) {
    return (T[]) copyOf(original, newLength, original.getClass());//拷贝原来的数组对象到一个新的长度为newLength的数组中.可以再进一步查看copyOf方法.
}

//如果数组类型是Object数组,那么就构建一个newLength的Object数组
//如果不是的话就构建一个对应类型的数组对象
//将原来的数组从头开始,按照原生数组长度或者数组对象的最小值,复制到新的数组对象,并返回该对象.
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
    T[] copy = ((Object)newType == (Object)Object[].class)
        ? (T[]) new Object[newLength]
        : (T[]) Array.newInstance(newType.getComponentType(), newLength);
    System.arraycopy(original, 0, copy, 0,
                     Math.min(original.length, newLength));
    return copy;
}
  • 在add方法中,当它达到能够存储的上限时,它存储的内容就会被复制到另外一个"更大尺寸"的数组中,并被这个新的数组取而代之.而它则被无情地抛弃,伴随着垃圾回收消失在内存中.
  • 这其中最关键的就是System.arraycopy(original, srcPos, copy, destPos,length);
  • 指定原始的数组original和要存放复制元素的对象copy,从original的srcPos位置开始复制length长度的元素到copy的destPos位置.
    除开add,还有更多的方法调用了这个方法
  • add(int index, E e) 在指定位置插入对象.将elementData的inxdex开始的元素复制到elementData的index+1的位置,变向将index以后所有的元素后移了一位.这样就能理所当然的让新对象占据index的位置了.System.arraycopy(elementData, index, elementData, index + 1,size - index);
  • remove(int index) 判断移除的对象是不是最后一个,如果不是,那么将该索引的右边的对象左移一位,最后去掉尾部重复的对象System.arraycopy(elementData, index+1, elementData, index, numMoved);
  • addAll(Collection<? extends E> c) 先得到c的数组对象a,将数组根据a的长度扩容,然后将a拷贝到elementData的尾部System.arraycopy(a, 0, elementData, size, numNew);
  • addAll(int index, Collection<? extends E> c) 将c的数组对象拷贝到指定index的位置,如果index不在尾部,还要将elementData内index位置的对象后移System.arraycopy(elementData, index, elementData, index + numNew,numMoved);最后才同样调用相同方法System.arraycopy(a, 0, elementData, size, numNew);

转载于:https://www.cnblogs.com/itsrobin/p/5184664.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值