ArrayList源码解析

作者: Skymiles | 来源:发表于2017-01-12 15:13 被阅读121次

    ArrayList简介

    ArrayList是基于数组实现的,是一个动态数组,其容量能自动增长,类似于C语言中的动态申请内存,动态增长内存。
      ArrayList不是线程安全的,只能用在单线程环境下,多线程环境下可以考虑用Collections.synchronizedList(List l)函数返回一个线程安全的ArrayList类,也可以使用concurrent并发包下的CopyOnWriteArrayList类。

    ArrayList源码分析 (JDK 1.6)

    首先我们先分析一个List接口的实现类之一,也是最常用的ArrayList的源码。

    ArrayList底层使用一个数组完成数据的添加,查询,删除,修改。这个数组就是下面提到的elementData。

    这里分析的代码是基于jdk1.6的(加入了比较详细的注释)。限于篇幅有几个小方法没有列出,80%的代码都列出了。

    // MyArryList=ArrayList
    
    public class MyArrayList<T> extends AbstractList<T> implements List<T>, RandomAccess, Cloneable, Serializable {    
      private static final long serialVersionUID = -6268233918174116440L;    
      // ArrayList基于该数组实现,用该数组保存数据    
      private transient Object[] elementData;   
       // ArrayList中实际数据的数量    
      private int size;
    
    // ArrayList带容量大小的构造函数
    public MyArrayList(int initialCapacity) {    
      if (initialCapacity < 0)        
        throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
      elementData = new Object[initialCapacity];
    }
    
    // ArrayList无参构造函数。默认容量是10。
    public MyArrayList() {    
      this(10);
    }
    
    // 创建一个包含collection的ArrayList
    public MyArrayList(Collection<? extends T> c) {  
      elementData = c.toArray();    
      size = elementData.length;    
      // c.toArray方法可能不会返回一个Object[]结果,需要做一层判断。这个一个Java的bug,可以在http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6260652查看    
      if (elementData.getClass() != Object[].class)        
        elementData = Arrays.copyOf(elementData, size, Object[].class);
    }
    
    @Override
    public void trimToSize() {    
      modCount++;    
      int oldSize = elementData.length;    
      if (size < oldSize) 
      // 真实的size小于数组的大小        
        elementData = Arrays.copyOf(elementData, size);
    }
    
    @Override
    public void ensureCapacity(int minCapacity) {
        modCount++;    
        int oldCapacity = elementData.length;
        if (minCapacity > oldCapacity) {
            //新的容量=“(原始容量x3)/2 + 1” 
           int newCapacity = oldCapacity * 3 / 2 + 1; 
           //如果还不够,则直接将minCapacity设置为当前容量
           if (minCapacity > newCapacity)
              newCapacity = minCapacity;
              elementData = Arrays.copyOf(elementData, newCapacity);
        }
    }
    
    // 直接添加元素e
    @Override
    public boolean add(T e) {
        // 确定ArrayList的容量大小
        ensureCapacity(size + 1);  // Increments modCount!!
        // 添加e到ArrayList中
        elementData[size++] = e;
        return true;
    }
    
    // 将element添加到ArrayList的指定位置
    @Override
    public void add(int index, T element) {
        rangeCheckForAdd(index);
        ensureCapacity(size + 1);
        // System.arraycopy最终实现是native方法
        System.arraycopy(elementData, index, elementData, index + 1, size - index);
        elementData[index] = element;
        size++;
    }
    
    // 从index位置开始,将集合c全部添加到ArrayList
    public boolean addAll(int index, Collection<? extends T> c) {
        if (index > size || index < 0)
            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
        Object[] a = c.toArray();
        int numNew = a.length;
        ensureCapacity(size + numNew);  // Increments modCount
        int numMoved = size - index;
        if (numMoved > 0)
            System.arraycopy(elementData, index, elementData, index + numNew,                numMoved);
        System.arraycopy(a, 0, elementData, index, numNew);
        size += numNew;
        return numNew != 0;
    }
    
    // 删除ArrayList指定位置index的元素
    @Override
    public T remove(int index) {
        rangeCheck(index);
        modCount++;
        T oldVal = (T) elementData[index];
        int numMoved = size - index - 1;
        // 删除ArrayList中最后一个元素,是不会执行这个if的
        if (numMoved > 0)
            System.arraycopy(elementData, index + 1, elementData, index, numMoved);
        elementData[--size] = null;     // Let gc do its work
        return oldVal;
    }
    
    // 删除ArrayList的指定元素
    @Override
    public boolean remove(Object o) {
        if (o == null) {
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                    remove(index);  //JDK 1.6版本实际上用了fastRemove(int index). 这个和remove(int index)区别就是没有了rangeCheck步骤                
                    return true;
        }
        } else {
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {
                    remove(index);  //JDK 1.6版本实际上用了fastRemove(int index). 这个和remove(int index)区别就是没有了rangeCheck步骤
                    return true;
                }
        }
        return false;
    }
    
    @Override
    public void clear() {
        modCount++;
        for (int i = 0; i < elementData.length; i++)
            elementData[i] = null;
        size = 0;
    }
    
    @Override
    public T get(int index) {
        rangeCheck(index);
        return (T) elementData[index];
    }
    
    @Override
    public T set(int index, T element) {
        rangeCheck(index);
        T oldData = (T) elementData[index];
        elementData[index] = element;
        return oldData;
    }
    
    @Override
    protected Object clone() throws CloneNotSupportedException {
        try {
            MyArrayList<T> cloned = (MyArrayList<T>) super.clone();
            cloned.elementData = Arrays.copyOf(elementData, size);
            cloned.modCount = 0;
            return cloned;
        } catch (CloneNotSupportedException e) {
            // this shouldn't happen, since we are Cloneable
            throw new InternalError();
        }
    }
    
    @Override
    public int size() {
        return size;
    }
    
    // ArrayList是否包含Object(o)
    public boolean contains(Object o) {
        return indexOf(o) >= 0;
    }
    
    //返回ArrayList是否为空
    public boolean isEmpty() {
        return size == 0;
    }
    
    // 正向查找,返回元素的索引值
    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;
    }
    
    // 返回ArrayList的Object数组
    public Object[] toArray() {
        return Arrays.copyOf(elementData, size);
    }
    
    // 返回ArrayList元素组成的数组
    public <T> T[] toArray(T[] a) {
        // 若数组a的大小 < ArrayList的元素个数;
        // 则新建一个T[]数组,数组大小是“ArrayList的元素个数”,并将“ArrayList”全部拷贝到新数组中
        if (a.length < size)
            return (T[]) Arrays.copyOf(elementData, size, a.getClass());
        // 若数组a的大小 >= ArrayList的元素个数;
        // 则将ArrayList的全部元素都拷贝到数组a中。
        System.arraycopy(elementData, 0, a, 0, size);
        if (a.length > size)
            a[size] = null;
        return a;
    }
    
    private void rangeCheckForAdd(int index) {
        if (index > size || index < 0)
            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
    }
    
    private void rangeCheck(int index) {
        if (index >= size)
            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
    }
    
    // 迭代器实现
    public Iterator<T> iterator() {
        return new Itr();
    }
    
    private class Itr implements Iterator<T> {
        int cursor;       // index of next element to return 下一个将要返回的元素的下表
        int lastRet = -1; // index of last element returned; -1 if no such 上一个返回的元素的下表, -1表示没有
        int expectedModCount = modCount;    // fast-fail机制
    
        // 是否还有元素
        @Override
        public boolean hasNext() {
            // 由于cursor是将要返回元素的索引,也就是下一个元素的索引,和size比较是否相等,也就是判断是否已经next到最后一个元素
            return cursor != size();
        }
    
        // 下一个元素
        @Override
        public T next() {
            checkForComodification();
            // i=下一个元素索引
            int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
            Object[] elementData = MyArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;
            lastRet = i;
            return (T) elementData[lastRet];
        }
    
        // 将迭代器返回的元素删除
        @Override
        public void remove() {
            if (lastRet == -1)
                throw new IllegalStateException();
            checkForComodification();
            try {
                MyArrayList.this.remove(lastRet);
                cursor = lastRet;            // 重置为-1,不能连续两次调用remove()
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }
    
        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
      }
    }
    

    ArrayList注意点

    • 当数据量很大的时候, ArrayList内部操作元素的时候会移动位置,很耗性能

    • ArrayList虽然可以自动扩展长度,但是数据量一大,扩展的也多,会造成很多空间的浪费

    • ArrayList允许加入null元素

    • ArrayList支持3种遍历方式
      (01) 第一种,通过迭代器遍历。即通过Iterator去遍历。

    Integer value = null;
    Iterator iter = list.iterator();
    while (iter.hasNext()) {
      value = (Integer)iter.next();
    }

    (02) 第二种,随机访问,通过索引值去遍历。由于ArrayList实现了RandomAccess接口,它支持通过索引值去随机访问元素。

    Integer value = null;
    int size = list.size();
    for (int i=0; i<size; i++) {
      value = (Integer)list.get(i);
    }

    (03) 第三种,for循环遍历。如下:

    Integer value = null;
    for (Integer i:list) {
      value = i;
    }

    遍历ArrayList时,使用随机访问(即,通过索引序号访问)效率最高,而使用迭代器的效率最低!!!

    相关文章

      网友评论

      • 廖先生有料:Integer value = null;
        int size = list.size();
        for (int i=0; i<size; i++) {
          value = (Integer)list.get(i);
        }
        这段不是顺序访问么 :fearful:
        Skymiles:@坐天观井 ArrayList是数组实现的,数组就是随机访问的。不像LinkedList是要拿任意index元素都要从头节点一直next去找

      本文标题:ArrayList源码解析

      本文链接:https://www.haomeiwen.com/subject/lxbdbttx.html