阿里面試常見題:ArrayList、LinkedList和CopyOnWriteArrayList

ArrayList方面

ArrayList簡介:面試

ArrayList是一種以數組實現的List,它實現了List, RandomAccess, Cloneable, Serializable接口。數組

  1. 實現List接口表示它能夠支持刪除、添加和查找等操做。
  2. 實現RandomAccess接口表示它能夠支持隨機訪問(強調一點,並非由於實現RandomAccess接口,ArrayList才支持隨機訪問。RandomAccess只是一個標記接口,接口RandomAccess中內容是空的,只是做爲標記使用。)。
  3. 實現了Cloneable接口表示ArrayList能夠被克隆。
  4. 實現了Serializable接口表示ArrayList能夠被序列化。

ArrayList中的屬性安全

  1. DEFAULT_CAPACITY =10;表示默認的容量爲10。
  2. Object[] EMPTY_ELEMENTDATA ={};表示一個空數組,若是你傳入的容量爲0時使用,例如:ArrayList list=new ArrayList(0)。
  3. Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA={};表示一個空的數組,在你不傳入容量的時候使用,例如:ArrayList list=new ArrayList()時使用。在添加第一個元素的時候會初始化默認的大小10.
  4. Object[] elementData;用於存儲元素的數組。
  5. int size;表示元素的個數。
  6. modCount;對於add操做,remove操做,modCount會進行自增操做。表示ArrayList支持fail-fast。

ArrayList的構造方法(三種)dom

ArrayList list =new ArrayList(int initialCapacity)線程

傳入初始容量,若是小於0就拋出異常;若是大於0,則使用傳入的容量;若是等於0就使用EMPTY_ELEMENTDATA空數組。對象

ArrayList list=new ArrayList()blog

不傳入初始容量,默認使用
DEFAULTCAPACITY_EMPTY_ELEMENTDATA空數組,在添加第一個元素的時候擴容爲默認的大小DEFAULT_CAPACITY也就是10。索引

ArrayList list=new ArrayList(Collection c)接口

會將Collection集合轉化爲數組拷貝到element數組中(elementData=c.toArray())。隊列

ArrayList的各類操做

add(E e)

將元素添加到末尾,平均時間複雜度爲O(1);

  1. 檢查數組是否須要擴容
  2. 首先判斷elementData是否等於DEFAULTCAPACITY_EMPTY_ELEMENTDATA便是否爲空數組,若是是就初始化爲默認大小DEFAULT_CAPACITY(10);
  3. 新容量爲舊容量的1.5倍;若是發現仍是比須要的容量小,則以須要的容量爲標準;若是須要的容量已經超過最大的容量(MAX_ARRAY_SIZE),則使用最大的容量;最後以新容量拷貝出一個新的數組。
  4. 添加元素。

add(int index,E element)

將元素添加到指定位置,時間複雜度爲O(n),由於須要將index後的元素總體向後移動一位。

  1. 檢查index是否越界。
  2. 檢查是否須要進行擴容。
  3. 將index後的元素總體向後移動一位。
  4. 將index位置的元素賦值爲element。
  5. size++,表示元素個數增長一。

get(int index)

  1. 返回指定位置的元素,時間複雜度爲o(1)。
  2. 判斷index是否越界。
  3. 返回index位置的元素。

remove(int index)

刪除指定位置的元素,時間複雜度爲o(n),由於須要將index後的元素總體向前移動一位。

  1. 檢查是否越界。
  2. modCount++。
  3. 調用System.arrayCopy()方法對於數組自己進行復制,將index後的元素總體向前移動一位。
  4. 將最後一個元素設置爲null,幫助GC。
  5. 返回index位置的舊值。

remove(Object o)

刪除指定元素的值,時間複雜爲o(n)。

  1. 遍歷數組,若是刪除的元素爲null,使用==進行null的比較;若是刪除的元素不爲null,使用equals()進行比較。
  2. modCount++;
  3. 調用System.arrayCopy()方法將刪除元素位置後的全部元素總體向前移動一位。
  4. 將最後一個元素設置爲null,方便進行GC。
  5. 返回true或false表示刪除成功或者失敗。

ArrayList總結

  1. ArrayList使用數組存儲元素,當數組長度不夠的時候,會進行擴容,每次擴容爲1.5倍。
  2. ArrayList添加元素到尾部,平均時間複雜度爲O(1)。
  3. ArrayList添加元素到中間,平均時間複雜度爲O(n)。
  4. ArrayList刪除尾部的元素,平均時間複雜度爲O(1)。
  5. ArrayList從中間刪除元素比價慢,平均時間複雜度爲O(n)。
  6. ArrayList支持隨機訪問,時間複雜度爲O(1)。
阿里面試常見題:ArrayList、LinkedList和CopyOnWriteArrayList

 

LinkedList相關方面

LinkedList簡介:

相較於ArrayList的數組實現,LinkedList是基於雙向鏈表實現的。它實現了List, Deque,Queue, Cloneable, Serializable接口。

  1. 實現List接口表示它能夠支持刪除、添加和查找等操做。
  2. 實現Deque和Queue接口表示它能夠做爲雙端隊列進行使用,同時也能夠做爲棧進行使用。
  3. 實現了Cloneable接口表示ArrayList能夠被克隆。
  4. 實現了Serializable接口表示ArrayList能夠被序列化。

LinkedList的內部屬性

int size表示元素的個數,初始爲0。

  1. Node< E> first。表示鏈表的第一個節點。
  2. Node< E> last。表示鏈表中的最後一個節點。
  3. Node< E> 是一個雙向鏈表的結構。Node< E>內部包括Node< E> next,Node< E> prev和E item。
  4. modcount表示支持fail-fast。

