Java ArrayList工作原理及源码浅析

来源:互联网 发布:新津知 编辑:程序博客网 时间:2024/04/30 07:02

关于Java集合的小抄中是这样描述的:

以数组实现。节约空间,但数组有容量限制。超出限制时会增加50%容量,用System.arraycopy()复制到新的数组,因此最好能给出数组大小的预估值。默认第一次插入元素时创建大小为10的数组。

按数组下标访问元素—get(i)/set(i,e) 的性能很高,这是数组的基本优势。

直接在数组末尾加入元素—add(e)的性能也高,但如果按下标插入、删除元素—add(i,e), remove(i), remove(e),则要用System.arraycopy()来移动部分受影响的元素,性能就变差了,这是基本劣势。

然后再来学习一下官方文档:

Resizable-array implementation of the List interface. Implements all optional list operations, and permits all elements, including null. In addition to implementing the List interface, this class provides methods to manipulate the size of the array that is used internally to store the list. (This class is roughly equivalent to Vector, except that it is unsynchronized.)

ArrayList是一个相对来说比较简单的数据结构,最重要的一点就是它的自动扩容,可以认为就是我们常说的“动态数组”。
来看一段简单的代码:

1
2
3
4
5
ArrayList<String> list =new ArrayList<String>();
list.add("语文: 99");
list.add("数学: 98");
list.add("英语: 100");
list.remove(0);

在执行这四条语句时,是这么变化的:

其中,add操作可以理解为直接将数组的内容置位,remove操作可以理解为删除index为0的节点,并将后面元素移到0处。


ArrayList 算是常用的集合之一了,不知作为javaner的你有没在百忙之中抽出一点时间看看ArrayList的源码呢。 如果看了,你会觉得其实ArrayList其实就那么一回事儿,对吧,下面就看看ArrayList的部分源码吧。

复制代码
  1 public class ArrayList<E> extends AbstractList<E>  2         implements List<E>, RandomAccess, Cloneable, java.io.Serializable  3 {  4     private static final long serialVersionUID = 8683452581122892189L;  5   6     //设置arrayList默认容量  7     private static final int DEFAULT_CAPACITY = 10;  8   9     //空数组,当调用无参数构造函数的时候默认给个空数组 10     private static final Object[] EMPTY_ELEMENTDATA = {}; 11  12     //这才是真正保存数据的数组 13     private transient Object[] elementData; 14  15     //arrayList的实际元素数量 16     private int size; 17  18     //构造方法传入默认的capacity 设置默认数组大小 19     public ArrayList(int initialCapacity) { 20         super(); 21         if (initialCapacity < 0) 22             throw new IllegalArgumentException("Illegal Capacity: "+ 23                                                initialCapacity); 24         this.elementData = new Object[initialCapacity]; 25     } 26  27     //无参数构造方法默认为空数组 28     public ArrayList() { 29         super(); 30         this.elementData = EMPTY_ELEMENTDATA; 31     } 32  33     //构造方法传入一个Collection, 则将Collection里面的值copy到arrayList 34     public ArrayList(Collection<? extends E> c) { 35         elementData = c.toArray(); 36         size = elementData.length; 37         // c.toArray might (incorrectly) not return Object[] (see 6260652) 38         if (elementData.getClass() != Object[].class) 39             elementData = Arrays.copyOf(elementData, size, Object[].class); 40     } 41      42     //下面主要看看ArrayList 是如何将数组进行动态扩充实现add 和 remove 43      44  45     public boolean add(E e) { 46         ensureCapacityInternal(size + 1);  // Increments modCount!! 47         elementData[size++] = e; 48         return true; 49     } 50  51      52     public void add(int index, E element) { 53         rangeCheckForAdd(index); 54  55         ensureCapacityInternal(size + 1);  // Increments modCount!! 56         System.arraycopy(elementData, index, elementData, index + 1, 57                          size - index); 58         elementData[index] = element; 59         size++; 60     } 61      62     private void ensureCapacityInternal(int minCapacity) { 63         if (elementData == EMPTY_ELEMENTDATA) { 64             minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); 65         } 66  67         ensureExplicitCapacity(minCapacity); 68     } 69      70     private void ensureExplicitCapacity(int minCapacity) { 71         modCount++; 72  73         //超出了数组可容纳的长度,需要进行动态扩展 74         if (minCapacity - elementData.length > 0) 75             grow(minCapacity); 76     } 77      78     //这才是动态扩展的精髓,看到这个方法,ArrayList瞬间被打回原形 79     private void grow(int minCapacity) { 80         int oldCapacity = elementData.length; 81         //设置新数组的容量扩展为原来数组的1.5倍 82         int newCapacity = oldCapacity + (oldCapacity >> 1); 83         //再判断一下新数组的容量够不够,够了就直接使用这个长度创建新数组,  84         //不够就将数组长度设置为需要的长度 85         if (newCapacity - minCapacity < 0) 86             newCapacity = minCapacity; 87         //判断有没超过最大限制 88         if (newCapacity - MAX_ARRAY_SIZE > 0) 89             newCapacity = hugeCapacity(minCapacity); 90         //将原来数组的值copy新数组中去, ArrayList的引用指向新数组 91         //这儿会新创建数组,如果数据量很大,重复的创建的数组,那么还是会影响效率, 92         //因此鼓励在合适的时候通过构造方法指定默认的capaticy大小 93         elementData = Arrays.copyOf(elementData, newCapacity); 94     } 95      96     private static int hugeCapacity(int minCapacity) { 97         if (minCapacity < 0) // overflow 98             throw new OutOfMemoryError(); 99         return (minCapacity > MAX_ARRAY_SIZE) ?100             Integer.MAX_VALUE :101             MAX_ARRAY_SIZE;102     }103       
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);
    // 把最后的置null
    elementData[--size] = null; // clear to let GC do its work
 
    return oldValue;
}
104 105 }
复制代码

其实, ArrayList 的本质就是数组, ArrayList就是对数组进行动态的扩展,其add, get , remove 等等操作就是对数组的操作。至此,你还需要去记书籍上面所描述的ArrayList的特性了嘛? 如果还要记,那就弱爆了!ArrayList的一些特性都来源于数组:有序、元素可重复、插入慢、 索引快 等等一系列神马所谓的属性, 你懂了么?有木有恍然大悟的感觉