一般在面試中可能會被問到ArrayList、LinkedList、Vector三者相關的區別!
一般來說我想大概都會回答如下的這些:
ArrayList底層是數組結構,查詢快,增刪慢,線程不安全,效率高。
LinkedList底層是鏈表數據結構,查詢慢,增刪快,線程不安全,效率高。
Vector底層是數組結構,查詢快,增刪慢,線程安全,效率低。
以上就是最基本的一個優缺點,但是他們的內部結構,具體怎么實現添加查詢這一塊的,我想應該有一部分人還是不太清楚。
下面我將帶領一起去集合的內部看一看具體的代碼實現。
ArrayList:
首先是ArrayList的一個實例化,java提供了一個有參構造和無參構造。下面一起查看代碼:
/** * Constructs an empty list with the specified initial capacity.
構造具有指定初始容量的空列表。 * * @param initialCapacity the initial capacity of the list 初始容量列表的初始容量 * @throws IllegalArgumentException if the specified initial capacity 如果指定的初始容量為負,則拋出IllegalArgumentException * is negative */ 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); } }
通過上述我們可以看到,這是ArrayList的有參構造,可以自定義集合的初始化長度,否則如果輸入的是0那么就使用ArrayList自帶的默認的數組緩存區。
/** * Constructs an empty list with an initial capacity of ten. 構造初始容量為10的空列表。 */ public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; }
使用無參構造,將會創建一個默認長度的數組。初始長度為10。
/** * Default initial capacity. 默認初始容量 */ private static final int DEFAULT_CAPACITY = 10; /** * Shared empty array instance used for empty instances. 用於空實例的共享空數組實例 */ private static final Object[] EMPTY_ELEMENTDATA = {};
* 解析add添加方法的全過程,下面的add方法相關的所有源代碼,
/** * Appends the specified element to the end of this list. 將指定的元素追加到列表的末尾 * * @param e element to be appended to this list 將追加到此列表中的e元素 * @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; }
private void ensureCapacityInternal(int minCapacity) {
// 判斷該數組是否是一個新創建的實例對象 if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
// 如果是,就設置數組的長度為默認長度 10 minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } // 確保能夠有儲存能力 ensureExplicitCapacity(minCapacity); }
private void ensureExplicitCapacity(int minCapacity) {
// 保存這個列表在結構上被修改的次數。 modCount++; // overflow-conscious code
// 如果默認的長度減去實際數組的長度大於0,那么就調用grow()方法
if (minCapacity - elementData.length > 0) grow(minCapacity); }
private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; // 獲取數組原始的長度 int newCapacity = oldCapacity + (oldCapacity >> 1); // 獲取新的數組的長度 (0 + 0/2) if (newCapacity - minCapacity < 0) // 如果新的值 - 最小值小於0 (0-10) newCapacity = minCapacity; // 將默認值 10 賦值給 新的值 if (newCapacity - MAX_ARRAY_SIZE > 0) // 如果新的值 - 最大長度 大於 0 (0 - 2147483639) > 0 newCapacity = hugeCapacity(minCapacity); // 調用方法 // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity); // 復制原本的數組,定義長度,賦值給自己,來達到自動擴容 }
* 總結以上,在ArrayList被無參實例化的時候就會被創建一個空的數組,在添加第一個值時,ArrayList底層的自動擴容機制將會被執行,也就是private void grow(int minCapacity)這個方法會被調用,給內部的elementData數組定義初始長度為10,然后再將值添加到數組的末尾。這里面主要就是牽涉到一個自動擴容機制,在每一次添加之前,都會去判斷,當前數組長度是否有實際的存儲能力,如果沒有那么自動擴容機制就會根據當前數組長度+當前長度/2來計算的方式,對當前數組進行擴容。
linkedList:
* 鏈接內部結構圖

* 查看linkedList的無參構造和有參構造
* 無參構造
/** * Constructs an empty list. // 構造一個空列表 */ public LinkedList() { }
* 有參構造
/** * 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 LinkedList(Collection<? extends E> c) { this(); addAll(c); }
* 解析add添加方法:
/** * Appends the specified element to the end of this list. 將指定的元素追加到列表的末尾 * * <p>This method is equivalent to {@link #addLast}. * * @param e element to be appended to this list * @return {@code true} (as specified by {@link Collection#add}) */ public boolean add(E e) { linkLast(e); return true; }
/** * Links e as last element. 鏈接做為最后一個元素 */ void linkLast(E e) {
// 將最后一個節點臨時存儲起來 final Node<E> l = last;
// 創建一個新的節點,設置新的節點的上一個節點和當前節點的值 final Node<E> newNode = new Node<>(l, e, null);
// 將新創建的節點重新存儲到專門用於保存最后一個節點的值的對象 last = newNode;
// 判斷是否是第一次添加,如果是第一次添加值,那么上一個值一定是null,否則就會一個值 if (l == null)
// 如果是第一次添加,那么我們就要將新創建的節點保存到鏈表的頭first first = newNode; else // 否則就設置l的下一個節點為新的節點
l.next = newNode;
// 長度增加 size++;
// 修改次數 modCount++; }
* 總結以上:從源代碼上我們可以看到,linkedList內部采用的實際上是通過多個節點來保存值,每個節點對象中對它的上一個節點和下一個節點繼續記錄,以此將所有的節點串聯起來,就形成了鏈表。
Vector:
vector其實本質上和ArrayList是一樣的,底層都是使用了數組來完成,只是vector是從jdk1.0版本開始,ArrayList是1.2版本開始,可以理解的是ArrayList其實就是用來代替Vector的。Vector和ArrayList最大的區別就是一個是線程安全,一個是線程不安全的。這個我們可以通過查看底層代碼來得知。
* 解析add代碼
/** * 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; }
* 總結上述可得知:相比較ArrayList的add方法,我們可以看出,Vector的add方法添加的同步鎖。
------------------------------------------------------ 分割 -------------------------------------------------------------------
學無止境,永遠不要輕言放棄。
