ArrayList详解


ArrayList


1.概述

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

  • ArrayList是用数组实现的线性列表,其是相当与动态数组。
  • ArrayList查找、修改速度较快,插入、删除速度较慢。
  • ArrayList可以存放任何元素,包括null对象。
  • ArrayList是线程不同步的。

ArrayList的类关系图如下:

 

2.详解

字段与构造函数

 1 private static final int DEFAULT_CAPACITY = 10;  // ArrayList默认容量
 2 transient Object[] elementData;  // ArrayList中存放元素的数组
 3 private int size;  // ArrayList存放元素的个数
 4 /**
 5  * 常量,代表ArrayList中没有元素。只有当使用有参的构造函数且initialCapatity为0时返回它。
 6  */
 7 private static final Object[] EMPTY_ELEMENTDATA = {};
 8 /**
 9  *常量,当使用无参构造函数时返回它。
10  */
11 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
12 /**
13  * 默认的构造函数:创建容量为10的ArrayList
14  */
15 public ArrayList(){
16     this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
17 }
18 /**
19  * 创建一个指定容量的ArrayList
20  * @param initialCapatity ArrayList的容量
21  */
22 public ArrayList(int initialCapatity){
23     if(initialCapatity > 0) {
24         this.elementData = new Object[initialCapatity];
25     }else if(initialCapatity == 0) {
26         this.elementData = EMPTY_ELEMENTDATA;
27     }else {
28         throw new IllegalArgumentException("Illegal Capatity" + inintCapatity);
29     }
30 }
31 /**
32  * 创建一个包含Collection的ArrayList
33  * @param @param c Collection
34  */
35 public ArrayList(Collection<? extends E> c){
36     elementData = c.toArray();
37     if((size = elementData.length) != 0){
38         // c.toArray might (incorrectly) not return Object[] (see 6260652)
39         if(elementData.getClass() != Object[].class){
40             elementData = Arrays.copyof(elementData, size, Object[].class);
41         }
42     }
43 }

一些方法

 1 public E get(int index){
 2     // 检查索引位置
 3     rangeCheck(index);
 4     return elementData[index];
 5 }
 6 public E set(int index, E element){
 7     // 检查索引位置
 8     rangeCheck(index); 
 9     E oldValue = elementData[index];
10     elementData[index] = element;
11     return oldValue;   
12 }
13 public boolean add(E e){
14     // 确保ArrayList有足够的容量:验证+扩容
15     ensureCapacityInternal(size + 1);
16     elementData[size++] = e;
17     return true;
18 }
19 public void add(int index, E element){
20     // 检查索引是否合适
21     rangeCheckForAdd(index);
22     // 确保ArrayList有足够的容量:验证+扩容
23     ensureCapatityInternal(size + 1);
24     // 把原数组从index后的每一个元素向后移一位
25     System.arraycopy(elementData,index,elementData,index+1,size-index);
26     elementData[index] = element;
27     size++;
28 }
29 public E remove(int index){
30     // 检查索引位置是否合适
31     rangeCheck(index);
32     modCount++;
33     E oldValue = elementData(index);
34     // 把原数组从index后的每一个元素向前移动一位
35     int numMoved = size - index - 1;
36     if(numMoved > 0){
37         System.arraycopy(elementData, index+1, elementData, index, numMoved);
38     }
39     elementData[--size] = null; //clear to let GC do its work
40     return oldValue;
41 }

