從源碼對比ArrayList和LinkList區別

先列下提綱:

  1. ArrayList和LinkList底層的數據結構不一樣
  2. 對於set()和get()方法, ArrayList比LinkList要快,也就是說,使用ArrayList查詢比LinkList快
  3. 對於add() 和remove()方法,LinkList比ArrayList要快,增刪方面使用LinkList更好
  4. 對於使用Iterator,暫更

開始逐條分析:
一. ArrayList和LinkList底層的數據結構不一樣
(1)ArrayList
private static final Object[] EMPTY_ELEMENTDATA = {};
private transient Object[] elementData;
private int size;

public ArrayList() {
    super();
    this.elementData = EMPTY_ELEMENTDATA;//這個無參很好的解釋了數組集合的由來  第一點
}

(2)LinkList
Entry 可以當作節點類 ,它有三個成員變量 previous上一個節點 ,next下一個節點, element節點的值 .previous和next可以當作是指針

private static class Entry {
E element;
Entry next;
Entry previous;

Entry(E element, Entry<E> next, Entry<E> previous) {
    this.element = element;
    this.next = next;
    this.previous = previous;

}
}

  • private transient Entry header = new Entry(null, null, null);
  • private transient int size = 0;
    public LinkedList() {
  •    header.next = header.previous = header; //這個無參構造,很好的解釋了雙向循環列表的名字由來   第一點
    
    }

二. 對於set()和get()方法, ArrayList比LinkList要快,也就是說,使用ArrayList查詢比LinkList快
(1)ArrayList

    public void set(E e) {
        if (lastRet < 0)
            throw new IllegalStateException();//這處地方很好的解釋了爲何,ArrayList一上來的時候不能直接set,因爲本來就是空數組,還有條件判斷,所以一開始應該要add 第二點
        checkForComodification();
        try {
            ArrayList.this.set(lastRet, e);
        } catch (IndexOutOfBoundsException ex) {
            throw new ConcurrentModificationException();
        }
    }
      public E set(int index, E element) {
    rangeCheck(index);
    E oldValue = elementData(index);
    elementData[index] = element;//此處表明了,set真的就是找到下標後放進去  第二點
    return oldValue;
}

public E get(int index) {

    rangeCheck(index);
    
    return elementData(index);//get時就是從數組中把下表傳進去取
}

(2)LinkList

 public E set(int index, E element) {
  Entry<E> e = entry(index);
    E oldVal = e.element;
    e.element = element;
    checkElementIndex(index);
    Node<E> x = node(index);
    E oldVal = x.item;
    x.item = element;
     return oldVal;
 }
 
 public E get(int index) {
    return entry(index).element;
    checkElementIndex(index);
    return node(index).item;
 }
private Entry<E> entry(int index) {//從這個方法,可以看出,set 與get都需要每次利用二分法從前往後或者從後往前循環查找.  第二點
    if (index < 0 || index >= size)
        throw new IndexOutOfBoundsException("Index: "+index+
                                            ", Size: "+size);
    Entry<E> e = header;
    if (index < (size >> 1)) {
        for (int i = 0; i <= index; i++)
            e = e.next;
    } else {
        for (int i = size; i > index; i--)
            e = e.previous;
    }
    return e;

}

三.對於add() 和remove()方法,LinkList比ArrayList要快,增刪方面使用LinkList更好
(1)ArrayList

  public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }
    private void ensureCapacityInternal(int minCapacity) {
        if (elementData == EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }

        ensureExplicitCapacity(minCapacity);
    }
    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // 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 + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);//此處說明,ArrayList的add就是重新生成(copy)一個數組,先擴容,然後賦值     第三點
    }
    public E remove(int index) {
        rangeCheck(index);
        modCount++;
        E oldValue = elementData(index);
        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);//此處說明AyyayList的remove就是重新生成一個長度短的數組     第四點
        elementData[--size] = null; // clear to let GC do its work   

        return oldValue;
    }

(2)LinkList

 public boolean add(E e) {
   addBefore(e, header);
     return true;
 }
   private Entry<E> addBefore(E e, Entry<E> entry) {
       Entry<E> newEntry = new Entry<E>(e, entry, entry.previous);//此處描述,鏈表集合的add就是直接增加一個Entry,然後改變相應的指針  第三點
       newEntry.previous.next = newEntry;
        newEntry.next.previous = newEntry;
        size++;
        modCount++;
        return newEntry;
    }
   private E remove(Entry<E> e) {
      if (e == header)
           throw new NoSuchElementException();
     E result = e.element;//從這往下的一段邏輯,可以看出,LinkList集合的remove就是把當前的節點前後節點的指針改變,同時清空自身的指針和元素  第四點
       e.previous.next = e.next;
       e.next.previous = e.previous;
       e.next = e.previous = null;
       e.element = null;
       size--;
       modCount++;
       return result;
           }

四 對於使用Iterator,暫更

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章