Java中主要數據結構的實現原理及擴容機制

說明

  • Java版本:1.8.0_231

ArrayList

  1. 底層由Object數組實現,具有數組的所有特性,實現了RandomAccess接口支持隨機訪問,非線程安全類型
Object[] elementData;
  1. 構造方法
  • 創建一個空數組
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
  • 具有初試容量的數組
    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);
        }
    }
  1. add()方法及擴容機制
    public boolean add(E e) {
        ensureCapacityInternal(size + 1);
        // 將元素e添加到末尾
        elementData[size++] = e;
        return true;
    }
  • 數組容量初始化
    private static int calculateCapacity(Object[] elementData, int minCapacity) {
    // 判斷是否是爲空數組,若爲空,返回10;否則將返回arr.length + 1(第一次添加數據肯定是空的,第二次及後續就是arr.length +1)
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }
  • 判斷是否到達擴容零界點
    private void ensureExplicitCapacity(int minCapacity) {
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

	// 核心 開始擴容
    private void grow(int minCapacity) {
        // 獲取數組長度
        int oldCapacity = elementData.length;
        // 右移位運算得出擴容後的長度
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // 將擴容後的數據賦值給原數組
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

在添加第一個元素時,就會調用grow()方法進行擴容操作,但此時數組長度爲0,擴容後的

LinkedList

  1. 底層由雙向鏈表實現,實現了Deque接口,可以雙向操作,不支持隨機訪問,非線程安全類型
	// node節點
    private static class Node<E> {
        E item;
        Node<E> next;
        Node<E> prev;

        Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
    }
    // 指向上一個節點
	Node<E> first;
	// 指向下一個節點
	Node<E> last;
  1. 兩個構造函數
  • 構造一個空List
    public LinkedList() {
    }
  • 一個有參構造函數
    public LinkedList(Collection<? extends E> c) {
        this();
        addAll(c);
    }sdss
  1. 鏈表追加節點至末尾
    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;
        size++;
        modCount++;
    }

Vector

  1. 底層有Object數組實現,實現了RandomAccess接口,支持隨機訪問,線程安全類型
protected Object[] elementData;
  1. 三個構造函數(其實是一個)
  • 賦予初始容量和擴容量
    public Vector(int initialCapacity, int capacityIncrement) {
        super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        this.elementData = new Object[initialCapacity];
        this.capacityIncrement = capacityIncrement;
    }
  • 使用默認的擴容量0
    public Vector(int initialCapacity) {
        this(initialCapacity, 0);
    }
  • 使用默認的初始容量10和初始容量0
    public Vector() {
        this(10);
    }
  1. 添加元素與擴容機制
    public synchronized void addElement(E obj) {
    	// 擴容
        ensureCapacityHelper(elementCount + 1);
        // 將新增元素添加到數組末尾
        elementData[elementCount++] = obj;
    }
    
     private void ensureCapacityHelper(int minCapacity) {
         // 第一次添加元素時,minCapacity=10,elementData.length = 0,這時不會進行擴容 
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
    
        private void grow(int minCapacity) {
            // 獲取數據的長度
        int oldCapacity = elementData.length;
            // 擴容核心:在創建數組時指定了capacityIncrement且大於0,擴容後的值爲capacityIncrement+初始容量,反之爲初始容量+初始容量,即兩倍的初始容量
        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);
    }

List接口主要實現類總結

  1. ArrayList和Vector底層基於數組實現,具有數組的所有特性且支持隨機訪問,其中Vector時線程安全的;在擴容機制上:
  • ArrayList是1.5倍擴容,關鍵代碼爲int newCapacity = oldCapacity + (oldCapacity >> 1); 即 10 --> 15;
  • Vector是2倍擴容,關鍵代碼:int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity);,即:10 --> 20
  1. LinkedList是基於雙向鏈表實現,可雙向插入,插入刪除快,查找慢

網站原文:https://www.haicheng.website/passages/source-code-analysis-01/

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