ArrayList源码解析

ArrayList的继承结构

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

ArrayList的属性

// 底层数组默认的初始大小
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;
// 要分配数组的最大大小,这是JVM的限制,尝试分配更大的空间可能导致OutOfMemoryError错误
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
// 这个属性在ArrayList的直接父类AbstractList中定义,记录添加、删除操作的次数,用于在FailFast机制中保护并发环境下集合数据的安全
protected transient int modCount = 0;

ArrayList的构造器

无参构造器

分配一个空数组 DEFAULTCAPACITY_EMPTY_ELEMENTDATA

    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

有参构造器 ArrayList(int initialCapacity)

  1.   当自定义容量大于0时,分配指定大小的数组空间;
  2.   当自定义容量为0时,分配一个空数组 EMPTY_ELEMENTDATA;
  3.   当自定义容量小于0时,抛出IllegalArgumentException异常
  4.   需要注意的是,当试图分配超出MAX_ARRAY_SIZE的数组空间时,因为会被转化为int类型而导致溢出,成为一个负数,不会成功分配空间,而会抛出IllegalArgumentException异常
    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);
        }
    }

有参构造器 ArrayList(Collection<? extends E> c)

  1. 如果集合c是空的,则返回名为EMPTY_ELEMENTDATA的数组
  2. 如果集合c非空,则elementData指向c转化后的Object数组
    public ArrayList(Collection<? extends E> c) {
        Object[] a = c.toArray();
        if ((size = a.length) != 0) {
            if (c.getClass() == ArrayList.class) {
                elementData = a;
            } else {
                elementData = Arrays.copyOf(a, size, Object[].class);
            }
        } else {
            // replace with empty array.
            elementData = EMPTY_ELEMENTDATA;
        }
    }

方法

add(E e, Object[] elementData, int s)

  1. private的用于add(E object)
  2. 在s位置添加元素e,如果在尾部添加则对原数组进行扩容,再添加
    private void add(E e, Object[] elementData, int s) {
        if (s == elementData.length)
            elementData = grow();
        elementData[s] = e;
        size = s + 1;
    }

add(E object)

  1. 修改次数midCount+1
  2. 使用add(E e, Object[] elementData, int s)在尾部添加e
    public boolean add(E e) {
        modCount++;
        add(e, elementData, size);
        return true;
    }

add(int index, E element)

  1. 指在 index的位置 ,插入一个新元素。
  2. 从要插入的位置开始的所有数据,都要往先后挪一位;然后再把要插入的数据放进去。

rangeCheckForAdd(int index):如果添加位置大于原数组长度或小于0,则抛出IndexOutOfBoundsException(outOfBoundsMsg(index))异常。

    private void rangeCheckForAdd(int index) {
        if (index > size || index < 0)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

创建一个新数组elementData等于原数组,若elementData数组长度==s==size,则扩容。

之后进行数组copy在index左右两边复制后,最后在index添加element

    public void add(int index, E element) {
        rangeCheckForAdd(index);
        modCount++;
        final int s;
        Object[] elementData;
        if ((s = size) == (elementData = this.elementData).length)
            elementData = grow();
        System.arraycopy(elementData, index,
                         elementData, index + 1,
                         s - index);
        elementData[index] = element;
        size = s + 1;
    }

private Object[] grow() 

扩容方法

    private Object[] grow() {
        return grow(size + 1);
    }

private Object[] grow(int minCapacity)

private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    elementData = Arrays.copyOf(elementData, newCapacity);
}

默认情况下,扩容后新数组的大小为旧数组大小的1.5倍,把旧数组的内容拷贝到新数组中。

特殊情况下,如果扩容后的1.5倍容量newCapacity仍然小于所需的最小容量,则扩容后的新数组大小为所需的最小容量;如果扩容后的大小大于ArrayList的最大限定大小,则调用hugeCapacity函数处理。

private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // overflow
        throw new OutOfMemoryError();
    return (minCapacity > MAX_ARRAY_SIZE) ?
        Integer.MAX_VALUE :
    MAX_ARRAY_SIZE;
}

