ArrayList和CopyOnWriteArrayList面試題總結與原始碼分析
阿新 • • 發佈:2019-08-23
面試題
(1)ArrayList和CopyOnWriteArrayList的增刪改查實現原理?
(2)為什麼說ArrayList查詢快而增刪慢?
(3)弱一致性的迭代器原理是怎麼樣的?
(4)CopyOnWriteArrayList為什麼併發安全且效能比Vector好?
(1)ArrayList和CopyOnWriteArrayList的增刪改查實現原理?
ArrayList類圖
CopyOnWriteArrayList類圖
1.List介面
首先我們來看List介面,如上因為ArrayList和CopyOnWriteArrayList都是實現了List介面,所有檢視其相應的方法即可。
2.ArrayList的幾個重點
1、底層是陣列,初始化大小為10
2、插入時會判斷陣列容量是否足夠,不夠的化會進行擴容
3、所謂擴容就是新建一個數組,然後將老的資料裡面的元素複製到新的數組裡面
4、移除元素的時候也涉及到陣列中元素的移動,刪除指定index位置的元素,然後將index+1至陣列最後一個元素往前移動一格
2.2增刪改查
1.增
/** * Appends the specified element to the end of this list. * * @param e element to be appended to this list * @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; } /** * Inserts the specified element at the specified position in this * list. Shifts the element currently at that position (if any) and * any subsequent elements to the right (adds one to their indices). * * @param index index at which the specified element is to be inserted * @param element element to be inserted * @throws IndexOutOfBoundsException {@inheritDoc} */ public void add(int index, E element) { rangeCheckForAdd(index); //——檢查是否越界 ensureCapacityInternal(size + 1); // Increments modCount!! //——進行陣列容量判斷,不夠就擴容 System.arraycopy(elementData, index, elementData, index + 1, //——將index至資料最後一個元素整體往後移動一格,然後插入新的元素 size - index); elementData[index] = element; size++; }
2.刪
/** * Removes the element at the specified position in this list. * Shifts any subsequent elements to the left (subtracts one from their * indices). * * @param index the index of the element to be removed * @return the element that was removed from the list * @throws IndexOutOfBoundsException {@inheritDoc} */ public E remove(int index) { rangeCheck(index); //——判斷是否越界 modCount++; E oldValue = elementData(index); int numMoved = size - index - 1; if (numMoved > 0) //——若該元素不是最後一個元素的話,將index+1至陣列最後一個元素整體向前移動一格 System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // clear to let GC do its work return oldValue; } /** * Removes the first occurrence of the specified element from this list, * if it is present. If the list does not contain the element, it is * unchanged. More formally, removes the element with the lowest index * <tt>i</tt> such that * <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt> * (if such an element exists). Returns <tt>true</tt> if this list * contained the specified element (or equivalently, if this list * changed as a result of the call). * * @param o element to be removed from this list, if present * @return <tt>true</tt> if this list contained the specified element */ 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; } /* * Private remove method that skips bounds checking and does not * return the value removed. */ 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 }
3.改
public E set(int index, E e) { rangeCheck(index); checkForComodification(); E oldValue = ArrayList.this.elementData(offset + index); ArrayList.this.elementData[offset + index] = e; //——將陣列對應的index的元素進行替換 return oldValue; }
4.查
public E get(int index) { rangeCheck(index); //——進行陣列越界判斷 checkForComodification(); return ArrayList.this.elementData(offset + index); //——獲取陣列對應的index元素 }
E elementData(int index) { return (E) elementData[index]; }
總結
(2)為什麼說ArrayList查詢快而增刪慢?
以上部分就是ArrayList的增刪改查原理,以此就可以解決我們的第二個問題了。
ArrayList底層是陣列,所以查詢的時候直接根據索引可以很快地找到對應地元素,改也是如此,找到index對應元素進行替換。而增加和刪除就涉及到陣列元素地移動,所以會比較慢。
CopyOnWriteArrayList幾個關鍵點
1、實現了List介面
2、內部持有一個ReentrantLock lock=new ReentrantLock()
3、底層是用volatile transient宣告地陣列 array
4、讀寫分離,寫時複製出一個新地陣列,完成插入、修改或者移除操作後將新陣列賦值給array
增刪改查
1.增
/** * Appends the specified element to the end of this list. * * @param e element to be appended to this list * @return {@code true} (as specified by {@link Collection#add}) */ public boolean add(E e) { final ReentrantLock lock = this.lock; lock.lock(); //——獲得鎖