首先看下ArrayList的关系图
ArrayList 继承自AbstractList,实现了List 、RandomAccess、Cloneable、Serializable接口
点开List接口,你会发现我们常用的方法基本上都在这里,当然,实现都是在ArrayList当中。
再回到ArrayList的源码,我们会发现ArrayList的几大特点:
- ArrayList维护了一个动态的数组,可以增加或缩减其长度。
- ArrayList 是线性不安全的,在多线程中操作一个ArrayList需要手动保证数据的同步。
- 每个ArrayList实例维护了一个capacity的属性,顾名思义,就是集合的容量,且其值会随着数据的变化增长或者衰减。
ArrayList的两大精华
- 扩容
- Iterator
首先看下这几个属性
/**
* 默认的容器大小
*/
private static final int DEFAULT_CAPACITY = 10;
/**
*一个空的数组
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
在这里要清楚transient 的含义,被该属性修饰的变量不会被序列化
*/
transient Object[] elementData;
/**
* 元素长度
*
*/
private int size;
//这个属性来自AbstrctList 代表的含义是每当ArrayList的结构发生变化的时候 该变量+1;该属性同样使用了transient 修饰,因为没必要持久化。
protected transient int modCount = 0;
大精华之一:扩容:
最常见的add()方法
/**
* Appends the specified element to the end of this list.
*
* @param e element to be appended to this list
* @return <tt>true</tt> (as specified by {@link Collection#add})
*/
public boolean add(E e) {
//扩容
ensureCapacityInternal(size + 1); // Increments modCount!!
//赋值
elementData[size++] = e;
return true;
}
/**
* Increases the capacity of this <tt>ArrayList</tt> instance, if
* necessary, to ensure that it can hold at least the number of elements
* specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
*/
public void ensureCapacity(int minCapacity) {
//最小长度 如果数组不为空 最小即为0 否则为默认的10
int minExpand = (elementData != EMPTY_ELEMENTDATA)
// any size if real element table
? 0
// larger than default for empty table. It's already supposed to be
// at default size.
: DEFAULT_CAPACITY;
//如果需要的长度 即目标长度大于最小长度 说明需要扩容
if (minCapacity > minExpand) {
ensureExplicitCapacity(minCapacity);
}
}
private void ensureCapacityInternal(int minCapacity) {
//如果数组为空 最小容量取下面二者最大值
if (elementData == 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);
}
/**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
*/
//重点来了 此乃精华之一: 扩容
private void grow(int minCapacity) {
// overflow-conscious code
//旧集合的长度
int oldCapacity = elementData.length;
//新集合的长度 是旧集合长度的 大概1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
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);
}
//附带下copy方法
public static <T> T[] copyOf(T[] original, int newLength) {
return (T[]) copyOf(original, newLength, original.getClass());
}
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
T[] copy = ((Object)newType == (Object)Object[].class)
? (T[]) new Object[newLength]
: (T[]) Array.newInstance(newType.getComponentType(), newLength);
System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength));
return copy;
}
其实扩容也就在grow()方法中的几行代码 主要是对集合长度的控制。
大精华之二 Iterator:
最常见的listIterator()方法
/**
* Returns a list iterator over the elements in this list (in proper
* sequence), starting at the specified position in the list.
* The specified index indicates the first element that would be
* returned by an initial call to {@link ListIterator#next next}.
* An initial call to {@link ListIterator#previous previous} would
* return the element with the specified index minus one.
*
* <p>The returned list iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
*
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public ListIterator<E> listIterator() {
return listIterator(0);
}
public ListIterator<E> listIterator(final int index) {
rangeCheckForAdd(index);
return new ListItr(index);
}
ListItr是个什么鬼?原来是一个内部类,实现了ListIterator接口
private class ListItr extends Itr implements ListIterator<E> {
//把坐标传递进来
ListItr(int index) {
cursor = index;
}
public boolean hasPrevious() {
return cursor != 0;
}
public E previous() {
checkForComodification();
try {
int i = cursor - 1;
E previous = get(i);
lastRet = cursor = i;
return previous;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
public int nextIndex() {
return cursor;
}
public int previousIndex() {
return cursor-1;
}
public void set(E e) {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
AbstractList.this.set(lastRet, e);
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
public void add(E e) {
checkForComodification();
try {
int i = cursor;
AbstractList.this.add(i, e);
lastRet = -1;
cursor = i + 1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
}
//看完之后你会发现确实没什么东西 但是Iterator这个东西在很多地方都有用到,这里就显现出来接口的强大之处。
总结
看完ArrayList的源码之后,对ArrayList数据存储有了更深的理解,然而它的性能如何呢,要知道扩容和写数据都是需要时间的,经过测试,ArrayList在遍历和普通插入(add(object))的性能上都优于LinkedList。但是LinkedList在首尾进行操作的性能上明显优于ArrayList.