ArrayList源码解析(JDK1.8)

一.简介

ArrayList 是 Java 集合框架中 List 接口的一个实现类。底层是数组,相当于动态数组。与 Java 中的数组相比,它的容量能动态增长。

ArrayListVector的翻版,区别在于ArrayList是线程不安全的,而Vector则是线程安全的。但是Vector是一个较老的集合,具有很多缺点,不建议使用,这里我们就不对其进行分析了。

ArrayList 可以说是我们使用最多的 List 集合,它有以下特点:

  • 它是基于数组实现的List类
  • 可以动态地调整容量
  • 有序的(元素输出顺序与输入顺序一致)
  • 元素可以为 null
  • 不同步,非线程安全,效率高
  • 查询快,增删慢
  • 占用空间更小,对比 LinkedList,不用占用额外空间维护链表结构

二.继承关系图

在这里插入图片描述

可以看到,ArrayListAbstractList的子类,同时实现了List接口。除此之外,它还实现了三个标识型接口,这几个接口都没有任何方法,仅作为标识表示实现类具备某项功能。RandomAccess表示实现类支持快速随机访问,Cloneable表示实现类支持克隆,具体表现为重写了clone方法,java.io.Serializable则表示支持序列化,如果需要对此过程自定义,可以重写writeObjectreadObject方法。

三.成员变量

// 序列号
private static final long serialVersionUID = 8683452581122892189L;
// 数组初始容量为 10
private static final int DEFAULT_CAPACITY = 10;
// 空对象数组
private static final Object[] EMPTY_ELEMENTDATA = {
   };
// 缺省空对象数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {
   };
// 底层数据结构,数组
transient Object[] elementData;
// 数组元素个数,默认为0
private int size;
// 最大数组容量
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

四.构造方法

//默认构造方法,初始为空数组。
//只有插入一条数据后才会扩展为10,而实际上默认是空的
public ArrayList() {
   
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

//根据指定容量创建对象数组
public ArrayList(int initialCapacity) {
   
    if (initialCapacity > 0) {
   
        //创建initialCapacity大小的数组
        this.elementData = new Object[initialCapacity];
    } else if (initialCapacity == 0) {
   
        //创建空数组
        this.elementData = EMPTY_ELEMENTDATA;
    } else {
   
        throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
    }
}

/**
 * 构造一个包含指定集合的元素的列表,按照它们由集合的迭代器返回的顺序。
 */
public ArrayList(Collection<? extends E> c) {
   
    //转换最主要的是toArray(),这在Collection中就定义了
    elementData = c.toArray();
    if ((size = elementData.length) != 0) {
   
        // c.toArray 有可能不返回一个 Object 数组
        if (elementData.getClass() != Object[].class)
            //使用 Arrays.copy 方法拷创建一个 Object 数组
            elementData = Arrays.copyOf(elementData, size, Object[].class);
    } else {
   
        // 替换为空数组
        this.elementData = EMPTY_ELEMENTDATA;
    }
}

以无参数构造方法创建 ArrayList 时,实际上初始化赋值的是一个空数组。当真正对数组进行添加元素操作时,才真正分配容量。即向数组中添加第一个元素时,数组容量扩为10。

五.内部类

private class Itr implements Iterator<E>  
private class ListItr extends Itr implements ListIterator<E>  
private class SubList extends AbstractList<E> implements RandomAccess  
static final class ArrayListSpliterator<E> implements Spliterator<E>  

ArrayList有四个内部类,其中的Itr是实现了Iterator接口,同时重写了里面的hasNext()next()remove() 等方法;其中的ListItr 继承 Itr,实现了ListIterator接口,同时重写了hasPrevious()nextIndex()previousIndex()previous()set(E e)add(E e) 等方法,所以这也可以看出了 Iterator和ListIterator的区别:ListIterator在Iterator的基础上增加了添加对象,修改对象,逆向遍历等方法,这些是Iterator不能实现的。

六.核心方法

1.add()方法(有四个)

增和删是ArrayList最重要的部分,这部分代码需要我们细细研究

//添加一个特定的元素到list的末尾
public boolean add(E e) {
   
    //先确保elementData数组的长度足够,size是数组中数据的个数,因为要添加一个元素,所以size+1,先判断size+1的这个个数数组能否放得下,在这个方法中去判断数组长度是否够用
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    //在数据中正确的位置上放上元素e,并且size++
    elementData[size++] = e;
    return true;
}

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

    //先确保elementData数组的长度足够
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    //将数据整体向后移动一位,空出位置之后再插入,效率不太好
    System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
    elementData[index] = element;
    size++;
}

// 校验插入位置是否合理
private void rangeCheckForAdd(int index) {
   
    //插入的位置肯定不能大于size 和小于0
    if (index > size || index < 0)   
        //如果是,就报越界异常
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

//添加一个集合
public boolean addAll(Collection<? extends E> c) {
   
    //把该集合转为对象数组
    Object[] a = c
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值