ArrayList源码分析

一、底层数据结构

transient Object[] elementData; //定义了一个Object元素类型的数组

private int size;//数组的长度

二、构造函数

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

private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};//用于空实例的空数组实例。如 ArrayList list = new ArrayList<>() list就等于{}



//初始化ArrayList的容量大小

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

     }

}



//无任何入参,实例化一个空的数组实例

public ArrayList() {

     this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;

}



public ArrayList(Collection<? extends E> c) {

     elementData = c.toArray();

     if ((size = elementData.length) != 0) {

         if (elementData.getClass() != Object[].class) //这个地方之所以要比较,是因为c.toArray()返回的不一定是object[],这是jdk的一个bug,详情可以看see 6260652 【这个编号代表JDK bug库中的编号】

             elementData = Arrays.copyOf(elementData, size, Object[].class);

     } else {

         this.elementData = EMPTY_ELEMENTDATA;

     }

}

+-----------------------------------------------------

其他版本的jdk写法

public ArrayList(Collection<? extends E> c) {

    Object[] a = c.toArray();

    if ((size = a.length) != 0) {

        if (c.getClass() == ArrayList.class) {

            elementData = a;

        } else {

            elementData = Arrays.copyOf(a, size, Object[].class);

        }

    } else {

        elementData = EMPTY_ELEMENTDATA;

    }

}

三、自动扩容

public void ensureCapacity(int minCapacity) {

    //判断需要扩容的数组是否为空实例(空数组)如果为不为空,变量等于0, 为空则变量等于数组默认容量 10[意味着不需要扩容,取默认大小即可]

    int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) ? 0 : DEFAULT_CAPACITY;

    if (minCapacity > minExpand) {//如果需要扩容的量大于定义的变量,则进行扩容操作

        ensureExplicitCapacity(minCapacity);

    }

}

private void ensureExplicitCapacity(int minCapacity) {

    modCount++;

    if (minCapacity - elementData.length > 0)//需要扩容的量大于原数组的长度,则真正进行扩容操作

        grow(minCapacity);

}





private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;//要分配的数组的最大大小



private void grow(int minCapacity) {

    int oldCapacity = elementData.length;  //原数组的长度

    int newCapacity = oldCapacity + (oldCapacity >> 1);  //原数组的长度+原数组的长度/2

    if (newCapacity - minCapacity < 0)

        newCapacity = minCapacity; // 系统给予的扩容策略所扩的容量<用户给的扩容量,则改用用户指定扩容量

    if (newCapacity - MAX_ARRAY_SIZE > 0)// 如果需要扩容的量大于了本类中定义的最大扩容限制,则扩容到 int 类型最大长度

        newCapacity = hugeCapacity(minCapacity);

    elementData = Arrays.copyOf(elementData, newCapacity);// 扩容,其实调用的的是数组的复制方法

}

private static int hugeCapacity(int minCapacity) {

    if (minCapacity < 0)

        throw new OutOfMemoryError();

    // 如若需要扩容的量大于了最大限制,则扩容量改为 int 最大限制量:2147483647。否则为本类中所限制长度:2147483647-8

    return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;

}

四、其他方法

add(), addAll():该方法是向list中添加一个或者多个元素,默认是往最后添加;同时,也是可以指定位置进行添加的。

+---在这个过程中,会先检查空间是否有剩余,指定位置的时候还会校验位置,而且会存在元素移动的情况,addAll时间复杂度都是线性递增的

set():由于底层是数组,指定位置赋值即可。

get():需要注意的地方是:由于底层是Object元素,取值的时候需要进行类型转换。

remove():删除指定位置的元素,需要将后面的元素向前移动一个位置。而且为了让GC起到作用,最后一个元素必须手动赋值null,也就是手动清除该引用。

trimToSize():将底层数据容量调整为实际存放元素大小容量。

indexOf(), lastIndexOf():获取元素第一个出现的位置,包括null第一次出现的位置,主要是使用for循环,使用equal进行匹配。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值