ArrayList 分析

本文深入解析了ArrayList的实现原理,包括其继承体系、属性、构造函数、关键方法如add、get、remove,以及性能特点。ArrayList使用数组存储元素,支持快速随机访问和高效尾部添加,但中间操作较慢。

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

继承体系

ArrayList实现了List, RandomAccess, Cloneable, java.io.Serializable等接口。

ArrayList实现了List,提供了基础的添加、删除、遍历等操作。

ArrayList实现了RandomAccess,提供了随机访问的能力。

ArrayList实现了Cloneable,可以被克隆。

ArrayList实现了Serializable,可以被序列化。

源码解析

属性

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

    // 序列化id号
    private static final long serialVersionUID = 8683452581122892189L;

    // 默认容量
    private static final int DEFAULT_CAPACITY = 10;
    
   // 空数组,如果传入的容量为0时使用
    private static final Object[] EMPTY_ELEMENTDATA = {};
   
    // 空数组,传入容量时使用,添加第一个元素的时候会重新初始为默认容量大小
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    // 存储元素的数组
    transient Object[] elementData;
    // 集合中元素的个数 
    private int size;
}

(1)DEFAULT_CAPACITY

默认容量为10,也就是通过new ArrayList()创建时的默认容量。

(2)EMPTY_ELEMENTDATA

空的数组,这种是通过new ArrayList(0)创建时用的是这个空数组。

(3)DEFAULTCAPACITY_EMPTY_ELEMENTDATA

也是空数组,这种是通过new ArrayList()创建时用的是这个空数组,与EMPTY_ELEMENTDATA的区别是在添加第一个元素时使用这个空数组的会初始化为DEFAULT_CAPACITY(10)个元素。

(4)elementData

真正存放元素的地方,使用transient是为了不序列化这个字段。

至于没有使用private修饰,后面注释是写的“为了简化嵌套类的访问”,但是楼主实测加了private嵌套类一样可以访问。

private表示是类私有的属性,只要是在这个类内部都可以访问,嵌套类或者内部类也是在类的内部,所以也可以访问类的私有成员。

(5)size

真正存储元素的个数,而不是elementData数组的长度。

构造函数

ArrayList()

ArrayList(int initialCapacity)

ArrayList(Collection c)

 

ArrayList()

不传初始容量,初始化为DEFAULTCAPACITY_EMPTY_ELEMENTDATA空数组,

会在添加第一个元素的时候扩容为默认的大小,即10。

public ArrayList() {
        // 如果没有传入初始容量,则使用空数组DEFAULTCAPACITY_EMPTY_ELEMENTDATA
        // 使用这个数组是在添加第一个元素的时候会扩容到默认大小10
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

ArrayList(int initialCapacity)

传入初始容量,如果大于0就初始化elementData为对应大小,如果等于0就使用EMPTY_ELEMENTDATA空数组,如果小于0抛出异常。

public ArrayList(int initialCapacity) {
        
        
        if (initialCapacity > 0) {
            // 如果传入的初始容量大于0,就新建一个数组存储元素
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
           // 如果传入的初始容量等于0,使用空数组EMPTY_ELEMENTDATA
            this.elementData = EMPTY_ELEMENTDATA;
        } else {

           // 如果传入的初始容量小于0,抛出异常
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }

ArrayList(Collection c)构造方法

传入集合并初始化elementData,这里会使用拷贝把传入集合的元素拷贝到elementData数组中,如果元素个数为0,则初始化为EMPTY_ELEMENTDATA空数组。

 public ArrayList(Collection<? extends E> c) {
       // 集合转数组
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
            // 检查c.toArray()返回的是不是Object[]类型,如果不是,重新拷贝成Object[].class类型
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // 如果c的空集合,则初始化为空数组EMPTY_ELEMENTDATA
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

方法

add(E e)方法

(1)检查是否需要扩容

(2)如果elementData等于DEFAULTCAPACITY_EMPTY_ELEMENTDATA,也就是没有长度,则初始化容量大小为DEFAULT_CAPACITY,也就是10(new ArrayList<>()),  另外一种情况是初始化时elementData有长度(比如new ArrayList<>(2))

(3)新容量是老容量的1.5倍,如果加了这么多容量发现比需要的容量还小,则以需要的容量为准;

    正常情况下会扩容1.5倍,特殊情况下(新扩展数组大小已经达到了最大值)则只取最大值。

(4)创建新容量的数组并把老数组拷贝到新数组;

get(int index)方法

(1)检查索引是否越界,这里只检查是否越上界,如果越上界抛出IndexOutOfBoundsException异常,如果越下界抛出的是       ArrayIndexOutOfBoundsException异常。

(2)返回索引位置处的元素

remove(int index)方法

(1)检查索引是否越界;

(2)获取指定索引位置的元素;

(3)如果删除的不是最后一位,则其它元素往前移一位;

(4)将最后一位置为null,方便GC回收;

(5)返回删除的元素。

可以看到,ArrayList删除元素的时候并没有缩容。

总结

(1)ArrayList内部使用数组存储元素,当数组长度不够时进行扩容,每次加一半的空间,ArrayList不会进行缩容;

(2)ArrayList支持随机访问,通过索引访问元素极快,时间复杂度为O(1);

(3)ArrayList添加元素到尾部极快,平均时间复杂度为O(1);

(4)ArrayList添加元素到中间比较慢,因为要搬移元素,平均时间复杂度为O(n);

(5)ArrayList从尾部删除元素极快,时间复杂度为O(1);

(6)ArrayList从中间删除元素比较慢,因为要搬移元素,平均时间复杂度为O(n);

(7)ArrayList支持求并集,调用addAll(Collection c)方法即可;

(8)ArrayList支持求交集,调用retainAll(Collection c)方法即可;

(7)ArrayList支持求单向差集,调用removeAll(Collection c)方法即可;

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值