扩容
在上面add()方法中我们都需要验证ArrayList容量是否足够,不足需要扩容。

 1 /**
 2  * 验证+扩容
 3  * @param minCapacity 现在ArrayList存放元素所需要的最小容量
 4  */
 5 private void ensureCapacityInternal(int minCapacity) {
 6     if(elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
 7         minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
 8     }
 9     ensureExplicitCapacity(minCapacity);
10 }
11 private void ensureExplicitCapacity(int minCapacity) {
12     modCount++;
13     if(minCapacity - elementData.length > 0){
14         // 扩容
15         grow(minCapacity);
16     }
17 }
18 /**
19  * 该方法是扩容:扩大至原来的1.5倍,我没有看懂怎么就扩大到原来的1.5倍~(0)~
20  */
21 private void grow(int minCapacity) {
22     // 扩大至原来的1.5倍
23     int oldCapacity = elementData.length;
24     int newCapacity = oldCapacity + (oldCapacity >> 1);
25     if(newCapacity - minCapacity < 0){
26         newCapacity = minCapacity;
27     }
28     if(newCapacity - MAX_ARRAY_SIZE > 0){
29         newCapacity = hugeCapacity(minCapacity);
30     }
31     // elementData扩容
32     elementData = Arrays.copyOf(elementData,newCapacity);
33 }

以上是部分源码分析。
还有几点:

  • 以上是JDK1.8的源码,其中怎么就扩大要原来的1.5倍,我没有看懂。而且为什么要扩大要原来的1.5倍我也不知道。之前版本是增加至(oldCapacity * 3)/2 + 1。
  • 从上面我们可以看出在插入、删除元素时我们需要调用System.arraycopy()方法,这就比较耗时,所以说ArrayList在插入、删除时的速度慢的原因。当然这是由于ArrayList底层使用数组这种数据结构的缘故。

3.自己模仿写的ArrayList

class ArrayList<E> extends AbstractList<E> implements List<E> {
    // 默认容量
    private static final int DEFAULT_CAPACITY = 10;
    // 存放元素数量
    private int size;
    // 存放元素的数组
    private Object[] elementData;

    ArrayList(){
        elementData = new Object[DEFAULT_CAPACITY];
    }

    ArrayList(int initCapacity){
        if(initCapacity > 0){
            elementData = new Object[initCapacity];
        }else {
            throw new IllegalArgumentException("Illegal Capacity" + initCapacity);
        }
    }

    ArrayList(Collection< ? extends E> c){
        elementData = c.toArray();
        this.size = elementData.length;
        if(size != 0){
            if(elementData.getClass() != Object[].class){
                elementData = copyOf(elementData,size,Object[].class);
            }
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public E get(int index) {
        check(index);
        return (E) elementData[index];
    }

    @Override
    public int size() {
        return size;
    }

    @Override
    public boolean add(E e) {
        ensureCapacity(size + 1);
        elementData[size] = e;
        size++;
        return true;
    }

    @Override
    public void add(int index, E element) {
        check(index);
        ensureCapacity(size + 1);
        System.arraycopy(elementData,index,elementData,index+1,size - index);
        elementData[index] = element;
        size++;
    }

    @Override
    public boolean remove(Object o) {
        for(int index = 0; index < size; index++){
            if(Objects.equals(o,elementData[index])){
                int numMoved = size - index - 1;
                if(numMoved > 0){
                    System.arraycopy(elementData, index + 1, elementData, index, numMoved);
                }
                elementData[size] = null;
                size--;
                return true;
            }
        }
        return false;
    }

    @Override
    @SuppressWarnings("unchecked")
    public E remove(int index) {
        check(index);
        E oldValue = (E) elementData[index];
        int numMoved = size - index - 1;
        if(numMoved > 0){
            System.arraycopy(elementData, index + 1, elementData, index, numMoved);
        }
        elementData[size] = null;
        size--;
        return oldValue;
    }

    @Override
    @SuppressWarnings("unchecked")
    public E set(int index, E element) {
        check(index);
        E oldValue = (E) elementData[index];
        elementData[index] = element;
        return oldValue;
    }

    // 验证索引
    private void check(int index){
        if(index < 0 || index > size){
            throw new IndexOutOfBoundsException("Index:" + index + "Size:" + size);
        }
    }
    // 验证+扩容
    private void ensureCapacity(int minCapacity){
        // 验证
        if(minCapacity > elementData.length){
            // 扩容
            int oldCapacity = elementData.length;
            int newCapacity = (int) (oldCapacity * 1.5);
            elementData =  Arrays.copyOf(elementData, newCapacity);
        }
    }
}
原文地址:https://www.cnblogs.com/maying3010/p/6484037.html