1. 程式人生 > >java語言基礎--集合學習,ArrayList和Linkedlist

java語言基礎--集合學習,ArrayList和Linkedlist

rem 超出 pri internal mac extend pre 所有 因此

Collection<E>接口

  這個接口是集合框架最頂級的接口,該接口擴展了Iterable接口,這意味著所有的集合類fore-each風格進行遍歷。

ArrayList 與 Linkedlist

區別:

  ArrayList是實現了基於動態數組,LinkedList基於鏈表。對於隨機訪問get和set,ArrayList性能要優於LinkedList,因為LinkedList要移動指針。對於刪除和新增LinkedList性能要優於ArrayList,因為ArrayList要移動數據。

ArrayList的擴容方式,擴容時機

  當集合中的元素超出容量,便會進行擴容操作。擴容操作也是ArrayList 的一個性能消耗比較大的地方,所以若我們可以提前預知數據的規模,應該通過public ArrayList(int initialCapacity) {}構造方法,指定集合的大小,去構建ArrayList實例,以減少擴容次數,提高效率

ArrayList的成員屬性

public class ArrayList<E> extends AbstractList<E>implements List<E>, RandomAccess, Cloneable, java.io.Serializable{
    private static final long serialVersionUID = 8683452581122892189L;
    //默認初始容量
    private static final int DEFAULT_CAPACITY = 10;
    //默認構造函數的空數組
    private
static final Object[] EMPTY_ELEMENTDATA = {}; //瞬態(在采用Java默認的序列化機制的時候,被該關鍵字修飾的屬性不會被序列化)的數組,真正存放元素的數組 transient Object[] elementData; // non-private to simplify nested class access //elementData存放元素的數量,這裏和容量不一樣 private int size; }

ArrayList的構造方法

    public ArrayList(int initialCapacity) {
        super();
//即父類protected AbstractList() {} if (initialCapacity < 0)throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); this.elementData = new Object[initialCapacity];//創建一個容量為initialCapacity的空的(但是size==0)對象數組 } public ArrayList() { super(); this.elementData = EMPTY_ELEMENTDATA;//將空數組賦值給elementData } public ArrayList(Collection<? extends E> c) { //調用Collection.toArray()方法得到一個對象數組,並賦值給elementData elementData = c.toArray(); //設置size的值 size = elementData.length; //c.toArray()如果沒有返回Object[]時,利用Arrays.copyOf 來復制集合c中的元素到elementData數組中 if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, size, Object[].class); }

add方法

    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;//將數組元素追加到末尾,並修改size
        return true;
    }
    
    private void ensureCapacityInternal(int minCapacity) {
        //根據EMPTY_ELEMENTDATA  判斷數組是否是用默認構造函數初始化的,(這裏不考慮ArrayList(Collection<? extends E> c)這種情況是因為,minCapacity是肯定大於c的size的)
        if (elementData == EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }

        ensureExplicitCapacity(minCapacity);
    }
    
    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;///如果確定要擴容,會修改modCount 
        
        // 如果傳入的數大於數組原容量 則開始擴容
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
    
    private void grow(int minCapacity) {
        //
        int oldCapacity = elementData.length;
        //擴容為原來的1.5倍
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        //取1.5倍的容量和傳入的擴容系數的最大值
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)//這裏的 MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
    //最大返回 Integer.MAX_VALUE
    private static int hugeCapacity(int minCapacity) {
        // overflow
        if (minCapacity < 0) throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?Integer.MAX_VALUE :MAX_ARRAY_SIZE;
    }

指定位置插入add(int index, E element)

    public void add(int index, E element) {
        rangeCheckForAdd(index);//範圍檢查

        ensureCapacityInternal(size + 1);  // Increments modCount!!
        //將index開始的數據 向後移動一位
        System.arraycopy(elementData, index, elementData, index + 1,size - index);
        elementData[index] = element;
        size++;
    }
    
    private void rangeCheckForAdd(int index) {
        if (index > size || index < 0)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

addAl方法

    public boolean addAll(Collection<? extends E> c) {
        Object[] a = c.toArray();
        int numNew = a.length;
        //擴容準備
        ensureCapacityInternal(size + numNew);  
        // 復制數組 ,並載入數據
        System.arraycopy(a, 0, elementData, size, numNew);
        size += numNew;
        return numNew != 0;
    }

查詢

    public E get(int index) {
        rangeCheck(index);//範圍檢查

        return elementData(index);//下標獲取數據
    }    

    @SuppressWarnings("unchecked")
    E elementData(int index) {
        return (E) elementData[index];
    }

Linkedlist

    transient int size = 0;//集合元素數量

    transient Node<E> first; //頭部節點

    transient Node<E> last;//尾部節點

構造方法

   public LinkedList() {}

    public LinkedList(Collection<? extends E> c) {
        this();
        addAll(c);//將集合c所有元素插入鏈表中
    }

內部類 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;
        }
    }

add方法

    //尾部插入新節點
    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)//如果原尾部節點為null  則將當前節點設置為鏈表的首節點
            first = newNode;
        else//否則將當前節點設置為原尾部節點的後節點
            l.next = newNode;
        size++;
        modCount++;
    }

其他例子就不看了,總得來說 LinkedList 修改數據時,只需要設置新節點和關聯前後節點關系即可,不向ArrayList那樣,增加一個數據。後面的數據都要後移。因此LinkedList 對數據操作效率高。

java語言基礎--集合學習,ArrayList和Linkedlist