集合的体系结构
集合源码解析
- ArrayList
- LinkedList
- Vector
- CopyOnWriteArrayList
- HashMap
- HashTable
- ConcurrentHashMap
一:ArrayList的解读
数据机构
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
Arraylist是一个集合类,和vector一样都是继承类AbstractList类,而AbstractList类实现类List的接口;Arraylist还实现list类,Cloneable,Serializable接口支持克隆和序列化;实现了RandomAccess接口,其实 RandomAccess 接口是一个标志接口,他标志着“只要实现该接口的 List 类,都能实现快速随机访问”。
Arraylist和Vector底层都是基于数组实现,支持动态扩容;
特点:查询快,增删慢;
源码解析
/**
* Arraylist默认的初始容量是10
*/
private static final int DEFAULT_CAPACITY = 10;
/**
* 提供了一个空数组
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
* Shared empty array instance used for default sized empty instances. We
* distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
* first element is added.
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
* 数组对象;使用transient是为了防止对象数组被其他外部方法序列化。
* 由于 ArrayList 的数组是基于动态扩增的,所以并不是所有被分配的内存空间都存储了数据。如果采用外部序列化法实现数组的序列化,会序列化整个数组。ArrayList 为了避免这些没有存储数据的内存空间被序列化,内部提供了两个私有方法 writeObject 以及 readObject 来自我完成序列化与反序列化,从而在序列化与反序列化数组时节省了空间和时间。
*/
transient Object[] elementData; // non-private to simplify nested class access
/**
* 数组的大小
*
* @serial
*/
private int size;
构造函数:
/**
*若传入一个初始容量,则先判断该初始值是否为空:为空,则给数组赋值一个空数组;不为空,则创建一个该初始容量的对象数组;
*/
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);
}
}
/**
* 无参函数则给对象数组默认初始容量为10
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
/**
* Constructs a list containing the elements of the specified
* collection, in the order they are returned by the collection's
* iterator.
*
* @param c the collection whose elements are to be placed into this list
* @throws NullPointerException if the specified collection is null
*/
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
ArrayList的增加元素方法:
/** **添加元素到末尾**
*1,判断初始容量与传入的容量大小,返回最大值
*2,若传入容量超过初始容量则扩容,以1.5倍扩容,扩容后复制到新的对象数组中
*3,新的对象数组容量+1
*/
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
/**
*判断容量是否超出数组的元素长度,若超出则扩容
*/
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
/**
*以1.5倍扩容,然后创建一个新容量的对象数组,复制之前的数组到新的对象数组;
*/
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);
}
/**
*判断对象数组的容量与传进来的容量的大小,返回最大值
*/
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
/** 添加元素到某一位置
* 1,校验索引是否越界
* 2,判断是否需要扩容
* 3,把添加元素位置后的元素往后移一位
* 4,再把添加的元素存放在指定位置
*/
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++;
}
private void rangeCheckForAdd(int index) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
/**
* @param src the source array. 原数组
* @param srcPos starting position in the source array. 原数组开始的位置
* @param dest the destination array. 目标数组
* @param destPos starting position in the destination data. 目标数组开始的位置
* @param length the number of array elements to be copied. 复制的数组的数量
* @exception IndexOutOfBoundsException if copying would cause
* access of data outside array bounds.
* @exception ArrayStoreException if an element in the <code>src</code>
* array could not be stored into the <code>dest</code> array
* because of a type mismatch.
* @exception NullPointerException if either <code>src</code> or
* <code>dest</code> is <code>null</code>.
*/
public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);
总结:数组添加元素如果在不扩容,添加到数组末端执行效率最高;添加元素越靠前,消耗的成本越高;
Arraylist删除元素
/**
*1,判断索引是否越界
* 2,判断修改的次数是否与预计修改次数不一致,不一致则抛出并发修改异常
* 3,移除该索引
* 4,对象数组大小-1
*/
public E remove(int index) {
rangeCheck(index);
checkForComodification();
E result = parent.remove(parentOffset + index);
this.modCount = parent.modCount;
this.size--;
return result;
}
/**
*1,判断要删除的元素是否为空;为空则删除集合中为空的元素;不为空
再根据要删除的元素去匹配要删除所在的索引位置,调用fastRemove删除
**/
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;
}
/** 删除某一索引的元素
*1,先判断要删除的元素是否是在末尾
*2,如果不是末尾元素,则调用系统复制该索引的元素往后移一位
* 3,并把对象数组size-1
*/
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
}
final void checkForComodification() {
if (expectedModCount != ArrayList.this.modCount)
throw new ConcurrentModificationException();
}
温馨提示:如果在开发过程中使用集合删除元素,遍历元素再通过匹配删除元素会产生并发修改异常或者索引越界问题;如果想要了解如何代码实现删除元素能执行成功,请参考:java中集合删除元素操作实践与解析
Arraylist获取元素
/** 获取元素
* 1,判断索引是否越界
* 2,通过数组直接获取到该索引位置的元素
*/
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
E elementData(int index) {
return (E) elementData[index];
}
二:LinkedList
数据结构
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{
LinkedList