ArrayList源码分析记录(JDK8)

ArrayList源码分析记录

小白发帖,可能有错误的地方,欢迎评论区斧正,求轻喷

ArrayList继承了AbstractList,并实现了List接口

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

1、成员变量

a、序列化的成员变量serialVersionUID
 private static final long serialVersionUID = 8683452581122892189L;
b、默认容量DEFAULT_CAPACITY, 空的ArrayList在第一次添加元素之后,容量变成默认容量
 private static final int DEFAULT_CAPACITY = 10;

​ ArrayList的默认容量为【10

c、空对象数组EMPTY_ELEMENTDATA,用于跟非空数组进行比较
private static final Object[] EMPTY_ELEMENTDATA = {};
d、默认的空对象数组DEFAULTCAPACITY_EMPTY_ELEMENTDATA,会在第一次添加元素的时候跟元素数组进行比较,以了解要进行的扩容大小
 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
e、真正存储元素的对象数组elementData,添加的元素实际上都会存在这个数组中
transient Object[] elementData;

transient关键字: transient用于修饰不需要序列化的字段,如果一个引用类型被transient修饰,则其反序列化的值为null,如果一个基本类型被transient修饰,则其反序列化的值为0,如果字段的引用类型是不可序列化的类,则也应该使用transient修饰,它在序列化时会被直接跳过, 也就是在流传输时该关键字修饰的变量不会传输过去。

为什么用transient修饰?
ArrayList在序列化的时候会调用自己内部的writeObject方法,直接将size和element写入ObjectOutputStream;反序列化时调用readObject方法,从ObjectInputStream获取size和element,再恢复到elementData。
为什么不直接用elementData来序列化,而采用上述的方式来实现序列化呢?原因在于elementData是一个缓存数组,它通常会预留一些容量,等容量不足时再扩充容量,那么有些空间可能就没有实际存储元素,采用上诉的方式来实现序列化时,就可以保证只序列化实际存储的那些元素,而不是整个数组,从而节省空间和时间。 

在这里插入图片描述
在这里插入图片描述

f、ArrayList的实际包含的元素数size
private int size;
g、修改因子 modCount = 0;该变量是父类AbstractList定义的,表示已对该列表进行结构修改的次数,实例中的列表每修改一次就进行一次modCount ++(无论是什么样的修改)
 protected transient int modCount = 0;
如果此字段的值意外更改,则迭代器(或列表迭代器)将抛出ConcurrentModificationException以响应next , remove , previous , set或add操作。 面对迭代期间的并发修改,这提供了fail-fast行为,而不是不确定的行为。

2、构造方法

a、构造一个初始容量的ArrayList实例public ArrayList(int initialCapacity)
 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);
        }
    }
b、构造一个初始容量为10的实例public ArrayList()
public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
c、构造一个包含指定集合的元素的实例public ArrayList(Collection<? extends E> c),其顺序由集合的迭代器返回
 public ArrayList(Collection<? extends E> c) {
     //先将集合对象转为数组并赋值给elementdata
        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;
        }
    }

3、成员方法

a、将实例中的多余的容量缩减为和元素数一样,去掉多余容量空间public void trimToSize(),节省空间
public void trimToSize() {
        modCount++;
        if (size < elementData.length) {
            elementData = (size == 0)
              ? EMPTY_ELEMENTDATA
              : Arrays.copyOf(elementData, size);
        }
    }

b、public void ensureCapacity(int minCapacity),在必要时对ArrayList进行扩容,以确保它至少可以容纳最小容量参数指定的元素数

public void ensureCapacity(int minCapacity) {
    //先对元素数组进行判断,是否为空数组(即未进行元素添加),不为空,minExpand取0,为空取默认容量10
        int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
            // any size if not default element table
            ? 0
            // larger than default for default empty table. It's already
            // supposed to be at default size.
            : DEFAULT_CAPACITY;
		//如果最小容量参数大于minExpand,则调用ensureExplicitCapacity方法进行扩容
        if (minCapacity > minExpand) {
            ensureExplicitCapacity(minCapacity);
        }
    }
c、私有方法private static int calculateCapacity(Object[] elementData, int minCapacity),返回传入的参数和默认容量10 之间较大的一个数
 private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }
