java集合源码分析之ArrayList

源码分析以JDK1.8为例.

ArrayList就是动态数组,就是Array的复杂版本.它提供了动态的增加和减少元素,实现了Collection和List接口,灵活的设置数组的大小等好处.UML图如下:
《java集合源码分析之ArrayList》

源码解读

公共属性

    
    //默认容量
    private static final int DEFAULT_CAPACITY = 10;

    // 空数据
    private static final Object[] EMPTY_ELEMENTDATA = {};

    //默认容量空数组
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    //保存数据的数组
    transient Object[] elementData; 

    //元素个数
    private int size;

   //最大数组长度
   //一些虚拟机会在数组头部保存头信息,占用更多空间,导致OOM
   private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

无参构造器

//初始化一个空数组
public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

int 构造器

指定初始容量,大于0直接初始化;等于0初始化一个空数组,小于0抛出异常。

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

集合构造器

集合参数转化为对象数组赋值给元素集合,如果有元素判断集合类型,如果不是Object[] 执行集合复制转化为Object[].
没有元素直接返回空集合.

public ArrayList(Collection<? extends E> c) {
        //转化为数组
        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 {
            //初始化为空集合
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

有一个注释,c.toArray 可能不会返回Object[].让参考bug编号6260652.到oracle 官网查看bug
https://bugs.java.com/bugdatabase/view_bug.do?bug_id=6260652

大意就是Arrays.asList 创建集合,再调用toArray返回的对象不是Object[]类型。测试一下看看:

public void test(){
        List<Integer> obj = new ArrayList<>();
        obj.add(32);
        obj.add(344);
        List<Integer> ls = new ArrayList<>(obj);
        System.out.println(ls.size());
        Object[] c = obj.toArray();
        System.out.println(c.getClass());
        System.out.println(Object[].class);
        //Arrays.asList创建
        List<Integer> d = Arrays.asList(3,2,3);
        System.out.println(d.toArray().getClass());
    }
2
class [Ljava.lang.Object;
class [Ljava.lang.Object;
class [Ljava.lang.Integer;

可见Arrays.asList 返回的是Integer[],并非Object[].
查看Arrays相关源码

    //初始化ArrayList
    @SafeVarargs
    @SuppressWarnings("varargs")
    public static <T> List<T> asList(T... a) {
        return new ArrayList<>(a);
    }

此处的ArrayList为Arrays的内部类.

private static class ArrayList<E> extends AbstractList<E>
        implements RandomAccess, java.io.Serializable
    {
        private static final long serialVersionUID = -2764017481108945198L;
        //泛型数组
        private final E[] a;
        
        //初始化
        ArrayList(E[] array) {
            a = Objects.requireNonNull(array);
        }

        @Override
        public int size() {
            return a.length;
        }
        
        //调用a的clone方法
        @Override
        public Object[] toArray() {
            return a.clone();
        }

        @Override
        @SuppressWarnings("unchecked")
        public <T> T[] toArray(T[] a) {
            int size = size();
            if (a.length < size)
                return Arrays.copyOf(this.a, size,
                                     (Class<? extends T[]>) a.getClass());
            System.arraycopy(this.a, 0, a, 0, size);
            if (a.length > size)
                a[size] = null;
            return a;
        }
}

官方显示,JDK9已经解决。
扩展一下,查看数组的clone方法,length属性的实现.

    public void test(){
        int [] a = {1,2,3};
        System.out.println(a.length);
    }

    public  static  void test2(){
        Integer[] f = {3,4};
        f.clone();

    }

查看byte code

public class com.xwolf.ArrayListTest {
  public com.xwolf.ArrayListTest();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public void test();
    Code:
       0: iconst_3
       1: newarray       int
       3: dup
       4: iconst_0
       5: iconst_1
       6: iastore
       7: dup
       8: iconst_1
       9: iconst_2
      10: iastore
      11: dup
      12: iconst_2
      13: iconst_3
      14: iastore
      15: astore_1
      16: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
      19: aload_1
      20: arraylength
      21: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
      24: return

  public static void test2();
    Code:
       0: iconst_2
       1: anewarray     #4                  // class java/lang/Integer
       4: dup
       5: iconst_0
       6: iconst_3
       7: invokestatic  #5                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      10: aastore
      11: dup
      12: iconst_1
      13: iconst_4
      14: invokestatic  #5                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      17: aastore
      18: astore_0
      19: aload_0
      20: invokevirtual #6                  // Method "[Ljava/lang/Integer;".clone:()Ljava/lang/Object;
      23: pop
      24: return

  public static void main(java.lang.String[]);
    Code:
       0: invokestatic  #7                  // Method test2:()V
       3: return
}

此处不展开,arraylength、invokevirtual参考官网java虚拟机规范https://docs.oracle.com/javase/specs/jvms/se8/html/index.html.

add方法


//List后追加元素
public boolean add(E e) {
        //扩容
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

 private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(ca lculateCapacity(elementData, minCapacity));
    }
//计算容量,元素为空返回默认容量和容量的最大值
 private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
        } 

//扩容到指定容量,修改次数modCount加1
 private void ensureExplicitCapacity(int minCapacity) {
        //增加修改次数
        modCount++;
        
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

private void grow(int minCapacity) {
        //old容量为元素数组的元素个数
        int oldCapacity = elementData.length;
        // 扩容至 old + (old/2)
        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);
    }

    //大容量,容量值小于0抛出异常,容量值大于最大数组长度返回Integer的最大值2^31-1
    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }    

add(int index, E element)

//指定位置添加元素
public void add(int index, E element) {
        //边界检查
        rangeCheckForAdd(index);
        //扩容
        ensureCapacityInternal(size + 1); 
        
        //将指定位置后的元素复制到扩容后的元素集合中
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        //指定位置赋值                 
        elementData[index] = element;
        size++;
    }

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

    /* @param      src      the source array.
     * @param      srcPos   starting position in the source array.
     * @param      dest     the destination array.
     * @param      destPos  starting position in the destination data.
     * @param      length   the number of array elements to be copied.
     */
    //将src的srcPos的连续length个元素复制到dest的destPos的连续位置(替换)
    public static native void arraycopy(Object src,  int  srcPos,
                                        Object dest, int destPos,
                                        int length);

add 集合

public boolean addAll(Collection<? extends E> c) {
        Object[] a = c.toArray();
        int numNew = a.length;
        ensureCapacityInternal(size + numNew);  // Increments modCount
        //将集合元素追加到elementData后
        System.arraycopy(a, 0, elementData, size, numNew);
        size += numNew;
        return numNew != 0;
    }

指定位置添加集合

public boolean addAll(int index, Collection<? extends E> c) {
        //边界检查
        rangeCheckForAdd(index);

        Object[] a = c.toArray();
        int numNew = a.length;
        //扩容
        ensureCapacityInternal(size + numNew);  // Increments modCount
        //计算要移动的元素数量
        int numMoved = size - index;
        if (numMoved > 0)
            //先将指定位置后的元素copy移动后指定位置的元素
            System.arraycopy(elementData, index, elementData, index + numNew,
                             numMoved);
        //将空出来的元素用添加的集合参数赋值
        System.arraycopy(a, 0, elementData, index, numNew);
        size += numNew;
        return numNew != 0;
    }

上图,更直观一点:

《java集合源码分析之ArrayList》

remove 指定索引位置的元素

public E remove(int index) {
        //边界检查
        rangeCheck(index);
        //增加修改次数
        modCount++;
        //获取指定索引位置的元素
        E oldValue = elementData(index);
        //需要移动的元素的数量
        int numMoved = size - index - 1;
        if (numMoved > 0)
            //将index后的元素向前移动一位
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        //size减1,最后一个元素赋值null,等待GC处理                     
        elementData[--size] = null; // clear to let GC do its work
        //返回删除的元素
        return oldValue;
    }

remove指定的元素

//遍历删除指定的元素
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;
    }

//快速移除
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
    }

set

public E set(int index, E element) {
       //边界检查
        rangeCheck(index);
        
        E oldValue = elementData(index);
        //赋新值
        elementData[index] = element;
        return oldValue;
    }

get

public E get(int index) {
        //边界检查
        rangeCheck(index);
        //返回指定索引元素
        return elementData(index);
    }

indexOf

//遍历获取第一个元素的索引,找不到返回-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;
        }
        return -1;
    }

