Java 集合深入理解:ArrayList

本文深入解析了ArrayList的内部结构,包括其实现原理、优势、空间占用、时间复杂度以及源码分析。详细介绍了ArrayList如何通过数组实现动态扩容,以及其在添加、查询、修改和删除操作上的高效表现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ArrayList在集合框架中的树形结构

以继承和实现接口展示

public class ArrayList<E> extends AbstractList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{}

优点

容量不固定,有最大阈值,但一般达不到
有序的(元素输出顺序与输入顺序一致)
元素可以为 null
效率高
size(), isEmpty(), get(), set() iterator(), ListIterator() 方法的时间复杂度都是 O(1)
add() 添加操作的时间复杂度平均为 O(n)
其他所有操作的时间复杂度几乎都是 O(n)
占用空间更小
对比 LinkedList,不用占用额外空间维护链表结构

源码分析

ArrayList底层实现是数组

transient Object[] elementData; // non-private to simplify nested class access

由于数组类型为 Object,所以允许添加 null 。
transient 说明这个数组无法序列化。
初始时为 DEFAULTCAPACITY_EMPTY_ELEMENTDATA 。

private static final Object[] 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);
    }
}
//初始为空数组
public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

//直接创建和指定集合一样内容的 ArrayList
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 boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}

//在指定位置添加一个元素
public void add(int index, E element) {
    rangeCheckForAdd(index);

    ensureCapacityInternal(size + 1);  // Increments modCount!!
    //整体后移一位
    System.arraycopy(elementData, index, elementData, index + 1,
                     size - index);
    elementData[index] = element;
    size++;
}

public boolean addAll(Collection<? extends E> c) {
    Object[] a = c.toArray();
    int numNew = a.length;
    ensureCapacityInternal(size + numNew);  // Increments modCount
    //挨个向后迁移
    System.arraycopy(a, 0, elementData, size, numNew);
    size += numNew;
    return numNew != 0;
}

public boolean addAll(int index, Collection<? extends E> c) {
    rangeCheckForAdd(index);

    Object[] a = c.toArray();
    int numNew = a.length;
    ensureCapacityInternal(size + numNew);  // Increments modCount

    int numMoved = size - index;
    //原来的数组挨个向后迁移
    if (numMoved > 0)
        System.arraycopy(elementData, index, elementData, index + numNew,
                         numMoved);

    System.arraycopy(a, 0, elementData, index, numNew);
    size += numNew;
    return numNew != 0;
}

查询,修改等操作,直接根据角标对数组操作,都很快

E elementData(int index) {
	return (E) elementData[index];
}

//获取
public E get(int index) {
	rangeCheck(index);
	//直接根据数组角标返回元素,快的一比
	return elementData(index);
}

//修改
public E set(int index, E element) {
	rangeCheck(index);
	E oldValue = elementData(index);

	//直接对数组操作
	elementData[index] = element;
	//返回原来的值
	return oldValue;
}

删除

以一个方法为例

//根据位置删除
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;
}

注意

支持 RandomAccess 的对象,遍历时使用 get 比 迭代器更快。

由于 ArrayList 继承自 RandomAccess, 而且它的迭代器都是基于 ArrayList 的方法和数组直接操作,所以遍历时 get 的效率要 >= 迭代器。

另外,由于 ArrayList 不是同步的,所以在并发访问时,如果在迭代的同时有其他线程修改了 ArrayList, fail-fast 的迭代器 Iterator/ListIterator 会报 ConcurrentModificationException 错。

因此我们在并发环境下需要外部给 ArrayList 加个同步锁,或者直接在初始化时用 Collections.synchronizedList 方法进行包装

List list = Collections.synchronizedList(new ArrayList(...));
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值