d、私有方法private void ensureCapacityInternal(int minCapacity),确保是否使用了默认容量
private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }
e、确定最终的容量private void ensureExplicitCapacity(int minCapacity),真正调用了扩容方法的地方
private void ensureExplicitCapacity(int minCapacity) {
        modCount++;//扩容一次,修改因子就会自增1一次

        // overflow-conscious code
    //如果传入的参数比现有元素数组的length大(如果是第一次添加,添加之前现有数组的length为0),就会进行扩容
        if (minCapacity - elementData.length > 0)
            //进入扩容方法
            grow(minCapacity);
    }
f、真正的扩容方法private void grow(int minCapacity),确保数组动态扩容后能容纳元素
 private void grow(int minCapacity) {
        // overflow-conscious code
     //先拿到原始元素对象数组的length
        int oldCapacity = elementData.length;
     //扩容元素,如果为第一次添加元素,数组中没有元素,则oldCapacity值为0,如果为第11次添加元素,则oldCapacity为10(因为已经添加了10个元素到数组中了),此时扩容为newCapacity =原容量+原容量右移1位,每次扩容都会扩容为原容量+原容量右移1位
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
     //最大值判断,确保容量小于Integer的最大值
        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);
    }
g、返回当前list实例包含的元素个数public int size()
public int size() {
        return size;
    }
h、判断当前list是否为空public boolean isEmpty()
 public boolean isEmpty() {
        return size == 0;
    }
i、判断当前list是否包含某对象public boolean contains(Object o)
public boolean contains(Object o) {    return indexOf(o) >= 0;}
j、返回指定元素在此列表中首次出现的索引public int indexOf(Object o);如果此列表不包含该元素,则返回-1
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;
        }
    //如果都没有找到,说明该对象在list中不存在,返回-1
        return -1;
    }
k、返回指定元素在此列表中最后一次出现的索引public int lastIndexOf(Object o) ;如果此列表不包含该元素,则返回-1
 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;
    }
l、返回此ArrayList实例的浅表副本public Object clone()。 (元素本身不会被复制。)
 public Object clone() {
        try {
            ArrayList<?> v = (ArrayList<?>) super.clone();
            v.elementData = Arrays.copyOf(elementData, size);
            v.modCount = 0;
            return v;
        } catch (CloneNotSupportedException e) {
            // this shouldn't happen, since we are Cloneable
            throw new InternalError(e);
        }
    }
m、以正确的顺序(从第一个元素到最后一个元素)返回包含此列表中所有元素的数组public Object[] toArray()
 public Object[] toArray() {
        return Arrays.copyOf(elementData, size);
    }

​ 返回的数组将是“安全的”,因为此列表不保留对其的引用。 (换句话说,此方法必须分配一个新数组,即重新生成了一个数组对象实例)。 因此,调用者可以自由修改返回的数组。此方法充当基于数组的API和基于集合的API之间的桥梁。

n、返回list中指定位置的元素public E get(int index)
public E get(int index) {
    //先对传入的参数进行范围检查是否越界
        rangeCheck(index);

        return elementData(index);
    }
n1、用指定的元素替换此列表中指定位置的元素public E set(int index, E element)
public E set(int index, E element) {
    //先对传入的索引值进行越界判断
        rangeCheck(index);
	//获取要替换的位置的元素
        E oldValue = elementData(index);
    //将新元素赋值给要替换的元素的索引位置
        elementData[index] = element;
    //返回被替换的元素
        return oldValue;
    }
n2、将指定的元素追加到此列表的末尾public boolean add(E e)
 public boolean add(E e) {
     //先调用ensureCapacityInternal方法对数组容量进行判断,决定是否扩容,此时的size是列表中元素的个数,而非动态数组的容量
        ensureCapacityInternal(size + 1);  // Increments modCount!!size+1表示元素的个数增加1个,因此在进行判断时使用增加后的元素个数进行判断
     //关于容量的方法调用完毕后,将添加的元素追加到列表的末尾   
     elementData[size++] = e;
        return true;
    }

//关联方法
//确定容量的内置方法
 private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }

//判断当前动态数组的容量与添加1个元素后的size的大小,并返回较大的1个
private static int calculateCapacity(Object[] elementData, int minCapacity) {
    //如果是空数组,初始容量为0,返回默认的容量10(第一次添加时动态数组的length为0,即为空数组,只有数组中有元素后length才会有变化)
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }

