ArrayList
基于数组实现,本质上是对象引用的一个变长数组,能够动态的增加或减小其大小。
不是线程安全的,只能用在单线程环境下。多线程环境下可以考虑用Collection.synchronizedList(List l)函数返回一个线程安全的ArrayList类,也可以使用concurrent并发包下的
CopyOnWriteArrayList类
下面直接贴ArrayList的Java实现,来源JDK1.8.0_25/src.zip。
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable{ //实现了RandomAccess接口,支持快速随机访问 //实现了Cloneable接口,能够被克隆 //实现了Serializable接口,支持序列化 private static final long serialVersionUID = 8683452581122892189L;//序列版本号 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;//ArrayList实际元素容量 //构造函数1---带容量大小的构造函数 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); } } //构造函数2---无参构造函数,不指定大小时,默认构造大小为10的数组 public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } //构造函数3---构造一个包含指定collection元素的列表,这些元素是按collection迭代器返回他们的顺序排列的 public ArrayList(Collection<? extends E> c) { elementData = c.toArray(); if ((size = elementData.length) != 0) { // c.toArray might (incorrectly) not return Object[] (see 6260652) //http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6260652 可查看bug库 if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, size, Object[].class); } else { // replace with empty array. this.elementData = EMPTY_ELEMENTDATA; } } //将当前容量设为实际容量 public void trimToSize() { modCount++;//fast-fail机制,访问中如果修改集合会抛出 ConcurrentModificationException 异常 if (size < elementData.length) { elementData = (size == 0)? EMPTY_ELEMENTDATA: Arrays.copyOf(elementData, size); } } //增加容量为minCapacity public void ensureCapacity(int minCapacity) { int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)?0:DEFAULT_CAPACITY; if (minCapacity > minExpand) { ensureExplicitCapacity(minCapacity); } } private void ensureCapacityInternal(int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } ensureExplicitCapacity(minCapacity); } private void ensureExplicitCapacity(int minCapacity) { modCount++; // overflow-conscious code if (minCapacity - elementData.length > 0) grow(minCapacity); } private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;//可分配的最大容量 //每次重新分配内存时,新的容量为旧的1.5倍 //但是如果分配后超过可以分配的内存范围分配Integer.MAX_VALUE大小 ,则比较要分配的和最大可分配的容量大小,如果大于分配Integer.MAX_VALUE,如果小于,分配最大容量大小 private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1);//设置新的容量 = 原始容量*1.5 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); } private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; } public int size() { return size; } //是否为空 public boolean isEmpty() { return size == 0; } //是否包含指定元素o public boolean contains(Object o) { return indexOf(o) >= 0; } //返回指定元素位置,若没有返回-1,查找的元素容许为null 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; } //返回最后一次出现的位置,若没有返回-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; } //克隆函数 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); } } public Object[] toArray() { return Arrays.copyOf(elementData, size); } @SuppressWarnings("unchecked") public <T> T[] toArray(T[] a) { if (a.length < size) // Make a new array of a's runtime type, but my contents: return (T[]) Arrays.copyOf(elementData, size, a.getClass()); System.arraycopy(elementData, 0, a, 0, size); if (a.length > size) a[size] = null; return a; } // Positional Access Operations @SuppressWarnings("unchecked") E elementData(int index) { return (E) elementData[index]; } /** * Returns the element at the specified position in this list. * * @param index index of the element to return * @return the element at the specified position in this list * @throws IndexOutOfBoundsException {@inheritDoc} */ public E get(int index) { rangeCheck(index); return elementData(index); } public E set(int index, E element) { rangeCheck(index); E oldValue = elementData(index); elementData[index] = element; return oldValue; } public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; } //指定位置添加元素,原来位置元素并没有消失,只是后移了一位,即将当前位于该位置的元素以及所有后续元素右移一个位置。 public void add(int index, E element) { rangeCheckForAdd(index); ensureCapacityInternal(size + 1); // Increments modCount!! //将 elementData中从Index位置开始、长度为size-index的元素,拷贝到从下标为index+1位置开始的新的elementData数组中 System.arraycopy(elementData, index, elementData, index + 1, size - index); elementData[index] = element; size++; } //去除指定位置元素,该位置后所有元素前移一位 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); elementData[--size] = null; // clear to let GC do its work return oldValue; } //移除列表首次出现的指定元素,如果不存在返回false 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 } public void clear() { modCount++; // clear to let GC do its work for (int i = 0; i < size; i++) elementData[i] = null; size = 0; } 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 += 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) System.arraycopy(elementData, index, elementData, index + numNew, numMoved); System.arraycopy(a, 0, elementData, index, numNew); size += numNew; return numNew != 0; } 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; }
ArrayList的构造方法有3种,参数可以指定容量大小,可以为空(此时会构造一个默认大小为10的空数组),也可以由集合c中的元素来初始化一个数组。
容量增长方法:
关于ArrayList的容量增长方法可以见grow()。ArrayList在每次增加元素时,都要间接调用该方法来确保容量。可分配最大容量为MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8
但是实际最大分配容量可能为 Integer.MAX_VALUE。
在增加元素的过程中,如果当前容量不足以容纳元素,就设置为新的容量为旧的容量的1.5倍左右,以前版本是
newCapacity = (oldCapacity * 3)/2 + 1;JDK1.8采用的方法是:
newCapacity = oldCapacity + (oldCapacity >> 1);主要是移位操作比乘法除法更快一些
如果扩容后的新容量依然不够,则直接设置新容量为传入的参数(minCapacity)。如果扩容后新的容量比容许的最大容量MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8还要大,则不管满不满足要求,设置容量为Integer.MAX_VALUE,这也是前面说容许最大分配容量为MAX_ARRAY_SIZE,但是实际最大分配容量可能为 Integer.MAX_VALUE的原因了。当然,最小分配的容量为默认容量10,即使指定分配容量小于10,也会分配容量10,
说明:
查找元素时,可以查找null元素索引,从源码中可以看到,查找元素时,是区分null和非null的
必须说明的是:扩容后,还要将原来的元素拷贝到一个新的数组中,非常的耗时,因此建议在事先知道元素数量的情况下,才使用ArrayList,否则建议使用LinkedList
ArrayList基于数组实现,那么可以通过下标索引直接查找指定位置的元素,因此查找效率高,但是在插入和删除元素的过程中,要大量移动元素,效率很低。
原文地址:http://blog.csdn.net/u010498696/article/details/45874685