LinkedList的主要方法

addFirst(E e)

在隊首添加元素,時間複雜度爲O(1)。

  1. 建立一個新的節點newNode。
  2. 將newNode賦值給first即first=newNode。
  3. 判斷newNode是否是第一個新添加的節點,若是是的話,將newNode賦值給last即last=newNode。
  4. size++。
  5. modcount++。

addLast(E e)

在隊尾添加元素和addFirst(E e)同理,時間複雜度爲O(1)。

add(int index,E element)

在指定位置添加元素,時間複雜度爲O(n)。由於須要遍歷,查找到插入位置的後繼節點。

  1. 判斷是否越界。
  2. 若是index小於size/2,從前日後進行遍歷找到插入位置的後繼節點;若是index大於size/2,從後往前遍歷找到插入位置的後繼節點。
  3. 按照雙線鏈表在中間插入元素的方法進行插入。

removeFirst()

刪除隊首的元素,時間複雜度爲O(1)。

  1. 若是鏈表中沒有元素,拋出異常。
  2. 查找first的後繼節點假設是first_next,將first設置爲null,方便進行GC。
  3. 將first設置爲first_next即first=first_next;判斷first_next是否爲null,若是first_next等於null,則將last設置爲null不然將first_next.prev設置爲null。
  4. size–。
  5. modcount++。

removeLast()

刪除隊尾的元素,時間複雜度爲O(1)。原理同上。

remove(int index)

刪除指定位置的元素,時間複雜度爲O(n),原理同add(int index,E element)。

LinkedList總結

  1. LinkedList是基於雙向鏈表實現,能夠做爲雙端隊列,棧來進行使用。
  2. LinkedList在隊首隊尾刪除添加比較快,時間複雜度爲O(1)。
  3. LinkedList在鏈表中間添加刪除比較慢,時間複雜度爲O(n)。
  4. 另外要注意的是,LinkedList是不支持隨機訪問的,因此訪問中間元素的效率比較低。
阿里面試常見題:ArrayList、LinkedList和CopyOnWriteArrayList

 

CopyOnWriteArrayList相關

CopyOnWriteArrayList簡介:

CopyOnWriteArrayList是ArrayList的線程安全版本,也是經過數組實現的。相較於ArrayList,CopyOnWriteArrayList使用ReentrantLock重入鎖加鎖,保證線程安全。每次對數組的修改都徹底拷貝一份新的數組來修改,修改完了再替換掉老數組,這樣保證了只阻塞寫操做,不阻塞讀操做,實現讀寫分離。

CopyOnWriteArrayList實現了List, RandomAccess, Cloneable, Serializable接口。

  1. 實現List接口表示它能夠支持刪除、添加和查找等操做。
  2. 實現RandomAccess接口表示它能夠支持隨機訪問(強調一點,並非由於實現了RandomAccess接口,ArrayList才支持隨機訪問。RandomAccess只是一個標記接口,接口RandomAccess中內容是空的,只是做爲標記使用。)。
  3. 實現了Cloneable接口表示ArrayList能夠被克隆。
  4. 實現了Serializable接口表示ArrayList能夠被序列化。

CopyOnWriteArrayList主要的內部屬性:

  1. ReentrantLock lock=new ReentrantLock();用於修改時進行加鎖。
  2. Object[]array用於純屬元素。

CopyOnWriteArrayList主要方法:

add(E e)

添加一個元素到末尾。

  1. 使用ReentrantLock進行加鎖。
  2. 使用getArray()方法獲取元素的數組。
  3. 新建一個數組大小是原數組的長度加一,並使用Arrays.copyof()方法將原數組拷貝到新數組中。
  4. 將添加的元素放到新數組的末尾。
  5. 將新數組覆蓋原數組。
  6. 解鎖。

add(int index,E element)

添加元素到制定的位置。

  1. 加鎖。
  2. 判斷是否越界,若是越界拋出異常。
  3. 若是索引等於數組長度,那就拷貝一個len+1的數組即newElements =Arrays.copyOf(elements,len+1)。
  4. 若是索引不等於數組長度,那就新建一個len+1的數組,將索引以前的部分拷貝到新數組索引以前,索引以後拷貝到新數組索引以後的位置。
  5. 把索引位置賦值爲待添加的元素。
  6. 把新數組賦值給當前對象的array屬性,覆蓋原數組。
  7. 解鎖。

get(int index)

獲取指定位置的元素,時間複雜度爲O(1)。

  1. 經過getAway()方法獲取數組。
  2. 返回指定位置的元素。

remove(int index)

刪除指定位置的元素,時間複雜度O(n)。

  1. 加鎖。
  2. 經過getAway()方法獲取舊數組。
  3. 若是移除的是最後一位,那麼直接拷貝一份n-1的新數組, 最後一位就自動刪除。
  4. 若是移除的不是最後一位,那麼新建一個n-1的新數組。將前index的元素拷貝到新數組中,將index後面的元素往前挪一位拷貝到新數組中。
  5. 將新數組賦值給當前對象的數組屬性。
  6. 解鎖並返回舊值。

CopyOnWriteArrayList總結:

    1. 對於寫操做,CopyOnWriteArrayList使用ReentrantLock重入鎖加鎖,保證線程安全。
    2. CopyOnWriteArrayList的寫操做要先拷貝一份新數組,在新數組中進行修改,修改完了再用新數組去替換舊的數組。
    3. CopyOnWriteArrayList採用讀寫分離的思想,讀操做不加鎖,可是寫操做須要加鎖。
    4. CopyOnWriteArrayList支持隨機快速訪問,時間複雜度爲O(1)。
相關文章
相關標籤/搜索