contains

//索引大于0即为包含指定元素
public boolean contains(Object o) {
        return indexOf(o) >= 0;
    }

trimToSize

将容量和实际数组元素个数保持一致,删除扩容的null元素.


public void trimToSize() {
        modCount++;
        if (size < elementData.length) {
            elementData = (size == 0)
              ? EMPTY_ELEMENTDATA
              : Arrays.copyOf(elementData, size);
        }
    }

retainAll

获取两个集合的交集


 public boolean retainAll(Collection<?> c) {
        Objects.requireNonNull(c);
        return batchRemove(c, true);
    }

private boolean batchRemove(Collection<?> c, boolean complement) {
        
        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.
            //如果循环异常中断,正常情况下r==size
            if (r != size) {
                System.arraycopy(elementData, r,
                                 elementData, w,
                                 size - r);
                w += size - r;
            }
            //如果w!=size ,将w后的元素赋值为null
            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;
    }

iterator

迭代


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


 private class Itr implements Iterator<E> {
        int cursor;       // index of next element to return
        int lastRet = -1; // index of last element returned; -1 if no such
        int expectedModCount = modCount;
        
        //是否还有下一个元素
        public boolean hasNext() {
            return cursor != size;
        }
        
        //获取下一个元素
        @SuppressWarnings("unchecked")
        public E next() {
            checkForComodification();
            int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;
            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();
            }
        }

        @Override
        @SuppressWarnings("unchecked")
        public void forEachRemaining(Consumer<? super E> consumer) {
            Objects.requireNonNull(consumer);
            final int size = ArrayList.this.size;
            int i = cursor;
            if (i >= size) {
                return;
            }
            final Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length) {
                throw new ConcurrentModificationException();
            }
            while (i != size && modCount == expectedModCount) {
                consumer.accept((E) elementData[i++]);
            }
            // update once at end of iteration to reduce heap write traffic
            cursor = i;
            lastRet = i - 1;
            checkForComodification();
        }
        //检查修改
        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }

