ArrayList源码解析

ArrayList源码解析

简介

ArrayList是一个基于数组来实现动态扩容的集合,具有良好的查询性能。

1、重要的成员变量

// 默认初始容量
private static final int DEFAULT_CAPACITY = 10;
// 空数组,有参构造参数为0时,即创建一个容量为0的list时使用
private static final Object[] EMPTY_ELEMENTDATA = {};
// 空数组,无参构造时使用
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
// 数组
transient Object[] elementData;
// 数组大小
private int size;

2、构造方法

使用有参构造时,如果初始容量大于0,则直接创建数组;如果初始容量等于0,则使用EMPTY_ELEMENTDATA空数组。

// 无参构造函数
public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
// 有参构造函数
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);
    }
}

3、核心方法

3.1 插入元素 add(E e)

最常用的方法之一,每次添加元素前先判断容量是否足够,不够则触发扩容。

public boolean add(E e) {
	// 判断list容量是否够,不够则扩容。
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}
3.2 容量大小判断

先计算所需要的最小容量,再判断是否需要扩容。
如果是无参构造创建的list,则直接用默认初始容量和最小所需容量比较获取较大者。因此,如果创建list的时候没有指定大小,添加元素时list会默认扩容至10。
如果最小容量大于数组的容量,则触发扩容。

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

// 计算所需要的最小容量
private static int calculateCapacity(Object[] elementData, int minCapacity) {
	// 如果是无参构造创建的list,则直接用默认初始容量和最小所需容量比较获取较大者。
	// 即如果创建list的时候没有指定大小,添加元素时list会默认扩容至10。
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        return Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    return minCapacity;
}

private void ensureExplicitCapacity(int minCapacity) {
    modCount++;
    if (minCapacity - elementData.length > 0)
    	// 如果所需最小容量大于list的容量,则需要扩容。
        grow(minCapacity);
}
3.3 扩容方法 grow()

新容量为旧容量加上旧容量的一半,即扩容为原来的1.5倍。
扩容完成后,将旧数组的数据拷贝到新数组中,但会影响性能。所以如果能确定一个list的大小,最好使用在创建时指定大小。

// 开始扩容
private void grow(int minCapacity) {
    int oldCapacity = elementData.length;
    // 新容量为旧容量加上旧容量的一半,即扩容为原来的1.5倍。
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
   // 将数据拷贝到新数组中,这里会损失性能。
   // 所以如果能确定一个list的大小,最好使用在创建时指定大小。
    elementData = Arrays.copyOf(elementData, newCapacity);
}
3.4 获取List中元素 get()

这里会做一次检查,判断是否越界。

public E get(int index) {
    rangeCheck(index);
    return elementData(index);
}

private void rangeCheck(int index) {
    if (index >= size)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
  • 8
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值