源码阅读:ArrayList源码

1 篇文章 0 订阅
1 篇文章 0 订阅

ArrayList源码

基于java 1.8

List存储一个有序元素合集

List接口的实现类有: ArrayList,LinkedList,Vector,Stack

ArrayList一个数组型的List

数组

transient Object[] elementData;

默认容量

private static final int DEFAULT_CAPACITY = 10;

构造函数

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

add方法

public boolean add(E e) {
    // 首先容量+1
    ensureCapacityInternal(size + 1); 
    // 把新元素加到最后
    elementData[size++] = e;
    return true;
}

private void ensureCapacityInternal(int 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);
}
  • ensureCapacityInternal(size + 1);确保内部容量,不够则扩容
  • 当前数组为空时,扩容的长度为默认容量大小
  • 当初始化没有设置容量时,第一次添加元素是需要扩容的

扩容

private void grow(int minCapacity) {
    // 原来的数组长度
    int oldCapacity = elementData.length;
    // 需要扩容的长度=原数组长度+0.5个原数组长度
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    // MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; 等于2^31-1-8
    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();
    // 2^31-1还是2^31-1-8
    return (minCapacity > MAX_ARRAY_SIZE) ?
        Integer.MAX_VALUE :
        MAX_ARRAY_SIZE;
}
  • 扩容的大小为原长度+1/2的原长度
  • 如果扩容长度比传入的最小容量小,则使用最小容量,如果扩容长度超过设定的最大容量,则实用最大正整数
  • 初始化默认长度为10,当添加到11个长度时,容量为15
  • copy方法调用的是System.arraycopy();

remove方法

public E remove(int index) {
    // 检查下标,是不是大于数组长度
    rangeCheck(index);

    modCount++;
    E oldValue = elementData(index);
    // 需要移动的元素 如:10个长度,需要删除的索引为3,算出需要移动的元素为6个
    int numMoved = size - index - 1;
    if (numMoved > 0)
        //参数为:原数组,原索引从第四个开始copy,新元素,目标索引,长度
        System.arraycopy(elementData, index+1, elementData, index,numMoved);
    // 设置最后一个元素为null
    elementData[--size] = null; 
    return oldValue;
}

private void rangeCheck(int index) {
    if (index >= size)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
  • System.arraycopy()方法中原数组和新数组设为同一个数组,可以实现数组元素间的移动
  • remove()方法设为null值的都是最后一个元素

clear方法

public void clear() {
    modCount++;
    // 循环把所有数组元素设置为null
    for (int i = 0; i < size; i++)
        elementData[i] = null;
    // size设置为0
    size = 0;
}

size方法

private int size;

public int size() {
    //ArrayList中的size变量
    return size;
}

isEmpty方法

public boolean isEmpty() {
    return size == 0;
}

subList内部类

private final AbstractList<E> parent;
private final int parentOffset;
private final int offset;
int size;

SubList(AbstractList<E> parent,
    int offset, int fromIndex, int toIndex) {
    // 原始ArrayList
    this.parent = parent;
    // 开始的索引
    this.parentOffset = fromIndex;
    // 偏移量
    this.offset = offset + fromIndex;
    // subList的长度
    this.size = toIndex - fromIndex;
    this.modCount = ArrayList.this.modCount;
} 
  • 在构造方法中this.parent = parent,意味着对象为原始list
  • this.parentOffset = fromIndex;和this.offset = offset + fromIndex;为原始索引
生成subList对象
public List<E> subList(int fromIndex, int toIndex) {
    //检查边界
    subListRangeCheck(fromIndex, toIndex, size);
    //生成的时SubList对象,注意this
    return new SubList(this, 0, fromIndex, toIndex);
}

static void subListRangeCheck(int fromIndex, int toIndex, int size) {
    if (fromIndex < 0)
        throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
    if (toIndex > size)
        throw new IndexOutOfBoundsException("toIndex = " + toIndex);
    if (fromIndex > toIndex)
        throw new IllegalArgumentException("fromIndex(" + fromIndex +") > toIndex(" + toIndex + ")");
}
add方法
public void add(int index, E e) {
    // 检查索引防止溢出
    rangeCheckForAdd(index);
    checkForComodification();
    // 原始ArraryList被添加一个元素
    parent.add(parentOffset + index, e);
    this.modCount = parent.modCount;
    this.size++;
}

private void rangeCheckForAdd(int index) {
    if (index < 0 || index > this.size)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
  • parent.add(parentOffset + index, e);原始list将被添加一个元素
  • remove方法中E result = parent.remove(parentOffset + index);将在原始list中移除
remove方法
public E remove(int index) {
    // 检查索引
    rangeCheck(index);
    checkForComodification();
    // 原始ArrayList将删除一个元素
    E result = parent.remove(parentOffset + index);
    this.modCount = parent.modCount;
    this.size--;
    return result;
}

结论:

  • 在操作sublist的添加、移除等方法的时候,原始list将会被修改
  • sublist是一个list的视图

结语

本人深知水平有限,欢迎指正本文错误之处。


logo

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值