List接口是Java中常常用到的接口,若是對具體的List實現類的特性不瞭解的話,可能會致使程序性能的降低,下面從原理上簡單的介紹List的具體實現:java
能夠看到,List繼承了Collection接口,而Collection接口繼承了Iterable接口。其中還有AbstractCollection和AbstractList的實現,用於List對象的公共部分代碼的複用:數組
public interface List<E> extends Collection<E> { // Query Operations
public interface Collection<E> extends Iterable<E> { // Query Operations
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> { /** * Sole constructor. (For invocation by subclass constructors, typically * implicit.) */ protected AbstractList() { }
public abstract class AbstractCollection<E> implements Collection<E> { /** * Sole constructor. (For invocation by subclass constructors, typically * implicit.) */ protected AbstractCollection() { }
具體這三個接口定義的方法以下:安全
如今來看看List接口的具體特性:數據結構
一、Vector多線程
Vector類是經過數組實現的,支持線程的同步,即某一時刻只有一個線程可以寫Vector,避免多線程同時寫而引發的不一致性,但實現同步須要很高的花費,所以,訪問它的效率不是很高。併發
如今來看一下Vector的成員變量和其中部分的構造方法:app
public class Vector<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable { /** * The array buffer into which the components of the vector are * stored. The capacity of the vector is the length of this array buffer, * and is at least large enough to contain all the vector's elements. * * <p>Any array elements following the last element in the Vector are null. * * @serial */ protected Object[] elementData; /** * The number of valid components in this {@code Vector} object. * Components {@code elementData[0]} through * {@code elementData[elementCount-1]} are the actual items. * * @serial */ protected int elementCount; /** * The amount by which the capacity of the vector is automatically * incremented when its size becomes greater than its capacity. If * the capacity increment is less than or equal to zero, the capacity * of the vector is doubled each time it needs to grow. * * @serial */ protected int capacityIncrement; /** use serialVersionUID from JDK 1.0.2 for interoperability */ private static final long serialVersionUID = -2767605614048989439L; /** * Constructs an empty vector with the specified initial capacity and * capacity increment. * * @param initialCapacity the initial capacity of the vector * @param capacityIncrement the amount by which the capacity is * increased when the vector overflows * @throws IllegalArgumentException if the specified initial capacity * is negative */ public Vector(int initialCapacity, int capacityIncrement) { super(); if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); this.elementData = new Object[initialCapacity]; this.capacityIncrement = capacityIncrement; }
對數據結構有必定了解的人都知道,使用數組做爲存儲底層,當存儲空間不夠了的時候,是會從新分配一塊更大的內存空間,而後把原空間的數據所有都copy過去,最後釋放原空間,這樣會致使程序性能的降低,或者是GC的消耗(Vector是默認擴展1倍)。因此咱們對處理的數據量要有必定的預估,初始化Vector的時候指定容量大小。因爲對Vector全部動做都添加synchronized關鍵字,一樣會致使執行的性能降低。less
下面是對Vector添加元素的時候的代碼:dom
/** * Appends the specified element to the end of this Vector. * * @param e element to be appended to this Vector * @return {@code true} (as specified by {@link Collection#add}) * @since 1.2 */ public synchronized boolean add(E e) { modCount++; ensureCapacityHelper(elementCount + 1); elementData[elementCount++] = e; return true; }
/** * This implements the unsynchronized semantics of ensureCapacity. * Synchronized methods in this class can internally call this * method for ensuring capacity without incurring the cost of an * extra synchronization. * * @see #ensureCapacity(int) */ private void ensureCapacityHelper(int minCapacity) { int oldCapacity = elementData.length; if (minCapacity > oldCapacity) { Object[] oldData = elementData; int newCapacity = (capacityIncrement > 0) ? (oldCapacity + capacityIncrement) : (oldCapacity * 2); if (newCapacity < minCapacity) { newCapacity = minCapacity; } elementData = Arrays.copyOf(elementData, newCapacity); } }
二、Stack性能
Stack 類表示後進先出(LIFO)的對象堆棧。它經過五個操做對類 Vector 進行了擴展,一樣是線程安全的 ,容許將向量視爲堆棧。它提供了一般的 push 和 pop 操做,以及取堆棧頂點的 peek 方法、測試堆棧是否爲空的 empty 方法、在堆棧中查找項並肯定到堆棧頂距離的 search 方法。當操做的集合不存在元素的時候,拋出EmptyStackException。
public class Stack<E> extends Vector<E> { /** * Creates an empty Stack. */ public Stack() { }
三、ArrayList
一樣,ArrayList內部是經過數組實現的,它容許對元素進行快速隨機訪問。數組的缺點是每一個元素之間不能有間隔,當數組大小不知足時須要增長存儲能力,就要講已經有數組的數據複製到新的存儲空間中。當從ArrayList的中間位置插入或者刪除元素時,須要對數組進行復制、移動、代價比較高(ArrayList在內存不夠時默認是擴展50% + 1個)。所以,它適合隨機查找和遍歷,不適合插入和刪除。因爲沒有添加同步,因此是非線程安全的,執行效率也要比Vector高不少
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable { private static final long serialVersionUID = 8683452581122892189L; /** * The array buffer into which the elements of the ArrayList are stored. * The capacity of the ArrayList is the length of this array buffer. */ private transient Object[] elementData; /** * The size of the ArrayList (the number of elements it contains). * * @serial */ private int size; /** * Constructs an empty list with the specified initial capacity. * * @param initialCapacity the initial capacity of the list * @exception IllegalArgumentException if the specified initial capacity * is negative */ public ArrayList(int initialCapacity) { super(); if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); this.elementData = new Object[initialCapacity]; }
public void ensureCapacity(int minCapacity) { modCount++; int oldCapacity = elementData.length; if (minCapacity > oldCapacity) { Object oldData[] = elementData; int newCapacity = (oldCapacity * 3)/2 + 1; if (newCapacity < minCapacity) newCapacity = minCapacity; // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity); } }
四、LinkedList
LinkedList是用雙向鏈表結構存儲數據的,很適合數據的動態插入和刪除,隨機訪問和遍歷速度比較慢。另外,他還提供了List接口中沒有定義的方法,專門用於操做表頭和表尾元素,能夠看成堆棧、隊列和雙向隊列使用。
public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable { private transient Entry<E> header = new Entry<E>(null, null, null); private transient int size = 0; /** * Constructs an empty list. */ public LinkedList() { header.next = header.previous = header; }
Entry(E element, Entry<E> next, Entry<E> previous) { this.element = element; this.next = next; this.previous = previous; } }
總結:根據不一樣實現類的特性,選擇對應的數據結構,能提升程序的運行效率 。須要注意的是,一條線程在進行list列表元素迭代的時候,另一條線程若是想要在迭代過程當中,想要對元素進行操做的時候,好比知足條件添加新元素,會發生ConcurrentModificationException併發修改異常。固然後來版本的CopyOnWrite容器解決了該問題,後續會介紹。