//判断是否扩容的方法
 private void ensureExplicitCapacity(int minCapacity) {
     //每次对list的操作都会进入这个方法,并将修改因子进行自增
        modCount++;

        // overflow-conscious code
     //如果添加1个元素后的size大于动态数组原有的容量,就进入grow方法进行扩容(第一次添加时数组的length为0,在上面判断size+1与默认容量10的大小时会返回默认大小10),并将该minCapacity传入方法(此时minCapacity为10)
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

//真正实现扩容的方法
 private void grow(int minCapacity) {
        // overflow-conscious code
     //获取此时动态数组的容量,第一次添加时为0
        int oldCapacity = elementData.length;
     //扩容,每次扩容都为原容量+原容量右移1位
        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);
    }
n3、将指定的元素插入此列表中的指定位置public void add(int index, E element)。 将当前在该位置的元素(如果有)和任何后续元素右移(将其索引加一)
 public void add(int index, E element) {
     //索引检查,判断是否越界,是否小于0
        rangeCheckForAdd(index);
	//判断是否扩容,逻辑与add(E e)一样
        ensureCapacityInternal(size + 1);  // Increments modCount!!
     //判断扩容完成后,对数组进行复制,将当前在index位置的元素以及后面所有元素都往右移动1位(size-index既是要移动的所有元素数)
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
     //将index处的元素设为添加进来的元素,并将size自增1
        elementData[index] = element;
        size++;
    }
n4、删除此列表中指定位置的元素public E remove(int index)。 将所有后续元素向左移动(从其索引中减去一个)
 public E remove(int index) {
     //判断索引是否越界
        rangeCheck(index);
	//自增修改因子
        modCount++;
     //获取要删除位置的元素
        E oldValue = elementData(index);
	//拿到删除后要移动的元素个数
        int numMoved = size - index - 1;
        if (numMoved > 0)
            //复制欲删除元素后的所有元素,向左移动1位
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
     //将size自减并将最后一个元素置空
        elementData[--size] = null; // clear to let GC do its work
	//返回删除的元素
        return oldValue;
    }
n5、如果存在指定元素,则从列表中删除第一次出现的该元素public boolean remove(Object o)。 如果列表不包含该元素,则列表不变
public boolean remove(Object o) {
    //如果元素为空,则调用fastRemove删除第一个为空的元素
        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;
    }

//快速删除方法
 private void fastRemove(int index) {
     //删除也是使列表修改的一种方式,因此修改因子也是自增
        modCount++;
     //传入的index为要删除的元素的索引,下面的计算得到要删除元素的后面的所有元素个数
        int numMoved = size - index - 1;
        if (numMoved > 0)
            //复制动态数组
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
     //将size自减并将最后一个元素置空
        elementData[--size] = null; // clear to let GC do its work
    }

注意:remove不能用在遍历中,否则会因为线程安全问题抛出ConCurrentModifyException异常

n6、从此列表中删除所有元素public void clear()
 public void clear() {
        modCount++;

        // clear to let GC do its work
     //遍历列表中的元素,并将每个元素都置空,size置为0
        for (int i = 0; i < size; i++)
            elementData[i] = null;

        size = 0;
    }
n7、添加指定集合到list中public boolean addAll(Collection<? extends E> c)
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增加指定集合的元素数
        size += numNew;
        return numNew != 0;
    }
n8、从指定位置开始,将指定集合中的所有元素插入此列表public boolean addAll(int index, Collection<? extends E> c)
public boolean addAll(int index, Collection<? extends E> c) {
    //判断添加的索引是否越界,是否小于0
        rangeCheckForAdd(index);

        Object[] a = c.toArray();
        int numNew = a.length;
    //确定是否扩容,保障动态数组的容量足够添加
        ensureCapacityInternal(size + numNew);  // Increments modCount

        int numMoved = size - index;
        if (numMoved > 0)
            //将添加的索引位置后面的元素向后移动numMoved个
            System.arraycopy(elementData, index, elementData, index + numNew,
                             numMoved);
		//将元素添加到数组中
        System.arraycopy(a, 0, elementData, index, numNew);
    //修改size的值
        size += numNew;
        return numNew != 0;
    }
n9、从此列表中删除索引在fromIndex (包括)和toIndex (不包括)之间的所有元素protected void removeRange(int fromIndex, int toIndex)
 protected void removeRange(int fromIndex, int toIndex) {
        modCount++;
        int numMoved = size - toIndex;
        System.arraycopy(elementData, toIndex, elementData, fromIndex,
                         numMoved);

        // clear to let GC do its work
        int newSize = size - (toIndex-fromIndex);
        for (int i = newSize; i < size; i++) {
            elementData[i] = null;
        }
        size = newSize;
    }
