Java基礎篇——集合淺談

原創不易,如需轉載,請註明出處http://www.javashuo.com/article/p-sgixxweu-bx.html,不然將追究法律責任!!! html

Set(基於Map來實現的,不細說)

HashSet(不重複、無序、非線程安全的集合)

  • 底層實現,源碼以下:java

    public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, java.io.Serializable {
    
          static final long serialVersionUID = -5024744406713321676L;
          //賣個關子,這裏爲啥要用transient關鍵字? 評論區見哦!
          private transient HashMap<E,Object> map;
          private static final Object PRESENT = new Object();
    
          public HashSet() {
              map = new HashMap<>();
          }
          public boolean add(E e) {
              return map.put(e, PRESENT)==null;
          }
          ...
      }

    不用多說,是不沒想到,原來HashSet是基於HashMap實現的,元素都存到HashMap鍵值對的Key上面,而Value時有一個統一的值private static final Object PRESENT = new Object();git

  • 注意:
    1. 對於HashSet中保存的對象,主要要正確重寫equals方法和hashCode方法,以保證放入Set對象的惟一性
    2. HashSet沒有提供get()方法,願意是同HashMap同樣,Set內部是無序的,只能經過迭代的方式得到

TreeSet(不重複、有序、非線程安全的集合)

  • 底層實現,源碼以下:github

    public class TreeSet<E> extends AbstractSet<E> implements NavigableSet<E>, Cloneable, java.io.Serializable {
    
          private transient NavigableMap<E,Object> m;
          private static final Object PRESENT = new Object();
          TreeSet(NavigableMap<E,Object> m) {
              this.m = m;
          }
    
          public TreeSet() {
              this(new TreeMap<E,Object>());
          }
          public boolean add(E e) {
              return m.put(e, PRESENT)==null;
          }
      }
    我去,又是這個尿性,基於TreeMap來實現的
  • 注意:
    1. 首先要正確重寫equals方法和hashCode方法,以保證放入Set對象的惟一性
    2. 須要實現Comparable接口,從而實現有序存儲

LinkedHashSet(不重複、位置有序、非線程安全的集合)

  • 底層實現,源碼以下:算法

    public class LinkedHashSet<E> extends HashSet<E> implements Set<E>, Cloneable, java.io.Serializable {
    
          private static final long serialVersionUID = -2851667679971038690L;
    
          public LinkedHashSet(int initialCapacity, float loadFactor) {
              super(initialCapacity, loadFactor, true);
          }
          public LinkedHashSet(int initialCapacity) {
              super(initialCapacity, .75f, true);
          }
          public LinkedHashSet() {
              super(16, .75f, true);
          }
          public LinkedHashSet(Collection<? extends E> c) {
              super(Math.max(2*c.size(), 11), .75f, true);
              addAll(c);
          }
      }
    都是super,實現了把HashSet中預留的構造方法啓用了,於是能夠實現有序插入(LinkedHashMap再談究竟)
  • 注意:
    1. 首先要正確重寫equals方法和hashCode方法,以保證放入Set對象的惟一性
    2. 內部實現了有序插入,因此使用時不須要考慮

Map

HashMap(無序、線程不安全)

  • Jdk1.7數據存儲結構(採用數組+鏈表)segmentfault

    hashmap.png
    hashmap2.png

  • Jdk1.8數據存儲結構(採用數組+鏈表+紅黑樹)數組

    hashmap3.png

    注意:在鏈表長度大於8後,查詢複雜度由O(n)變爲O(logn),將鏈表存儲轉換成紅黑樹存儲(也就是TreeMap)安全

  • 紅黑樹R-B Tree簡介(本質實際上是2-3-4樹):數據結構

    紅黑樹.png

    二叉樹特性:
    (1)左字數上全部的節點的值都小於或等於他的根節點上的值
    (2)右子樹上全部節點的值均大於或等於他的根節點的值
    (3)左、右子樹也分別爲二叉樹
    紅黑樹特色(一種平衡二叉樹):
    (1)每一個結點要麼是紅的要麼是黑的。
    (2)根結點是黑的。 
    (3)每一個葉結點(葉結點即指樹尾端NIL指針或NULL結點)都是黑的。 
    (4)若是一個結點是紅的,那麼它的兩個兒子都是黑的。 
    (5)對於任意結點而言,其到葉結點樹尾端NIL指針的每條路徑都包含相同數目的黑結點
    節點操做:
    (1)左旋
    (2)右旋
    (3)變色

TreeMap(有序、線程不安全)

  • 底層就是紅黑二叉樹

LinkedHashMap(有序、線程不安全)

  • 底層實現,源碼以下:併發

    static class Entry<K,V> extends HashMap.Node<K,V> {
        //這裏維護了一個before和after的Entry, 見名思意, 就是每一個Entry<K,V>都維護它的上一個元素和下一個元素的關係。這也是LinkedHashMap有序的關鍵所在。
        Entry<K,V> before, after;
        Entry(int hash, K key, V value, Node<K,V> next) {
            super(hash, key, value, next);
        }
    }

    LinkedHashMap是繼承HashMap, 也就是說LinkedHashMap的結構也是和HashMap那樣(數組+鏈表)

    注意:LinkedHashMap分爲插入的順序排列和訪問的順序排列兩種方式,經過accessOrder參數來控制

Hashtable(線程安全)

  • 底層數據結構同HashMap。線程安全,效率低,沒什麼卵用,須要使用線程安全的Map可使用ConcurrentHashMap

List

ArrayList(位置有序、可重複、線程不安全)

  • 底層數據結構是數組,查詢快

LinkedList(有序、線程不安全)

  • 底層數據結構是雙向鏈表,查詢慢,增刪快

Vector(有序、線程安全)

  • 底層數據結構是數組,查詢快,增刪慢

併發集合

ConcurrentHashMap(線程安全)

  • 利用了鎖分段的思想提升了併發度,把Map分紅了N個Segment,每一個Segment至關於HashTable

CopyOnWriteArrayList(線程安全)

  • 讀寫分離,寫時複製出一個新的數組,完成插入、修改或者移除操做後將新數組賦值給array

Queue

非阻塞隊列

  • PriorityQueue :實質上維護了一個有序列表
  • ConcurrentLinkedQueue :基於連接節點的、線程安全的隊列

阻塞隊列

  • ArrayBlockingQueue :一個由數組支持的有界隊列。
  • LinkedBlockingQueue :一個由連接節點支持的可選有界隊列。
  • PriorityBlockingQueue :一個由優先級堆支持的無界優先級隊列。
  • DelayQueue :一個由優先級堆支持的、基於時間的調度隊列。
  • SynchronousQueue :一個利用 BlockingQueue 接口的簡單彙集(rendezvous)機制。

總結

  • 原本想詳細的總結一下各類集合的使用和底層實現,但發現說來講去仍是數據結構的事,你要能把數組、鏈表、二叉樹、紅黑樹等數據結構弄明白,這些所謂的集合也就是不一樣的實現而已。
  • 之後有機會仍是直接來搞數據結構、算法吧!

我的博客地址:

csdn:https://blog.csdn.net/tiantuo6513
cnblogs:https://www.cnblogs.com/baixianlong
segmentfault:https://segmentfault.com/u/baixianlong
github:https://github.com/xianlongbai

相關文章
相關標籤/搜索