ArrayList
功能
完全命名
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable
簡介
實現List接口的可調整大小的數組,這是個非線程安全的實現,如果需要線程安全,可以使用 List list = Collections.synchronizedList(new ArrayList(...)); 來包裝。
方法
// 將ArrayList實例的容量調整爲列表的當前大小。應用程序可以使用此操作最小化ArrayList實例的存儲 public void trimToSize() // 增加這個ArrayList實例的容量 public void ensureCapacity(int minCapacity) // 返回列表中元素的數目。 public int size() // 如果此列表不包含任何元素,則返回true。 public boolean isEmpty() // 如果此列表包含至少一個指定的元素,則返回true。 public boolean contains(Object o) // 返回該列表中指定元素第一次出現的索引,如果該列表不包含該元素,則返回-1。 public int indexOf(Object o) // 返回此列表中指定元素的最後一次出現的索引,如果此列表不包含該元素,則返回-1。 public int lastIndexOf(Object o) // 返回此ArrayList實例的淺拷貝。 public Object clone() // 返回一個數組,該數組按適當的順序(從第一個元素到最後一個元素)包含列表中的所有元素。返回的數組將是“安全的”,因爲這個列表不維護對它的引用。(換句話說,這個方法分配一個新數組)。因此,調用者可以自由地修改返回的數組。 public Object[] toArray() // 返回一個數組,該數組按適當的順序包含列表中的所有元素(從第一個元素到最後一個元素);返回數組的運行時類型是指定數組的運行時類型。 public <T> T[] toArray(T[] a) // 返回列表中指定位置的元素。 public E get(int index) // 將列表中指定位置的元素替換爲指定元素。 public E set(int index, E element) // 將指定的元素追加到此列表的末尾。 public boolean add(E e) // 將指定元素插入到列表中的指定位置,然後將當前位於該位置的元素和任何後續元素向右移動。 public void add(int index, E element) // 刪除列表中指定位置的元素,然後將任何後續元素向左移動 public E remove(int index) // 從該列表中刪除指定元素的第一個匹配項(如果存在)。如果列表不包含該元素,它將保持不變。 public boolean remove(Object o) // 從列表中刪除所有元素。該調用返回後,列表將爲空。 public void clear() // 將指定集合中的所有元素按照順序追加到此列表的末尾。 public boolean addAll(Collection<? extends E> c) // 從指定位置開始,將指定集合中的所有元素插入此列表。指定位置的元素以及後續元素都將向後移動。 public boolean addAll(int index, Collection<? extends E> c) // 從該列表中刪除其索引在fromIndex(包含)和toIndex(不包含)之間的所有元素。任何後續元素向左移動。 protected void removeRange(int fromIndex, int toIndex) // 從此列表中移除指定集合中包含的所有元素。 public boolean removeAll(Collection<?> c) // 僅保留此列表中包含在指定集合中的元素。換句話說,從這個列表中刪除指定集合中不包含的所有元素。 public boolean retainAll(Collection<?> c) // 從列表中的指定位置開始,返回此列表中元素的列表迭代器(按適當的順序)。 public ListIterator<E> listIterator(int index) // 返回此列表中元素的列表迭代器 public ListIterator<E> listIterator() // 按適當的順序對列表中的元素返回一個迭代器。 public Iterator<E> iterator() // 返回指定的fromIndex(包含)和toIndex(不包含)之間的列表視圖。習慣用法:從列表刪除一部分元素( list.subList(from, to).clear(); ) public List<E> subList(int fromIndex, int toIndex) // 爲可迭代的每個元素執行給定的操作,直到處理完所有元素或操作引發異常。 public void forEach(Consumer<? super E> action) // 在此列表中的元素上創建延遲綁定和快速故障的 Spliterator。 public Spliterator<E> spliterator() // 刪除此集合中滿足給定謂詞的所有元素。迭代期間或由謂詞拋出的錯誤或運行時異常將傳遞給調用者。 public boolean removeIf(Predicate<? super E> filter) // 將此列表中的每個元素替換爲將操作符應用於該元素的結果。操作符拋出的錯誤或運行時異常將傳遞給調用者。 public void replaceAll(UnaryOperator<E> operator) // 根據制定的規則對列表進行排序 public void sort(Comparator<? super E> c)
原理
添加
public boolean add(E e) { // 確保能容納新元素 ensureCapacityInternal(size + 1); // Increments modCount!! // 確保無誤後,插入數組最後的位置。這裏的size既起到了下標的作用,也起到了記錄元素數量的作用。 elementData[size++] = e; return true; } // 這裏的minCapacity實際上是預期需要的最小容量。 private void ensureCapacityInternal(int minCapacity) { // 先去計算容量(如果此時數組爲空,則在默認容量大小和minCapacity之間選個最大的;否則直接返回minCapacity) // 然後進入ensureExplicitCapacity方法 ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)); } private void ensureExplicitCapacity(int minCapacity) { // 這個列表在結構上被修改的次數 +1 modCount++; // 如果需要的容量大於當前容量,則執行擴容 if (minCapacity - elementData.length > 0) grow(minCapacity); } private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; // 新容量 = 老容量 + 老容量/2(左移操作,等價於oldCapacity/2^1)。也就是說,新容量是老容量的1.5倍 int newCapacity = oldCapacity + (oldCapacity >> 1); // 如果新容量小於需要的最小容量,新容量等於需要的最小容量 if (newCapacity - minCapacity < 0) newCapacity = minCapacity; // 如果新容量大於數組最大容量(MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8),則針對大容量做一個處理 if (newCapacity - MAX_ARRAY_SIZE > 0) // 如果minCapacity爲負數,拋出內存溢出異常;否則minCapacity = Integer.MAX_VALUE newCapacity = hugeCapacity(minCapacity); // minCapacity is usually close to size, so this is a win: // minCapacity通常最接近實際大小,這是個勝利,奧利給!! // 執行數組複製,根據newCapacity創建一個新數組,然後把老數據複製進來,返回新數組 elementData = Arrays.copyOf(elementData, newCapacity); }
刪除
public boolean remove(Object o) { if (o == null) { // 刪除一個null值,遍歷數組,找到第一個匹配的,刪除返回true for (int index = 0; index < size; index++) if (elementData[index] == null) { fastRemove(index); return true; } } else { // 刪除一個非null值,遍歷數組,找到第一個匹配的,刪除返回true for (int index = 0; index < size; index++) if (o.equals(elementData[index])) { fastRemove(index); return true; } } return false; } private void fastRemove(int index) { // 數組在結構上修改次數 +1 modCount++; // 刪除要移動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 } // 從指定的源陣列(從指定位置開始)複製陣列到目標陣列的指定位置。數組組件的子序列從src引用的源數組複製到dest引用的目標數組,複製的組件數量等於長度參數。 public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
最後那個本地方法畫圖解釋
contains
public boolean contains(Object o) { // 實際上調用的是indexOf return indexOf(o) >= 0; } public int indexOf(Object o) { if (o == null) { // 如果爲null,遍歷尋找第一個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; }
ForEach
public void forEach(Consumer<? super E> action) { Objects.requireNonNull(action); final int expectedModCount = modCount; @SuppressWarnings("unchecked") final E[] elementData = (E[]) this.elementData; final int size = this.size; // forEach內部實際上也是for循環遍歷,把每一個對象交給我們定義的處理方法處理 for (int i=0; modCount == expectedModCount && i < size; i++) { action.accept(elementData[i]); } if (modCount != expectedModCount) { throw new ConcurrentModificationException(); } }
優缺點
優點:查詢快,但是僅限於按照index查找,其它的比如contains,是遍歷查找。
缺點:添加和刪除慢,要移動元素。
LinkedList
功能
完全命名
public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, Serializable
簡介
實現了List和Deque接口的雙鏈表。這是非線程安全的,如果需要,可以使用 List list = Collections.synchronizedList(new LinkedList(...)); 來包裝
方法
// 返回列表第一個元素 public E getFirst() // 返回列表最後一個元素 public E getLast() // 移除並返回列表第一個元素 public E removeFirst() // 移除並返回列表最後一個元素 public E removeLast() // 將指定的元素插入此列表的開頭。 public void addFirst(E e) // 將指定的元素追加到此列表的末尾。這個方法等價於add(E)。 public void addLast(E e) // 如果此列表包含至少一個指定的元素,則返回true。 public boolean contains(Object o) // 返回列表中元素的數目。 public int size() // 將指定的元素追加到此列表的末尾。 public boolean add(E e) // 從該列表中刪除指定元素的第一個匹配項(如果存在)。如果列表不包含該元素,它將保持不變。 public boolean remove(Object o) // 將指定集合中的所有元素按照順序追加到此列表的末尾。 public boolean addAll(Collection<? extends E> c) // 從指定位置開始,將指定集合中的所有元素插入此列表。 public boolean addAll(int index, Collection<? extends E> c) // 從列表中刪除所有元素。該調用返回後,列表將爲空。 public void clear() // 返回列表中指定位置的元素。 public E get(int index) // 將列表中指定位置的元素替換爲指定元素。 public E set(int index, E element) // 將指定元素插入到列表中的指定位置。 public void add(int index, E element) // 刪除列表中指定位置的元素。 public E remove(int index) // 返回該列表中指定元素第一次出現的索引,如果該列表不包含該元素,則返回-1。 public int indexOf(Object o) // 返回此列表中指定元素的最後一次出現的索引,如果此列表不包含該元素,則返回-1。 public int lastIndexOf(Object o) // 檢索但不刪除此列表的頭(第一個元素)。 public E peek() // 檢索但不刪除此列表的頭(第一個元素)。 public E element() // 檢索並刪除此列表的頭(第一個元素)。 public E poll() // 檢索並刪除此列表的頭(第一個元素)。 public E remove() // 將指定的元素添加爲此列表的末尾(最後一個元素)。 public boolean offer(E e) // 將指定的元素插入此列表的開頭。 public boolean offerFirst(E e) // 將指定的元素插入此列表的末尾。 public boolean offerLast(E e) // 檢索但不刪除此列表的第一個元素,或在此列表爲空時返回null。 public E peekFirst() // 檢索但不刪除此列表的最後一個元素,或在此列表爲空時返回null。 public E peekLast() // 檢索並刪除此列表的第一個元素,如果該列表爲空,則返回null。 public E pollFirst() // 檢索並刪除此列表的最後一個元素,如果此列表爲空,則返回null。 public E pollLast() // 將元素推入此列表所表示的堆棧。換句話說,將元素插入到列表的前面。這個方法相當於addFirst(E)。 public void push(E e) // 從該列表表示的堆棧中彈出一個元素。換句話說,刪除並返回這個列表的第一個元素。這個方法相當於removeFirst()。 public E pop() // 刪除此列表中指定元素的第一個匹配項(在從頭到尾遍歷列表時)。如果列表不包含該元素,它將保持不變。 public boolean removeFirstOccurrence(Object o) // 刪除此列表中指定元素的最後一次出現(在從頭到尾遍歷列表時)。如果列表不包含該元素,它將保持不變。 public boolean removeLastOccurrence(Object o) // 從列表中的指定位置開始,返回此列表中元素的列表迭代器(按適當的順序)。列表迭代器是【快速失敗】的:如果列表在迭代器創建後的任何時候在結構上被修改(除了通過列表迭代器自己的刪除或添加方法),列表迭代器將拋出ConcurrentModificationException。 public ListIterator<E> listIterator(int index) // 以相反的順序返回deque中元素的迭代器。元素將按從最後(尾)到第一個(頭)的順序返回。 public Iterator<E> descendingIterator() // 返回該鏈表的淺拷貝。 public Object clone() // 返回一個數組,該數組按適當的順序(從第一個元素到最後一個元素)包含列表中的所有元素。返回的數組將是“安全的”,因爲這個列表不維護對它的引用。(換句話說,這個方法分配一個新數組)。因此,調用者可以自由地修改返回的數組。 public Object[] toArray() // 返回一個數組,該數組按適當的順序包含列表中的所有元素(從第一個元素到最後一個元素);返回數組的運行時類型是指定數組的運行時類型。 public <T> T[] toArray(T[] a) // 在此列表中的元素上創建延遲綁定和快速失敗的Spliterator。 public Spliterator<E> spliterator()
原理
添加
public boolean add(E e) { // 插入到最後 linkLast(e); return true; } void linkLast(E e) { // 獲取尾指針 final Node<E> l = last; // 創建新結點 final Node<E> newNode = new Node<>(l, e, null); // 尾指針指向新結點 last = newNode; if (l == null) // 列表第一個元素 first = newNode; else // 添加到尾部 l.next = newNode; // 列表大小 +1 size++; // 列表結構更改次數 +1 modCount++; }
刪除
public boolean remove(Object o) { if (o == null) { // 如果刪除對象爲null,遍歷鏈表,尋找第一個爲null的對象 for (Node<E> x = first; x != null; x = x.next) { if (x.item == null) { // 解除 unlink(x); return true; } } } else { // 否則,遍歷鏈表,尋找第一個匹配的對象 for (Node<E> x = first; x != null; x = x.next) { if (o.equals(x.item)) { // 解除 unlink(x); return true; } } } return false; } E unlink(Node<E> x) { // assert x != null; // 目標元素 final E element = x.item; // 後繼 final Node<E> next = x.next; // 前驅 final Node<E> prev = x.prev; if (prev == null) { // 當前元素是鏈表第一個元素,頭指針直接指向當前元素後繼。 first = next; } else { // 當前元素的前驅的後繼指向當前元素的後繼 prev.next = next; // 當前元素的前驅置null x.prev = null; } if (next == null) { // 當前元素是鏈表最後一個元素,尾指針直接指向當前元素前驅。 last = prev; } else { // 當前元素後繼的前驅指向當前元素的前驅 next.prev = prev; // 當前元素的後繼置null x.next = null; } // 數據置null,方便回收 x.item = null; // 鏈表元素數量 -1 size--; // 鏈表結構修改次數 +1 modCount++; // 返回老數據 return element; }
實際上LinkedList還提供了push和pop,這就使得它可以發揮棧的作用,原理無非是在鏈表頭部插入和刪除,這不在贅述。
優缺點
優點:添加和刪除效率比較高。只需要更改引用指向即可。
缺點:查找是從頭遍歷鏈表,最好情況第一個就是,最壞匹配到最後一個。不過如果僅限於首尾,只需要調用提供的getFirst和getLast等等方法
Vector
功能
完全命名
public class Vector<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable
簡介
Vector類實現了一個可增長的對象數組,它是線程安全的,如果不需要線程安全的實現,建議使用ArrayList代替Vector。
方法
// 將此Vector的組件複製到指定的數組中。這個Vector中下標k的項被複制到anArray的下標k中。 public void copyInto(Object[] anArray) // 將該向量的容量修剪爲該向量的當前大小。如果該向量的容量大於其當前大小,則通過將其保存在字段elementData中的內部數據數組替換爲一個更小的數組,將容量(Capacity)更改爲size。 public void trimToSize() // 增加這個向量的容量 public void ensureCapacity(int minCapacity) // 設置這個向量的大小。如果新大小大於當前大小,則在向量的末尾添加新的空項。如果新大小小於當前大小,則額外的所有組件都將被丟棄。 public void setSize(int newSize) // 返回此向量的當前容量。 public int capacity() // 返回此向量中組件的數量 public int size() // 如果無元素,則返回true public boolean isEmpty() // 返回此向量中組件的枚舉。返回的枚舉對象將生成此向量中的所有項。生成的第一個項是索引0處的項,然後是索引1處的項,以此類推。 public Enumeration<E> elements() // 如果該向量包含至少一個指定的元素,則返回true。 public boolean contains(Object o) // 返回該向量中指定元素第一次出現的索引,如果該向量不包含該元素,則返回-1。 public int indexOf(Object o) // 返回該向量中指定元素第一次出現時的索引(從指定索引向前搜索),如果沒有找到該元素,則返回-1。 public int indexOf(Object o, int index) // 返回該向量中指定元素的最後一次出現的索引,如果該向量不包含該元素,則返回-1。 public int lastIndexOf(Object o) // 返回此向量中指定元素的最後一次出現的索引(從指定索引向後搜索),如果沒有找到該元素,則返回-1。 public int lastIndexOf(Object o, int index) // 返回指定索引處的組件。此方法在功能上與get(int index)方法相同(後者是List接口的一部分)。 public E elementAt(int index) // 返回此向量的第一個組件(索引爲0的項)。 public E firstElement() // 返回向量的最後一個組件。 public E lastElement() // 將此向量的指定索引處的組件設置爲指定對象。索引的值必須大於或等於0,並且小於向量的當前大小。此方法在功能上與set(int, E)方法(它是List接口的一部分)相同。注意,set方法顛倒了參數的順序,以便更接近數組的用法。set方法返回存儲在指定位置的舊值。 public void setElementAt(E obj, int index) // 刪除指定索引處的組件。索引的值必須大於或等於0,並且小於向量的當前大小。該方法在功能上與remove(int)方法相同(後者是List接口的一部分)。注意,remove方法返回存儲在指定位置的舊值。 public void removeElementAt(int index) // 在指定索引處將指定對象作爲此向量中的組件插入。這個向量中索引大於或等於指定索引的每個分量向上移動,使索引大於先前的值。索引的值必須大於或等於0,並且小於或等於向量的當前大小。(如果索引等於向量的當前大小,則將新元素追加到向量。)此方法在功能上與add(int, E)方法(List接口的一部分)相同。注意,add方法顛倒了參數的順序,以便更接近於匹配數組的使用。 public void insertElementAt(E obj, int index) // 將指定的組件添加到該向量的末尾,將其大小增加1。此方法在功能上與add(E)方法(List接口的一部分)相同。 public void addElement(E obj) // 從這個向量中移除第一個匹配到的元素。此方法在功能上與remove(Object)方法(List接口的一部分)相同。 public boolean removeElement(Object obj) // 從這個向量中移除所有的分量,並將其大小設置爲0。此方法在功能上與clear()方法(List接口的一部分)相同。 public void removeAllElements() // 返回此向量的克隆。副本將包含對內部數據數組的克隆的引用,而不是對這個向量對象的原始內部數據數組的引用。 public Object clone() // 返回一個數組,該數組順序包含這個向量中的所有元素。 public Object[] toArray() // 返回一個數組,該數組順序包含這個向量中的所有元素。返回數組的運行時類型是指定數組的運行時類型 public <T> T[] toArray(T[] a) // 返回該向量中指定位置的元素。 public E get(int index) // 將此向量中指定位置的元素替換爲指定元素。 public E set(int index, E element) // 將指定的元素附加到此向量的末尾。 public boolean add(E e) // 移除此向量中指定元素的第一個匹配項,如果該向量不包含該元素,則該元素將保持不變。 public boolean remove(Object o) // 將指定元素插入到此向量的指定位置。 public void add(int index, E element) // 移除此向量中指定位置的元素。 public E remove(int index) // 從這個向量中移除所有的元素。 public void clear() // 如果該向量包含指定集合中的所有元素,則返回true。 public boolean containsAll(Collection<?> c) // 將指定集合中的所有元素按照指定集合的迭代器返回的順序追加到此向量的末尾。 public boolean addAll(Collection<? extends E> c) // 從該向量中移除指定集合中包含的所有元素。 public boolean removeAll(Collection<?> c) // 僅保留此向量中包含在指定集合中的元素。換句話說,從這個向量中刪除指定集合中不包含的所有元素。 public boolean retainAll(Collection<?> c) // 將指定集合中的所有元素插入到此向量的指定位置。 public boolean addAll(int index, Collection<? extends E> c) // 將指定的對象與此向量進行比較以確定是否相等。當且僅當指定的對象也是一個列表時,才返回true,兩個列表的大小相同,且兩個列表中所有對應的元素對都是相等的。 public boolean equals(Object o) // 返回此向量的哈希碼值 public int hashCode() // 返回此向量的字符串表示形式,其中包含每個元素的字符串表示形式。 public String toString() // 返回該列表中fromIndex(包含)和toIndex(不包含)之間的元素。 public List<E> subList(int fromIndex, int toIndex) // 刪除該列表中fromIndex(包含)和toIndex(不包含)之間的元素。 protected void removeRange(int fromIndex, int toIndex) // 從列表中的指定位置開始,返回此列表中元素的列表迭代器(按適當的順序)。 public ListIterator<E> listIterator(int index) // 返回該列表中元素的列表迭代器(按適當的順序)。 public ListIterator<E> listIterator() // 按適當的順序對列表中的元素返回一個迭代器。 public Iterator<E> iterator() // 爲可迭代的每個元素執行給定的操作,直到處理完所有元素或操作引發異常。 public void forEach(Consumer<? super E> action) // 刪除此集合中滿足給定謂詞的所有元素。迭代期間或由謂詞拋出的錯誤或運行時異常將傳遞給調用者。 public boolean removeIf(Predicate<? super E> filter) // 將此列表中的每個元素替換爲將操作符應用於該元素的結果。操作符拋出的錯誤或運行時異常將傳遞給調用者。 public void replaceAll(UnaryOperator<E> operator) // 根據比較器產生的順序對這個列表進行排序。 public void sort(Comparator<? super E> c) // 在此列表中的元素上創建延遲綁定和快速失敗的Spliterator。 public Spliterator<E> spliterator()
原理
添加
// 與ArrayList唯一的區別就是加了個同步關鍵字,以保證線程安全,內部邏輯一樣 public synchronized boolean add(E e) { modCount++; ensureCapacityHelper(elementCount + 1); elementData[elementCount++] = e; return true; } private void ensureCapacityHelper(int minCapacity) { // overflow-conscious code if (minCapacity - elementData.length > 0) grow(minCapacity); } private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); elementData = Arrays.copyOf(elementData, newCapacity); } public boolean remove(Object o) { return removeElement(o); }
刪除
// 與ArrayList唯一的區別就是加了個同步關鍵字,以保證線程安全,內部邏輯一樣 public synchronized boolean removeElement(Object obj) { modCount++; int i = indexOf(obj); if (i >= 0) { removeElementAt(i); return true; } return false; } public synchronized void removeElementAt(int index) { modCount++; if (index >= elementCount) { throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount); } else if (index < 0) { throw new ArrayIndexOutOfBoundsException(index); } int j = elementCount - index - 1; if (j > 0) { System.arraycopy(elementData, index + 1, elementData, index, j); } elementCount--; elementData[elementCount] = null; /* to let gc do its work */ }
get
// 注意,讀取的方法也是加了同步的 public synchronized E get(int index) { if (index >= elementCount) throw new ArrayIndexOutOfBoundsException(index); return elementData(index); }
優缺點
優缺點和ArrayList大致一樣,唯一的不同就是Vector是線程安全的,但是加了同步方法,也就降低了效率,如果沒有線程安全問題,直接使用ArrayList即可。