arraylist下标从几开始_Java源码篇之容器类——ArrayList

1、前言

对于平常开发的时候遇到的ArrayList,在此做一个简单的源码阅读记录,JDK1.8版本。

2、ArrayList的类关系

1d8d1a11af431dea201f46dfb634e18e.png

首先看下ArrayList的类关系图,可以看到实现了

  • Serializable接口,支持序列化与反序列化;
  • Cloneable接口,可以被克隆;
  • RandomAccess接口,支持随机访问,另外fori循环会比迭代器循环效率高,代码如下:
for (int i=0, n=list.size(); i < n; i++)         list.get(i); 

比这个循环运行得更快:

for (Iterator i=list.iterator(); i.hasNext(); )         i.next(); 

3、ArrayList的源码

一、类的属性

/*** 默认初始容量 */private static final int DEFAULT_CAPACITY = 10;/** * (用于空实例的)共享空数组实例 */private static final Object[] EMPTY_ELEMENTDATA = {};/** * (用于默认大小的空实例的)共享空数组实例,我们将其与空的元素数据区分开来, * 以了解何时添加第一个元素. */private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};/** * 存储ArrayList元素的数组缓冲区。ArrayList的容量是此数组缓冲区的长度。任何 * elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA elementData  * 将在添加第一个元素时扩展到默认容量(10)。 */transient Object[] elementData;// transient关键字标记的成员变量不参与序列化过程/** * ArrayList的大小(包含的元素数) */private int size;/** * 可分配的数组的最大大小,可能会导致OutOfMemory错误:Requested array size exceeds VM limit */private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

二、add()方法

// 默认往数组末尾添加元素public boolean add(E e) {    ensureCapacityInternal(size + 1);  // 大小加1    elementData[size++] = e;    return true;}private void ensureCapacityInternal(int minCapacity) {// minCapacity = size + 1    // elementData 是成员变量    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));}private static int calculateCapacity(Object[] elementData, int minCapacity) {/ 如果    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {// 数组为空时,返回较大的数        return Math.max(DEFAULT_CAPACITY, minCapacity);    }    return minCapacity; // 数组非空时,返回 minCapacity = size + 1}private void ensureExplicitCapacity(int minCapacity) {// minCapacity = size + 1    modCount++;// 计数    // 数组元素个数加1之后如果大于当前数组长度,则进行扩容    if (minCapacity - elementData.length > 0)        grow(minCapacity);}private void grow(int minCapacity) {// minCapacity = size + 1    int oldCapacity = elementData.length;// 旧数组的长度    int newCapacity = oldCapacity + (oldCapacity >> 1);// 新数组的长度 = 1.5倍旧数组长度    // 新数组长度小于数组元素个数加1    if (newCapacity - minCapacity < 0)        newCapacity = minCapacity;    // 新数组长度大于数组最大值    if (newCapacity - MAX_ARRAY_SIZE > 0)        newCapacity = hugeCapacity(minCapacity);    // 创建一个新的数组,并把旧数组元素复制过去,newCapacity为新数组大小    elementData = Arrays.copyOf(elementData, newCapacity);}private static int hugeCapacity(int minCapacity) {    if (minCapacity < 0)        // 新数组长度大于数组最大值,并且minCapacity<0才会抛出oom错误        throw new OutOfMemoryError();    return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;}// 指定位置添加元素public void add(int index, E element) {    // 下标合法性校验    rangeCheckForAdd(index);    ensureCapacityInternal(size + 1);     // 生成一个index位置为null的新数组    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));}

三、get()方法

public E get(int index) {    // 检查合法性    rangeCheck(index);    // 返回数组元素    return elementData(index);}private void rangeCheck(int index) {    // 下标位置大于等于数组长度的时候(数组下标从0开始),抛出下标越界异常    if (index >= size)        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));}E elementData(int index) {    return (E) elementData[index];}

四、remove()方法

// 删除指定下标的元素public E remove(int index) {    // 校验合法性    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;}// 删除指定的元素,第一个出现的public boolean remove(Object o) {    if (o == null) {        for (int index = 0; index < size; index++)            if (elementData[index] == null) {                fastRemove(index);                return true;            }    } else {        for (int index = 0; index < size; index++)            if (o.equals(elementData[index])) {                fastRemove(index);                return true;            }    }    return false;}private void fastRemove(int index) {    modCount++;    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}五、set()方法

五、set()方法

// 将index位置的元素置换成elementpublic E set(int index, E element) {    rangeCheck(index);    E oldValue = elementData(index);    elementData[index] = element;    return oldValue;}

4、总结

  • 通过阅读源码可以看出,ArrayList的这些方法都没有加锁,所以在多线程环境下是不安全的;
  • add()和remove()方法都需要创建新的数组,是比较消耗性能的;
43017f5df8c247adece042826c5bee11.png
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值