subList


public List<E> subList(int fromIndex, int toIndex) {
        subListRangeCheck(fromIndex, toIndex, size);
        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 + ")");
    }


      //内部类
       SubList(AbstractList<E> parent,
                int offset, int fromIndex, int toIndex) {
            this.parent = parent;
            this.parentOffset = fromIndex;
            this.offset = offset + fromIndex;
            this.size = toIndex - fromIndex;
            this.modCount = ArrayList.this.modCount;
        }

sort

只需要知道sort内部是归并排序和Tim Sort即可.此处不展开详细的排序算法.

public void sort(Comparator<? super E> c) {
        final int expectedModCount = modCount;
        Arrays.sort((E[]) elementData, 0, size, c);
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
        modCount++;
    }

    public static <T> void sort(T[] a, int fromIndex, int toIndex,
                                Comparator<? super T> c) {
        if (c == null) {
            sort(a, fromIndex, toIndex);
        } else {
            rangeCheck(a.length, fromIndex, toIndex);
            if (LegacyMergeSort.userRequested)
                legacyMergeSort(a, fromIndex, toIndex, c);
            else
                TimSort.sort(a, fromIndex, toIndex, c, null, 0, 0);
        }
    }   
     
     // legacyMergeSort
     private static <T> void legacyMergeSort(T[] a, int fromIndex, int toIndex,
                                            Comparator<? super T> c) {
        T[] aux = copyOfRange(a, fromIndex, toIndex);
        if (c==null)
            mergeSort(aux, a, fromIndex, toIndex, -fromIndex);
        else
            mergeSort(aux, a, fromIndex, toIndex, -fromIndex, c);
    }
     //mergeSort  归并排序
     private static void mergeSort(Object[] src,
                                  Object[] dest,
                                  int low,
                                  int high,
                                  int off) {
        int length = high - low;

        // Insertion sort on smallest arrays
        if (length < INSERTIONSORT_THRESHOLD) {
            for (int i=low; i<high; i++)
                for (int j=i; j>low &&
                         ((Comparable) dest[j-1]).compareTo(dest[j])>0; j--)
                    swap(dest, j, j-1);
            return;
        }

        // Recursively sort halves of dest into src
        int destLow  = low;
        int destHigh = high;
        low  += off;
        high += off;
        int mid = (low + high) >>> 1;
        mergeSort(dest, src, low, mid, -off);
        mergeSort(dest, src, mid, high, -off);

        // If list is already sorted, just copy from src to dest.  This is an
        // optimization that results in faster sorts for nearly ordered lists.
        if (((Comparable)src[mid-1]).compareTo(src[mid]) <= 0) {
            System.arraycopy(src, low, dest, destLow, length);
            return;
        }

        // Merge sorted halves (now in src) into dest
        for(int i = destLow, p = low, q = mid; i < destHigh; i++) {
            if (q >= high || p < mid && ((Comparable)src[p]).compareTo(src[q])<=0)
                dest[i] = src[p++];
            else
                dest[i] = src[q++];
        }
    }


    ///TimSort.sort
    static <T> void sort(T[] a, int lo, int hi, Comparator<? super T> c,
                         T[] work, int workBase, int workLen) {
        assert c != null && a != null && lo >= 0 && lo <= hi && hi <= a.length;

        int nRemaining  = hi - lo;
        if (nRemaining < 2)
            return;  // Arrays of size 0 and 1 are always sorted

        // If array is small, do a "mini-TimSort" with no merges
        if (nRemaining < MIN_MERGE) {
            int initRunLen = countRunAndMakeAscending(a, lo, hi, c);
            binarySort(a, lo, hi, lo + initRunLen, c);
            return;
        }

        /**
         * March over the array once, left to right, finding natural runs,
         * extending short natural runs to minRun elements, and merging runs
         * to maintain stack invariant.
         */
        TimSort<T> ts = new TimSort<>(a, c, work, workBase, workLen);
        int minRun = minRunLength(nRemaining);
        do {
            // Identify next run
            int runLen = countRunAndMakeAscending(a, lo, hi, c);

            // If run is short, extend to min(minRun, nRemaining)
            if (runLen < minRun) {
                int force = nRemaining <= minRun ? nRemaining : minRun;
                binarySort(a, lo, lo + force, lo + runLen, c);
                runLen = force;
            }

            // Push run onto pending-run stack, and maybe merge
            ts.pushRun(lo, runLen);
            ts.mergeCollapse();

            // Advance to find next run
            lo += runLen;
            nRemaining -= runLen;
        } while (nRemaining != 0);

        // Merge all remaining runs to complete sort
        assert lo == hi;
        ts.mergeForceCollapse();
        assert ts.stackSize == 1;
    }

总结

  • 初始容量为10
  • 动态扩容容量为 old + old/2
  • 随机查找效率较高
  • 插入和删除慢,需要移动元素
  • 排序用归并排序和TimSort
  • 动态删除元素会抛出异常,可用迭代器实现
  • 线程不安全

参考

如有错误,欢迎批评指正,望不吝赐教!!!

    原文作者:xwolf
    原文地址: https://www.cnblogs.com/xwolf/p/9964533.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