该函数会尝试分配更大的空间,如果所需的最小容量minCapacity未超过ArrayList设定的最大容量,则扩容后新数组的大小就为ArrayList设定的最大容量,否则也会分配长度为Integer.MAX_VALUE的新数组。在判断minCapacity与MAX_ARRAY_SIZE的大小之前,需要判断calculateCapacity函数计算得到的最小容量是否小于0,minCapacity是int类型,小于0表明已经溢出,即也超出了后面所要分配的最大空间大小Integer.MAX_VALUE,故而抛出OutOfMemoryError错误。

remove (int index)

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;
}

rangeCheck方法

private void rangeCheck(int index) {
    if (index >= size)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

remove (int index)方法,首先判断待删除的索引下标是否越界,如果越界则抛出IndexOutOfBoundsException异常,否则调用System.arrayCopy方法把待删除元素后面的元素依次向前移动1个索引距离,然后把数组的最后一个元素置为null,由GC机制回收内存空间,该方法返回被删除元素的值。

remove (Object o)

public boolean remove(Object o) {
    if (o == null) {
        for (int index = 0; index < size; index++)
            if (elementData[index] == null) {
                fastRemove(index);
                return true;
            }
    } else {
        for (int index = 0; index < size; index++)
            if (o.equals(elementData[index])) {
                fastRemove(index);
                return true;
            }
    }
    return false;
}

按对象删除,如果集合中有满足条件的对象,则把该对象的下标赋给fastRemove函数,调用fastRemove方法进行删除,并返回true,反则,返回false。

private void fastRemove(int index) {
    modCount++;
    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
}

fastRemove方法是基于下标删除,和remove (int index)方法逻辑相同,只不过这里的下标一定是正常的,不需要调用rangeCheck方法校验。

size()

public int size() {
    return size;
}

isEmpty

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

list.isEmpty和list == null的区别,list == null 表示没有指向具体的内存空间,而list.isEmpty表示指向了一块连续的存储空间,但这块存储空间还没有存储任何元素。

contains (Object o)

public boolean contains(Object o) {
    return indexOf(o) >= 0;
}

indexOf(Object o)

public int indexOf(Object o) {
    if (o == null) {
        for (int i = 0; i < size; i++)
            if (elementData[i]==null)
                return i;
    } else {
        for (int i = 0; i < size; i++)
            if (o.equals(elementData[i]))
                return i;
    }
    return -1;
}

从前往后找,找到符合条件的对象则返回索引,找不到返回-1。

lastIndexOf ()

public int lastIndexOf(Object o) {
    if (o == null) {
        for (int i = size-1; i >= 0; i--)
            if (elementData[i]==null)
                return i;
    } else {
        for (int i = size-1; i >= 0; i--)
            if (o.equals(elementData[i]))
                return i;
    }
    return -1;
}

从后往前找,找到符合条件的对象则返回索引,找不到返回-1。

get(int index)

public E get(int index) {
    rangeCheck(index);

    return elementData(index);
}

检查下标,如果合法则根据下标返回指定元素,否则,在rangeCheck方法中抛出IndexOutOfBoundsException异常。

set(int index, E element)

public E set(int index, E element) {
    rangeCheck(index);

    E oldValue = elementData(index);
    elementData[index] = element;
    return oldValue;
}

检查下标,如果合法则根据下标更新元素,并返回旧值,否则,在rangeCheck方法中抛出IndexOutOfBoundsException异常。

clear()

public void clear() {
    modCount++;

    // clear to let GC do its work
    for (int i = 0; i < size; i++)
        elementData[i] = null;

    size = 0;
}

iterator ()

public Iterator<E> iterator() {
    return new Itr();
}

返回一个Itr对象,Itr是ArrayList的内部类,实现了Iterator接口。

private class Itr implements Iterator<E>

Iterator提供了遍历的方法,Itr则对这些方法提供了具体实现,因此,iterator方法返回的是ArrayList的迭代器。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值