ArrayList源码分析

ArrayList是一个可变大小的数组实现,用于存储任意元素,包括null。它提供了高效的get和set操作,但add和remove操作相对较慢。默认容量为10,当需要时会按1.5倍旧容量扩容。非线程安全,多线程环境下需外部同步。添加和删除元素涉及数组拷贝,可能导致性能下降。
摘要由CSDN通过智能技术生成

ArrayList概述

ArrayList是一个可调整容量大小的数组,其实现了List接口,可以存放任意元素包括null,其内部实现是数组,get、set、Iterator操作是固定时间内运行,效率较高,但是add、remove操作效率稍低。不是线程安全的类,如果有多个线程访问该类的实例,并且至少有一个线程在修改列表,则必须在外部进行同步

成员变量

// 初始化时如果没有指定容量大小,则默认容量为10
private static final int DEFAULT_CAPACITY = 10;
​
// 当没有元素时赋值为此空对象
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
​
// 以数组形式维护其内部成员,以transient关键字声明,说明其成员不参与序列化
transient Object[] elementData;
​
private int size;//ArrayList 内部当前维护的元素个数

构造函数

public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;//初始化为空对象
}
// 用另外一个集合初始化
public ArrayList(Collection<? extends E> c) {
    elementData = c.toArray();
    if ((size = elementData.length) != 0) {
        // c.toArray might (incorrectly) not return Object[] (see 6260652)
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, size, Object[].class);
    } else {
        // replace with empty array.
        this.elementData = 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);
    }
}

成员方法

添加新元素

public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // 以当前元素个数+1,与capacity比较,如果容量不够,则扩容
    elementData[size++] = e;
    return true;
}
​
private void ensureCapacityInternal(int minCapacity) {
    // 如果列表中没有元素时,取当前容量与minCapacity中的最大值
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
    }
​
    ensureExplicitCapacity(minCapacity);
}
​
private void ensureExplicitCapacity(int minCapacity) {
    modCount++;
​
    // 如果容量不够用了,开始扩容
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}
​
private void grow(int minCapacity) {
    int oldCapacity = elementData.length;// 当前元素个数
    int newCapacity = oldCapacity + (oldCapacity >> 1);// 新容量为旧容量的1.5倍
    if (newCapacity - minCapacity < 0)// 如果新容量小于比较值,取比较值为新的容量大小
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)// 如果超过了最大支持容量数
        newCapacity = hugeCapacity(minCapacity);// 大容量数组检验
    // 当前元素复制到新扩容的空间中,此处涉及到内存数据复制
    elementData = Arrays.copyOf(elementData, newCapacity);
}
​
private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // 数据溢出,抛异常, 否则取整型数的最大值为新容量
        throw new OutOfMemoryError();
    return (minCapacity > MAX_ARRAY_SIZE) ?
        Integer.MAX_VALUE :
    MAX_ARRAY_SIZE;
}

给指定位置添加新元素

public void add(int index, E element) {
    if (index > size || index < 0)// 边界检查,越界时抛出异常
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
​
    ensureCapacityInternal(size + 1);  // 与上面add方法基本一致
    System.arraycopy(elementData, index, elementData, index + 1,
                     size - index);
    elementData[index] = element;// 将新元素插入到指定索引位置
    size++;
}

ArrayList 在添加新元素的过程中,如果当闪容量不中以存储下元素的数量,则需要进行扩容操作,int newCapacity = oldCapacity + (oldCapacity >> 1); 这一句代码表明:一般情况下扩容时都是以旧容量的1.5倍进行扩容

移除元素

public E remove(int index) {
    if (index >= size)// 越界,抛出异常
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
​
    modCount++;
    E oldValue = (E) elementData[index];// 指定位置的元素
​
    int numMoved = size - index - 1;// 计算需要做内存移动的元素数量
    if (numMoved > 0)// 如果需要移动,将index后面的元素向前移动到时合适位置
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
    elementData[--size] = null; // 将最后一个元素置空,之后可能会触发GC
​
    return oldValue;// 返回要删除的元素
}

set、get

set方法直接将指定位置替换为新元素,最后将老元素返回

get方法直接将指定位置的元素返回

public E set(int index, E element) {
    if (index >= size)// 越界抛异常
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
​
    E oldValue = (E) elementData[index];
    elementData[index] = element;
    return oldValue;
}
​
public E get(int index) {
    if (index >= size)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
​
    return (E) elementData[index];
}

总结

  • 以数组维护内部数据

  • 容量大小自动调节,容量不够时1.5倍旧容量大小扩容

  • 添加删除操作效率较低,遍历西西查找效率较高

  • 不是线程安全的实现

  • 内容可重复,可以为null

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值