1.结构
数据结构一直是学习的一大重点,但在Java中它被封装的过于完美,以致于学习Java这么久都不清楚它到底是怎么用的.而且单纯学习数据结构容易学了又忘,所以特此学习了Java Collections Framewoek.
这个框架是java.util程序包的一部分,其中已经实现了大量的数据结构和算法.首先来看看Collection整个结构情况.
其中关于List接口的UML结构图如下:
其中的ArrayList,Vector,LinkedList为相应的实现类,我们在这里主要研究这3个类,使用的JDK版本是1.7.
2.源码分析
2.1 ArrayList
2.1.1 字段
private static final long serialVersionUID = 8683452581122892189L;
private static final int DEFAULT_CAPACITY = 10;
private static final Object[] EMPTY_ELEMENTDATA = {};
private transient Object[] elementData;
private int size;
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
在这里我把对字段的描述去掉了,这样显得篇幅少一点.
- serialVersionUID:实现java.io.Serializable类所需要的序列化的值.
- DEFAULT_CAPACITY:默认的集合大小为10
- EMPTY_ELEMENTDATA:空的数组
- size:数组中元素的数量,不是数组的大小
- MAX_ARRAY_SIZE:最大数组的大小
- elementData:存储元素的集合
在这里的elementData是一个Object[]对象,说明集合是通过数组的形式来存储的,在elementData前面有个transient限定符.
transient限定符说明在串行化时这个字段不保存到某个流中.这样可以节省空间,比如:elementData的长度为10,而其中保存的元素只有5个,那么序列化的时候会保存10个对象,这样就造成了浪费。
从两个序列化的方法可以看出,ArrayList类只保存元素本身,而不是数组.
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException{
// Write out element count, and any hidden stuff
int expectedModCount = modCount;
s.defaultWriteObject();
// Write out size as capacity for behavioural compatibility with clone()
s.writeInt(size);
// Write out all elements in the proper order.
for (int i=0; i<size; i++) {
s.writeObject(elementData[i]);
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
elementData = EMPTY_ELEMENTDATA;
// Read in size, and any hidden stuff
s.defaultReadObject();
// Read in capacity
s.readInt(); // ignored
if (size > 0) {
// be like clone(), allocate array based upon size not capacity
ensureCapacityInternal(size);
Object[] a = elementData;
// Read in all elements in the proper order.
for (int i=0; i<size; i++) {
a[i] = s.readObject();
}
}
}
当集合进行序列化操作的时候,会执行writeObject方法,该方法将集合大小以及每个元素保存了下来,当反序列化的时候,执行readObject将数据在组装到集合中.
2.1.2 构造器
public ArrayList(int initialCapacity) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
}
public ArrayList() {
super();
this.elementData = EMPTY_ELEMENTDATA;
}
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
size = elementData.length;
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
}
这其中有3个构造器,第一个构造器创建了一个指定大小的集合数组,第二个构造器创建了一个空的集合数组,第三个构造器创建一个带Collection集合的集合数组.
其中的Arrays.copyOf方法是将elementData中的元素复制到指定size的Object[]中.
2.1.3 add方法
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
ensureCapacityInternal()的功能是判断是否扩展数组大小.
elementData[size++] = e 将数据保存到Object[]数组中
private void ensureCapacityInternal(int minCapacity) {
if (elementData == EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
如果elementData为空,就在DEFAULT_CAPACITY和minCapacity中找一个最大的.
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
如果size+1的长度大于elementData.length的时候进行扩展.如果小于返回.
这里的modCount字段是继承AbstractList抽象类中的,主要用于Iterator迭代器中,到迭代器时会说明用途.
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
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);
}
在这个方法中,首先获取原始数组集合的大小,其中的oldCapacity >> 1 的意思是将oldCapacity 除以2,这意味着默认扩充的大小为原数组的一半.
最后的Arrays.copyOf(elementData, newCapacity);是将原Object[]数据copy到一个长度为newCapacity的新的Object[]中.
另一个add方法为:
public void add(int index, E element) {
rangeCheckForAdd(index);
ensureCapacityInternal(size + 1); // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
这其中先判断下表是否超出,判断是否需要扩充.
System.arraycopy(elementData, index, elementData, index + 1,size - index);将需要添加元素位置之后的元素向后移一位,elementData[index] = element;再将指定位置填充.最后size++
2.1.4 remove方法
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;
}
remove方法先获取oldValue(原来指定位置的元素),再计算出需要向前移动距离,最后移动.返回原始的值.
其中的elementData()如下:
E elementData(int index) {
return (E) elementData[index];
}
直接从集合中获取值
另一个remove方法为:
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;
}
这里使用迭代删除,故其消耗的时间和数组长度n成正比,其中的fastRemove()方法为:
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
}
也是跟上述类似的方法.
2.1.5 其他方法
trimToSize:将elementData数组大小变成同size(元素个数)一样大的Object[].
indexOf(index) : 通过迭代循环获取指定下表的元素.
toArray : 用过Arrays.copyOf方法复制一个数组集合返回
contains(object) : 是否包含指定元素
…
…
2.1.6 Iterator迭代器
public interface Collection<E> extends Iterable<E> {
public interface Iterable<T> {
/**
* Returns an iterator over a set of elements of type T.
*
* @return an Iterator.
*/
Iterator<T> iterator();
}
由于Collection接口继承Iterable接口,所以子类需要实现该方法,在ArrayList和AbstractList中都实现了iterator()方法.以下为ArrayList中的实现.
public Iterator<E> iterator() {
return new Itr();
}
public ListIterator<E> listIterator() {
return new ListItr(0);
}
public ListIterator<E> listIterator(int index) {
if (index < 0 || index > size)
throw new IndexOutOfBoundsException("Index: "+index);
return new ListItr(index);
}
这里需要两个类Itr和ListItr,这两个类用于进行elementData数组的迭代操作.
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
在Itr类中cursor代表指针,指向下一个元素的引用,lastRet代表上一次操作返回的元素,expectedModCount稍后再方法中描述.
public boolean hasNext() {
return cursor != size;
}
只要指向下一个元素的位置不为总集合元素长度返回true.
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
这里先检查一下下表是否找不到元素或者越界,cursor = i + 1 游标向后移.
elementData[lastRet = i];我对这种写法经过测试,和elementData[i]没有任何区别,不清楚为什么这么写.
在这其中的checkForComodification()方法 如下:
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
在前面Itr的字段中有expectedModCount = modCount.
在之前的ArrayList方法中,比如add,remove等有对集合进行修改的地方,第一个操作就是modCount++,而且这个modCount是共有的.
这说明在使用迭代器迭代的时候不允许操作数组集合,如果进行操作抛出ConcurrentModificationException()异常.
ListItr类继承Itr类,提供了一些其他的方法,比如:hasPrevious(),previous(),add(),等,实现方式和Itr类似.
2.1.6 subList()
SubList类中有个私有的AbstractList对象,现在不清楚这个方法是干什么用的.
2.2 Vector
Vector类和ArrayList类唯一的重要区别是Vector类的大多数方法是同步的.比如:
public synchronized boolean add(E e) {
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = e;
return true;
}