o、从此列表中删除指定集合中包含的所有元素public boolean removeAll(Collection<?> c)
 public boolean removeAll(Collection<?> c) {
     //要求传入的参数必须不为空,否则报空指异常
        Objects.requireNonNull(c);
     //调用批量删除方法进行删除
        return batchRemove(c, false);
    }
p、仅保留此列表中指定集合中包含的元素public boolean retainAll(Collection<?> c)。 换句话说,从该列表中删除所有未包含在指定集合中的元素
 public boolean retainAll(Collection<?> c) {
        Objects.requireNonNull(c);
        return batchRemove(c, true);
    }
q、批量删除方法private boolean batchRemove(Collection<?> c, boolean complement)
 private boolean batchRemove(Collection<?> c, boolean complement) {
     //定义不可变对象数组并将list中的对象数组赋值给它
        final Object[] elementData = this.elementData;
        int r = 0, w = 0;
        boolean modified = false;
        try {
            for (; r < size; r++)
                //遍历元素,判断传入的集合是否包含定义的数组对象中的某个元素
                if (c.contains(elementData[r]) == complement)
                    //对数组对象进行操作
                    elementData[w++] = elementData[r];
        } finally {
            // Preserve behavioral compatibility with AbstractCollection,
            // even if c.contains() throws.
            if (r != size) {
                System.arraycopy(elementData, r,
                                 elementData, w,
                                 size - r);
                w += size - r;
            }
            if (w != size) {
                // clear to let GC do its work
                for (int i = w; i < size; i++)
                    elementData[i] = null;
                modCount += size - w;
                size = w;
                modified = true;
            }
        }
        return modified;
    }
r、从列表中的指定位置开始,以适当的顺序返回此列表中的元素的列表迭代器public ListIterator<E> listIterator(int index)。 指定的索引指示首次调用next将返回的第一个元素。 最初调用previous将返回指定索引减一的元素。
 public ListIterator<E> listIterator(int index) {
        if (index < 0 || index > size)
            throw new IndexOutOfBoundsException("Index: "+index);
     //返回的ListItr对象是ArrayList的内部类,继承自ArrayList另一个内部类Itr,实现了ListIterator接口,而Itr实现了Iterator接口
        return new ListItr(index);
    }
//上面的方法调用此对象的有参构造 
private class ListItr extends Itr implements ListIterator<E> {
        ListItr(int index) {
            //该有参构造调用了Itr类的无参构造
            super();
            //cursor是父类即Itr定义的变量,表示要返回的下一个元素的索引
            cursor = index;
        }
内部类Itr
private class Itr implements Iterator<E> {}//供元素遍历

Itr中的方法

//判断迭代列表中是否还有下一个元素 
public boolean hasNext() {
            return cursor != size;
        }

//获取迭代列表的下一个元素
 public E next() {
     //先检查是否发生了不可预知的引起modCount改变的行为,例如多线程访问,会抛出ConcurrentModificationException异常
            checkForComodification();
            int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
     //将当前列表中的数组对象赋值给新的elementData
            Object[] elementData = ArrayList.this.elementData;
     //如果遍历的索引大于元素的个数,会抛出异常
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
     //索引加1
            cursor = i + 1;
     //返回遍历的到的元素,并将此元素的索引赋值给lastRetsc
            return (E) elementData[lastRet = i];
        }

 public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                ArrayList.this.remove(lastRet);
                cursor = lastRet;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }
s、public void forEach(Consumer<? super E> action) forEach遍历
public void forEach(Consumer<? super E> action) {
        Objects.requireNonNull(action);
        final int expectedModCount = modCount;
        @SuppressWarnings("unchecked")
        final E[] elementData = (E[]) this.elementData;
        final int size = this.size;
        for (int i=0; modCount == expectedModCount && i < size; i++) {
            action.accept(elementData[i]);
        }
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
    }
t、根据由指定Comparator引起的顺序对该列表进行排序default void sort(Comparator<? super E> c),来自List接口方法
 public void sort(Comparator<? super E> c) {
        final int expectedModCount = modCount;
     //调用Arrays的sort方法对数组元素按传入的Comparator对象规则进行排序
        Arrays.sort((E[]) elementData, 0, size, c);
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
        modCount++;
    }
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值