java基礎:集合類

集合類繼承圖 

其中常見的有:
 HashMap、TreeMap、ConcurrentHashMap、ArrayList、LinkedList

ArrayList

特點:底層數據結構是數組。線程不安全。初始大小爲10,最大容量爲最大爲Integer.MAX_VALUE,即((2^31)-1)2147483647。

add(e)實現:

首先去檢查一下數組的容量是否足夠

擴容到原來的1.5倍

第一次擴容後,如果容量還是小於minCapacity,就將容量擴充爲minCapacity。

足夠:直接添加

不足夠:擴容

add(e,i)實現:

檢查角標

空間檢查,如果有需要進行擴容

插入元素

擴容方法:

擴容大小爲1.5倍     int newCapacity = oldCapacity + (oldCapacity >> 1);

    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是基於動態數組實現的,在增刪時候,需要數組的拷貝複製,所以增刪時效率較低但是在讀取修改時效率高。

ArrayList的默認初始化容量是10,每次擴容時候增加原先容量的一半,也就是變爲原來的1.5倍

刪除元素時不會減少容量,若希望減少容量則調用trimToSize()

它不是線程安全的。它能存放null值。

 LinkedList

特點:底層數據結構是雙向鏈表。線程不安全。

add方法:

往鏈表的最後添加數據

    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++;
    }

remove方法:

如果添加的o爲空則刪除最後一個節點,不爲空則遍歷全部節點找到相同的然後解鏈。

   public boolean remove(Object o) {
        if (o == null) {
            for (Node<E> x = first; x != null; x = x.next) {
                if (x.item == null) {
                    unlink(x);
                    return true;
                }
            }
        } else {
            for (Node<E> x = first; x != null; x = x.next) {
                if (o.equals(x.item)) {
                    unlink(x);
                    return true;
                }
            }
        }
        return false;
    }

解鏈方法:

 E unlink(Node<E> x) {
        // assert x != null;
        final E element = x.item;
        final Node<E> next = x.next;
        final Node<E> prev = x.prev;

        if (prev == null) {
            first = next;
        } else {
            prev.next = next;
            x.prev = null;
        }

        if (next == null) {
            last = prev;
        } else {
            next.prev = prev;
            x.next = null;
        }

        x.item = null;
        size--;
        modCount++;
        return element;
    }

 總結:

底層數據結構是雙向鏈表。線程不安全。增刪速度較快但查改較慢。

Vector(瞭解)

底層數據結構是數組。線程安全,每次擴容增加原先的2倍

HashMap

特點:

1、底層結構爲散列表(哈希表)+紅黑樹實現(數組+鏈表-->散列表)。初始容量爲16最大容量爲2的31次方。桶滿並且散列表容量大於64時會從鏈表變成紅黑二叉樹 , 默認當一個元素被添加到至少有8個元素的桶中時桶中鏈表變紅黑樹 ,當一個元素被刪除後桶中只剩6個元素時紅黑樹變鏈表

2、裝填因子默認爲0.75,也就是如果表中超過了75%的位置已經填入了元素,那麼這個表就會用雙倍的桶數自動進行再散列,並擴容兩倍

3、初始容量和裝載因子對HashMap影響挺大的

hash值計算方法:

將hash值和他的高16位進行異或運算。(異或運算:相同爲0,不同爲1)

    static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

put方法: 

1、當散列表爲空時,調用resize初始化散列表

2、查看桶是否爲空,爲空則直接放入

3、若不爲空查找鏈表有沒有key相同的元素,如果有則將value值覆蓋。

 

    final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
        else {
            Node<K,V> e; K k;
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            else if (p instanceof TreeNode)
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            else {
                for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            treeifyBin(tab, hash);
                        break;
                    }
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e;
                }
            }
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }
        }
        ++modCount;
        if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        return null;
    }

LinkedList

特點:

1、底層是散列表和雙向鏈表。繼承於HashMap所以如初始容量、裝載因子等參數函數和HashMap相同。

2、允許爲null,不同步

3、插入的順序是有序的(底層鏈表致使有序)

4、裝載因子和初始容量對LinkedHashMap影響是很大的~

5、LinkedHashMap遍歷的是內部維護的雙向鏈表,所以說初始容量對LinkedHashMap遍歷是不受影響的

 TreeMap

特點:

1、TreeMap底層是紅黑樹,它方法的時間複雜度都不會太高:log(n),map集合有序。

2、非同步

3、TreeMap實現了NavigableMap接口,而NavigableMap接口繼承着SortedMap接口,致使我們的TreeMap是有序的

4、使用Comparator或者Comparable來比較key是否相等與排序的問題~

​​​​​​​ConcurrentHashMap

1、​​​​​​​底層結構是散列表(數組+鏈表)+紅黑樹,這一點和HashMap是一樣的。

2、Hashtable是將所有的方法進行同步,效率低下。而ConcurrentHashMap作爲一個高併發的容器,它是通過部分鎖定+CAS算法來進行實現線程安全的。CAS算法也可以認爲是樂觀鎖的一種~

3、在高併發環境下,統計數據(計算size…等等)其實是無意義的,因爲在下一時刻size值就變化了。

4、get方法是非阻塞,無鎖的。重寫Node類,通過volatile修飾next來實現每次獲取都是最新設置的值

5、​​​​​​​​​​​​​​ConcurrentHashMapkeyValue都不能爲null

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