乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      HashMap

       印度阿三17 2019-07-30

      java.util.Map接口是JDK1.2開(kāi)始提供的一個(gè)基于鍵值對(duì)的散列表接口,其設(shè)計(jì)的初衷是為了替換JDK1.0中的java.util.Dictionary抽象類(lèi)。Dictionary是JDK最初的鍵值對(duì)類(lèi),它不可以存儲(chǔ)null作為key和value,目前這個(gè)類(lèi)早已不被使用了。目前都是在使用Map接口,它是可以存儲(chǔ)null值作為key和value,但Map的key是不可以重復(fù)的。其常用的實(shí)現(xiàn)類(lèi)主要有HashMap,TreeMap,ConcurrentHashMap等

      HashMap源碼解讀

      目前JDK已經(jīng)發(fā)布到JDK12,主流的JDK版本是JDK8, 但是如果閱讀HashMap的源碼建議先看JDK7的源碼。JDK7和JDK8的源碼中HashMap的實(shí)現(xiàn)原理大體相同,只不過(guò)是在JDK8中做了部分優(yōu)化。但是JDK8的源碼可讀性非常差。

      HashMap 是一個(gè)存儲(chǔ)鍵值對(duì)(key-value)映射的散列表,繼承于AbstractMap,實(shí)現(xiàn)了Map、Cloneable、java.io.Serializable接口,HashMap是線(xiàn)程不安全的,它存儲(chǔ)的映射也是無(wú)序的。

      HashMap的底層主要是基于數(shù)組和鏈表來(lái)實(shí)現(xiàn)的(JDK8之后又引入了紅黑樹(shù)),數(shù)據(jù)存儲(chǔ)時(shí)會(huì)通過(guò)對(duì)key進(jìn)行哈希操作取到哈希值,然后將哈希值對(duì)數(shù)組長(zhǎng)度取模,得到的值就是該鍵值對(duì)在數(shù)組中的索引index值,如果數(shù)組該位置沒(méi)有值則直接將該鍵值對(duì)放在該位置,如果該位置已經(jīng)有值則將其插入相應(yīng)鏈表的位置,JDK8開(kāi)始為優(yōu)化鏈表長(zhǎng)度過(guò)長(zhǎng)導(dǎo)致的性能問(wèn)題從而引入了紅黑樹(shù),當(dāng)鏈表的長(zhǎng)度大于8時(shí)會(huì)自動(dòng)將鏈表轉(zhuǎn)成紅黑樹(shù)。

      JDK7中HashMap的源碼解讀

      JDK7中HashMap采用Entry數(shù)組來(lái)存儲(chǔ)鍵值對(duì),每一個(gè)鍵值對(duì)組成了一個(gè)Entry實(shí)體,Entry類(lèi)實(shí)際上是一個(gè)單向的鏈表結(jié)構(gòu),它具有Next指針,可以連接下一個(gè)Entry實(shí)體組成鏈表。

      img

      JDK7中HashMap源碼中的主要字段

      // 數(shù)組默認(rèn)的大小
      // 1 << 4,表示1,左移4位,變成10000,即16,以二進(jìn)制形式運(yùn)行,效率更高
      static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;
      
      // 數(shù)組最大值
      static final int MAXIMUM_CAPACITY = 1 << 30; 
      
      // 默認(rèn)的負(fù)載因子
      static final float DEFAULT_LOAD_FACTOR = 0.75f;
      
      // 真正存放數(shù)據(jù)的數(shù)組
      transient Entry<K,V>[] table = (Entry<K,V>[]) EMPTY_TABLE;
      

      HashMap中默認(rèn)的數(shù)組容量為 16,負(fù)載因子為 0.75。Map 在使用過(guò)程中不斷的往里面存放數(shù)據(jù),當(dāng)數(shù)量達(dá)到了 16 * 0.75 = 12 就需要將當(dāng)前 16 的容量進(jìn)行擴(kuò)容,而擴(kuò)容這個(gè)過(guò)程涉及到 rehash、復(fù)制數(shù)據(jù)等操作,所以非常消耗性能。因此通常建議能提前預(yù)估 HashMap 的大小最好,盡量的減少擴(kuò)容帶來(lái)的性能損耗。

      JDK7中HashMap源碼中的構(gòu)造器

      
          /**  默認(rèn)的初始化容量、默認(rèn)的加載因子
           * Constructs an empty <tt>HashMap</tt> with the default initial capacity
           * (16) and the default load factor (0.75).
           */
          public HashMap() {    //16  0.75
              this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
          }
      
          /**
           * Constructs an empty <tt>HashMap</tt> with the specified initial
           * capacity and the default load factor (0.75).
           *
           * @param  initialCapacity the initial capacity.
           * @throws IllegalArgumentException if the initial capacity is negative.
           */
          public HashMap(int initialCapacity) {
              this(initialCapacity, DEFAULT_LOAD_FACTOR);
          }
      
          /**   做了兩件事:1、為threshold、loadFactor賦值   2、調(diào)用init()
           * Constructs an empty <tt>HashMap</tt> with the specified initial
           * capacity and load factor.
           *
           * @param  initialCapacity the initial capacity
           * @param  loadFactor      the load factor
           * @throws IllegalArgumentException if the initial capacity is negative
           *         or the load factor is nonpositive
           */
          public HashMap(int initialCapacity, float loadFactor) {
              if (initialCapacity < 0)
                  throw new IllegalArgumentException("Illegal initial capacity: "  
                                                     initialCapacity);
              if (initialCapacity > MAXIMUM_CAPACITY)     //限制最大容量
                  initialCapacity = MAXIMUM_CAPACITY;
              if (loadFactor <= 0 || Float.isNaN(loadFactor))     //檢查 loadFactor
                  throw new IllegalArgumentException("Illegal load factor: "  
                                                     loadFactor);
              //真正在做的,只是記錄下loadFactor、initialCpacity的值
              this.loadFactor = loadFactor;       //記錄下loadFactor
              threshold = initialCapacity;        //初始的 閾值threshold=initialCapacity=16
              init();
          }
      
          /**
           * Constructs a new <tt>HashMap</tt> with the same mappings as the
           * specified <tt>Map</tt>.  The <tt>HashMap</tt> is created with
           * default load factor (0.75) and an initial capacity sufficient to
           * hold the mappings in the specified <tt>Map</tt>.
           *
           * @param   m the map whose mappings are to be placed in this map
           * @throws  NullPointerException if the specified map is null
           */
          public HashMap(Map<? extends K, ? extends V> m) {
              this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR)   1,
                            DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR);
              inflateTable(threshold);
      
              putAllForCreate(m);
          }
      

      JDK7中HashMap源碼中的put方法

      
          /**
           * Associates the specified value with the specified key in this map.
           * If the map previously contained a mapping for the key, the old
           * value is replaced.
           *
           * @param key key with which the specified value is to be associated
           * @param value value to be associated with the specified key
           * @return the previous value associated with <tt>key</tt>, or
           *         <tt>null</tt> if there was no mapping for <tt>key</tt>.
           *         (A <tt>null</tt> return can also indicate that the map
           *         previously associated <tt>null</tt> with <tt>key</tt>.)
           */
          public V put(K key, V value) {
              if (table == EMPTY_TABLE) {
                  inflateTable(threshold);    //初始化表 (初始化、擴(kuò)容 合并為了一個(gè)方法)
              }
              if (key == null)        //對(duì)key為null做特殊處理
                  return putForNullKey(value);
              int hash = hash(key);           //計(jì)算hash值
              int i = indexFor(hash, table.length);   //根據(jù)hash值計(jì)算出index下標(biāo)
              for (Entry<K,V> e = table[i]; e != null; e = e.next) {  //遍歷下標(biāo)為i處的鏈表
                  Object k;
                  if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {  //如果key值相同,覆蓋舊值,返回新值
                      V oldValue = e.value;
                      e.value = value;    //新值 覆蓋 舊值
                      e.recordAccess(this);   //do nothing
                      return oldValue;    //返回舊值
                  }
              }
      
              modCount  ;         //修改次數(shù) 1,類(lèi)似于一個(gè)version number
              addEntry(hash, key, value, i);
              return null;
          }
      
      
          /**
           * Adds a new entry with the specified key, value and hash code to
           * the specified bucket.  It is the responsibility of this
           * method to resize the table if appropriate.
           *
           * Subclass overrides this to alter the behavior of put method.
           */
          void addEntry(int hash, K key, V value, int bucketIndex) {
              if ((size >= threshold) && (null != table[bucketIndex])) {  //如果size大于threshold && table在下標(biāo)為index的地方已經(jīng)有entry了
                  resize(2 * table.length);       //擴(kuò)容,將數(shù)組長(zhǎng)度變?yōu)樵瓉?lái)兩倍
                  hash = (null != key) ? hash(key) : 0;       //重新計(jì)算 hash 值
                  bucketIndex = indexFor(hash, table.length); //重新計(jì)算下標(biāo)
              }
      
              createEntry(hash, key, value, bucketIndex);     //創(chuàng)建entry
          }
      
          /**
           * Rehashes the contents of this map into a new array with a
           * larger capacity.  This method is called automatically when the
           * number of keys in this map reaches its threshold.
           *
           * If current capacity is MAXIMUM_CAPACITY, this method does not
           * resize the map, but sets threshold to Integer.MAX_VALUE.
           * This has the effect of preventing future calls.
           *
           * @param newCapacity the new capacity, MUST be a power of two;
           *        must be greater than current capacity unless current
           *        capacity is MAXIMUM_CAPACITY (in which case value
           *        is irrelevant).
           */
          void resize(int newCapacity) {
              Entry[] oldTable = table;
              int oldCapacity = oldTable.length;
              if (oldCapacity == MAXIMUM_CAPACITY) {  //狀態(tài)檢查
                  threshold = Integer.MAX_VALUE;
                  return;
              }
      
              Entry[] newTable = new Entry[newCapacity];      //實(shí)例化新的table
              transfer(newTable, initHashSeedAsNeeded(newCapacity));  //賦值數(shù)組元素到新的數(shù)組
              table = newTable;
              threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY   1);
          }
      
          /**
           * Transfers all entries from current table to newTable.
           */
          void transfer(Entry[] newTable, boolean rehash) {
              int newCapacity = newTable.length;
              for (Entry<K,V> e : table) {
                  while(null != e) {
                      Entry<K,V> next = e.next;
                      if (rehash) {
                          e.hash = null == e.key ? 0 : hash(e.key);       //對(duì)key進(jìn)行hash
                      }
                      int i = indexFor(e.hash, newCapacity);      //用新的index來(lái)取模
                      e.next = newTable[i];
                      newTable[i] = e;            //把元素存入新table新的新的index處
                      e = next;
                  }
              }
          }
      
          /**
           * Like addEntry except that this version is used when creating entries
           * as part of Map construction or "pseudo-construction" (cloning,
           * deserialization).  This version needn't worry about resizing the table.
           *
           * Subclass overrides this to alter the behavior of HashMap(Map),
           * clone, and readObject.
           */
          void createEntry(int hash, K key, V value, int bucketIndex) {
              Entry<K,V> e = table[bucketIndex];      //獲取table中存的entry
              table[bucketIndex] = new Entry<>(hash, key, value, e);   //將新的entry放到數(shù)組中,next指向舊的table[i]
              size  ;         //修改map中元素個(gè)數(shù)
          }
      

      JDK7中HashMap源碼中的put方法

      
          /**
           * Returns the value to which the specified key is mapped,
           * or {@code null} if this map contains no mapping for the key.
           *
           * <p>More formally, if this map contains a mapping from a key
           * {@code k} to a value {@code v} such that {@code (key==null ? k==null :
           * key.equals(k))}, then this method returns {@code v}; otherwise
           * it returns {@code null}.  (There can be at most one such mapping.)
           *
           * <p>A return value of {@code null} does not <i>necessarily</i>
           * indicate that the map contains no mapping for the key; it's also
           * possible that the map explicitly maps the key to {@code null}.
           * The {@link #containsKey containsKey} operation may be used to
           * distinguish these two cases.
           *
           * @see #put(Object, Object)
           */
          public V get(Object key) {
              if (key == null)
                  return getForNullKey();
              Entry<K,V> entry = getEntry(key);
      
              return null == entry ? null : entry.getValue();
          }
      
      
          /**
           * Returns the entry associated with the specified key in the
           * HashMap.  Returns null if the HashMap contains no mapping
           * for the key.
           */
          final Entry<K,V> getEntry(Object key) {
              if (size == 0) {
                  return null;
              }
      
              int hash = (key == null) ? 0 : hash(key);
              for (Entry<K,V> e = table[indexFor(hash, table.length)];
                   e != null;
                   e = e.next) {
                  Object k;
                  if (e.hash == hash &&
                      ((k = e.key) == key || (key != null && key.equals(k))))
                      return e;
              }
              return null;
          }
      

      JDK8中HashMap的源碼解讀

      JDK8中HashMap采用Node數(shù)組來(lái)存儲(chǔ)鍵值對(duì),Node其實(shí)就是JDK7中的Entry,只不過(guò)是換了一個(gè)名字,同樣每一個(gè)鍵值對(duì)組成了一個(gè)Node實(shí)體,然后組成鏈表。當(dāng) Hash 沖突嚴(yán)重時(shí),鏈表會(huì)變的越來(lái)越長(zhǎng),這樣在查詢(xún)時(shí)的效率就會(huì)越來(lái)越低,JDK8所做的優(yōu)化就是,當(dāng)鏈表的長(zhǎng)度達(dá)到8的時(shí)候會(huì)轉(zhuǎn)變成紅黑樹(shù)TreeNode。

      img

      JDK8中HashMap源碼中的主要字段

      static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;
      
      static final int MAXIMUM_CAPACITY = 1 << 30;
      
      static final float DEFAULT_LOAD_FACTOR = 0.75f;
      
      // 用于判斷是否需要將鏈表轉(zhuǎn)換為紅黑樹(shù)的閾值
      static final int TREEIFY_THRESHOLD = 8;
      
      // 用于判斷是否需要將紅黑樹(shù)轉(zhuǎn)換為鏈表的閾值
      static final int UNTREEIFY_THRESHOLD = 6;
      
      static final int MIN_TREEIFY_CAPACITY = 64;
      
      // 存放數(shù)據(jù)的數(shù)組
      transient Node<K,V>[] table;
      

      JDK8中HashMap源碼中的構(gòu)造器

          /**
           * Constructs an empty <tt>HashMap</tt> with the default initial capacity
           * (16) and the default load factor (0.75).
           */
          public HashMap() {
              this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
          }
      
          /**
           * Constructs an empty <tt>HashMap</tt> with the specified initial
           * capacity and the default load factor (0.75).
           *
           * @param  initialCapacity the initial capacity.
           * @throws IllegalArgumentException if the initial capacity is negative.
           */
          public HashMap(int initialCapacity) {
              this(initialCapacity, DEFAULT_LOAD_FACTOR);
          }
      
          /**
           * Constructs an empty <tt>HashMap</tt> with the specified initial
           * capacity and load factor.
           *
           * @param  initialCapacity the initial capacity
           * @param  loadFactor      the load factor
           * @throws IllegalArgumentException if the initial capacity is negative
           *         or the load factor is nonpositive
           */
          public HashMap(int initialCapacity, float loadFactor) {
              if (initialCapacity < 0)
                  throw new IllegalArgumentException("Illegal initial capacity: "  
                                                     initialCapacity);
              if (initialCapacity > MAXIMUM_CAPACITY)
                  initialCapacity = MAXIMUM_CAPACITY;
              if (loadFactor <= 0 || Float.isNaN(loadFactor))
                  throw new IllegalArgumentException("Illegal load factor: "  
                                                     loadFactor);
              this.loadFactor = loadFactor;
              this.threshold = tableSizeFor(initialCapacity);
          }
      
          /**
           * Constructs a new <tt>HashMap</tt> with the same mappings as the
           * specified <tt>Map</tt>.  The <tt>HashMap</tt> is created with
           * default load factor (0.75) and an initial capacity sufficient to
           * hold the mappings in the specified <tt>Map</tt>.
           *
           * @param   m the map whose mappings are to be placed in this map
           * @throws  NullPointerException if the specified map is null
           */
          public HashMap(Map<? extends K, ? extends V> m) {
              this.loadFactor = DEFAULT_LOAD_FACTOR;
              putMapEntries(m, false);
          }
      

      JDK8中HashMap源碼中的put方法

      
          /**
           * Associates the specified value with the specified key in this map.
           * If the map previously contained a mapping for the key, the old
           * value is replaced.
           *
           * @param key key with which the specified value is to be associated
           * @param value value to be associated with the specified key
           * @return the previous value associated with <tt>key</tt>, or
           *         <tt>null</tt> if there was no mapping for <tt>key</tt>.
           *         (A <tt>null</tt> return can also indicate that the map
           *         previously associated <tt>null</tt> with <tt>key</tt>.)
           */
          public V put(K key, V value) {
              return putVal(hash(key), key, value, false, true);
          }
      
          /**
           * Implements Map.put and related methods.  添加元素
           *
           * @param hash hash for key
           * @param key the key
           * @param value the value to put
           * @param onlyIfAbsent if true, don't change existing value
           * @param evict if false, the table is in creation mode.
           * @return previous value, or null if none
           */
          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)     //若table為null
                  n = (tab = resize()).length;                        //resize
              if ((p = tab[i = (n - 1) & hash]) == null)              //計(jì)算下標(biāo)i,取出i處的元素為p,如果p為null
                  tab[i] = newNode(hash, key, value, null);       //創(chuàng)建新的node,放到數(shù)組中
              else {                  //若 p!=null
                  Node<K,V> e; K k;
                  if (p.hash == hash &&
                      ((k = p.key) == key || (key != null && key.equals(k))))     //若key相同
                      e = p;      //直接覆蓋
                  else if (p instanceof TreeNode)     //如果為 樹(shù)節(jié)點(diǎn)
                      e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);     //放到樹(shù)中
                  else {                                          //如果key不相同,也不是treeNode
                      for (int binCount = 0; ;   binCount) {      //遍歷i處的鏈表
                          if ((e = p.next) == null) {             //找到尾部
                              p.next = newNode(hash, key, value, null);       //在末尾添加一個(gè)node
                              if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st    //如果鏈表長(zhǎng)度  >= 8
                                  treeifyBin(tab, hash);             //將鏈表轉(zhuǎn)成共黑樹(shù)
                              break;
                          }
                          if (e.hash == hash &&
                              ((k = e.key) == key || (key != null && key.equals(k))))     //若果key相同,直接退出循環(huán)
                              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;
          }
      
          /**
           * Replaces all linked nodes in bin at index for given hash unless
           * table is too small, in which case resizes instead.
           */
          final void treeifyBin(Node<K,V>[] tab, int hash) {
              int n, index; Node<K,V> e;
              if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
                  resize();
              else if ((e = tab[index = (n - 1) & hash]) != null) {
                  TreeNode<K,V> hd = null, tl = null;
                  do {
                      TreeNode<K,V> p = replacementTreeNode(e, null);
                      if (tl == null)
                          hd = p;
                      else {
                          p.prev = tl;
                          tl.next = p;
                      }
                      tl = p;
                  } while ((e = e.next) != null);
                  if ((tab[index] = hd) != null)
                      hd.treeify(tab);
              }
          }
      
         /**
           * Initializes or doubles table size.  If null, allocates in
           * accord with initial capacity target held in field threshold.
           * Otherwise, because we are using power-of-two expansion, the
           * elements from each bin must either stay at same index, or move
           * with a power of two offset in the new table.
           *
           * @return the table
           */
          final Node<K,V>[] resize() {
              Node<K,V>[] oldTab = table;
              int oldCap = (oldTab == null) ? 0 : oldTab.length;  // 如果 舊數(shù)組為null就講舊的容量看做是0,否則用舊的table長(zhǎng)度當(dāng)做容量
              int oldThr = threshold;
              int newCap, newThr = 0;
              if (oldCap > 0) {
                  if (oldCap >= MAXIMUM_CAPACITY) {
                      threshold = Integer.MAX_VALUE;
                      return oldTab;
                  }
                  else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
                           oldCap >= DEFAULT_INITIAL_CAPACITY)
                      newThr = oldThr << 1; // double threshold
              }
              else if (oldThr > 0) // initial capacity was placed in threshold
                  newCap = oldThr;
              else {               // zero initial threshold signifies using defaults
                  newCap = DEFAULT_INITIAL_CAPACITY;
                  newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
              }
              if (newThr == 0) {
                  float ft = (float)newCap * loadFactor;
                  newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
                            (int)ft : Integer.MAX_VALUE);
              }
              threshold = newThr;
              @SuppressWarnings({"rawtypes","unchecked"})
              Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];     //創(chuàng)建新的數(shù)組
              table = newTab;                                         //賦值給table
              if (oldTab != null) {
                  for (int j = 0; j < oldCap;   j) {
                      Node<K,V> e;
                      if ((e = oldTab[j]) != null) {
                          oldTab[j] = null;
                          if (e.next == null)
                              newTab[e.hash & (newCap - 1)] = e;
                          else if (e instanceof TreeNode)
                              ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
                          else { // preserve order
                              Node<K,V> loHead = null, loTail = null;
                              Node<K,V> hiHead = null, hiTail = null;
                              Node<K,V> next;
                              do {
                                  next = e.next;
                                  if ((e.hash & oldCap) == 0) {
                                      if (loTail == null)
                                          loHead = e;
                                      else
                                          loTail.next = e;
                                      loTail = e;
                                  }
                                  else {
                                      if (hiTail == null)
                                          hiHead = e;
                                      else
                                          hiTail.next = e;
                                      hiTail = e;
                                  }
                              } while ((e = next) != null);
                              if (loTail != null) {
                                  loTail.next = null;
                                  newTab[j] = loHead;
                              }
                              if (hiTail != null) {
                                  hiTail.next = null;
                                  newTab[j   oldCap] = hiHead;
                              }
                          }
                      }
                  }
              }
              return newTab;
          }
      

      JDK8中HashMap源碼中的get方法

      
          /**
           * Returns the value to which the specified key is mapped,
           * or {@code null} if this map contains no mapping for the key.
           *
           * <p>More formally, if this map contains a mapping from a key
           * {@code k} to a value {@code v} such that {@code (key==null ? k==null :
           * key.equals(k))}, then this method returns {@code v}; otherwise
           * it returns {@code null}.  (There can be at most one such mapping.)
           *
           * <p>A return value of {@code null} does not <i>necessarily</i>
           * indicate that the map contains no mapping for the key; it's also
           * possible that the map explicitly maps the key to {@code null}.
           * The {@link #containsKey containsKey} operation may be used to
           * distinguish these two cases.
           *
           * @see #put(Object, Object)
           */
          public V get(Object key) {
              Node<K,V> e;
              return (e = getNode(hash(key), key)) == null ? null : e.value;
          }
      
          /**
           * Implements Map.get and related methods.
           *
           * @param hash hash for key
           * @param key the key
           * @return the node, or null if none
           */
          final Node<K,V> getNode(int hash, Object key) {
              Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
              if ((tab = table) != null && (n = tab.length) > 0 &&
                  (first = tab[(n - 1) & hash]) != null) {
                  if (first.hash == hash && // always check first node
                      ((k = first.key) == key || (key != null && key.equals(k))))
                      return first;
                  if ((e = first.next) != null) {
                      if (first instanceof TreeNode)
                          return ((TreeNode<K,V>)first).getTreeNode(hash, key);
                      do {
                          if (e.hash == hash &&
                              ((k = e.key) == key || (key != null && key.equals(k))))
                              return e;
                      } while ((e = e.next) != null);
                  }
              }
              return null;
          }
      

      ConcurrentHashMap源碼解讀

      ConcurrentHashMap是一個(gè)線(xiàn)程安全的HashMap實(shí)現(xiàn),ConcurrentHashMap在JDK7和JDK8中的實(shí)現(xiàn)差別比較大,JDK7中ConcurrentHashMap是使用Segment數(shù)組來(lái)存放數(shù)據(jù),一個(gè)Segment就相當(dāng)于一個(gè)HashMap的數(shù)據(jù)結(jié)構(gòu),每個(gè)Segment使用一個(gè)鎖。JDK8之后Segment雖保留,但僅是為了兼容舊版本,已經(jīng)不再使用,JDK8中ConcurrentHashMap使用和HashMap一樣的數(shù)據(jù)結(jié)構(gòu)Node數(shù)組來(lái)存儲(chǔ)數(shù)據(jù),每個(gè)數(shù)組位置使用一個(gè)鎖。

      JDK7中的ConcurrentHashMap源碼解讀

      JDK7中ConcurrentHashMap的底層Segment組,而Segment其實(shí)就是特殊的HashMap,Segment的數(shù)據(jù)結(jié)構(gòu)跟HashMap一樣,同時(shí)它繼承了ReentrantLock,通過(guò)ReentrantLock提供的鎖實(shí)現(xiàn)了線(xiàn)程的安全。ConcurrentHashMap使用分段鎖技術(shù),將數(shù)據(jù)分成一段一段的存儲(chǔ),每個(gè)Segment就是一段,然后給每一段數(shù)據(jù)配一把鎖,當(dāng)一個(gè)線(xiàn)程占用鎖訪(fǎng)問(wèn)其中一個(gè)段數(shù)據(jù)的時(shí)候,其他段的數(shù)據(jù)也能被其他線(xiàn)程訪(fǎng)問(wèn),能夠?qū)崿F(xiàn)并發(fā)訪(fǎng)問(wèn),Segment數(shù)組的長(zhǎng)度就是ConcurrentHashMap的線(xiàn)程并行級(jí)別,Segment數(shù)組默認(rèn)的長(zhǎng)度為16,也就是說(shuō)最多同時(shí)可以有16個(gè)線(xiàn)程去訪(fǎng)問(wèn)ConcurrentHashMap。segment 數(shù)組不能擴(kuò)容,而是對(duì) segment 數(shù)組某個(gè)位置的segmen內(nèi)部的數(shù)組HashEntry[] 進(jìn)行擴(kuò)容,擴(kuò)容后容量為原來(lái)的 2 倍,該方法沒(méi)有考慮并發(fā),因?yàn)閳?zhí)行該方法之前已經(jīng)獲取了鎖。

      img

      JDK7中的ConcurrentHashMap源碼中的主要字段

      // 數(shù)組默認(rèn)大小
      static final int DEFAULT_INITIAL_CAPACITY = 16;
      
      // 默認(rèn)的負(fù)載因子
      static final float DEFAULT_LOAD_FACTOR = 0.75f;
      
      // 默認(rèn)線(xiàn)程并發(fā)度
      static final int DEFAULT_CONCURRENCY_LEVEL = 16;
      
      static final int MIN_SEGMENT_TABLE_CAPACITY = 2;
      
      static final int MAX_SEGMENTS = 1 << 16;
      
      // 數(shù)組最大大小
      static final int MAXIMUM_CAPACITY = 1 << 30;
      
      static final int MAXIMUM_CAPACITY = 1 << 30;
      
      static final int RETRIES_BEFORE_LOCK = 2;
      

      JDK7中的ConcurrentHashMap源碼中的構(gòu)造器

          /**
           * Creates a new, empty map with a default initial capacity (16),
           * load factor (0.75) and concurrencyLevel (16).
           */
          public ConcurrentHashMap() {
              this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
          }
      
          /**
           * Creates a new, empty map with the specified initial capacity,
           * and with default load factor (0.75) and concurrencyLevel (16).
           *
           * @param initialCapacity the initial capacity. The implementation
           * performs internal sizing to accommodate this many elements.
           * @throws IllegalArgumentException if the initial capacity of
           * elements is negative.
           */
          public ConcurrentHashMap(int initialCapacity) {
              this(initialCapacity, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
          }
      
          /**
           * Creates a new, empty map with the specified initial capacity
           * and load factor and with the default concurrencyLevel (16).
           *
           * @param initialCapacity The implementation performs internal
           * sizing to accommodate this many elements.
           * @param loadFactor  the load factor threshold, used to control resizing.
           * Resizing may be performed when the average number of elements per
           * bin exceeds this threshold.
           * @throws IllegalArgumentException if the initial capacity of
           * elements is negative or the load factor is nonpositive
           *
           * @since 1.6
           */
          public ConcurrentHashMap(int initialCapacity, float loadFactor) {
              this(initialCapacity, loadFactor, DEFAULT_CONCURRENCY_LEVEL);
          }
      
          /**
           * Creates a new, empty map with the specified initial
           * capacity, load factor and concurrency level.
           *
           * @param initialCapacity the initial capacity. The implementation
           * performs internal sizing to accommodate this many elements.
           * @param loadFactor  the load factor threshold, used to control resizing.
           * Resizing may be performed when the average number of elements per
           * bin exceeds this threshold.
           * @param concurrencyLevel the estimated number of concurrently
           * updating threads. The implementation performs internal sizing
           * to try to accommodate this many threads.
           * @throws IllegalArgumentException if the initial capacity is
           * negative or the load factor or concurrencyLevel are
           * nonpositive.
           */
          @SuppressWarnings("unchecked")
          public ConcurrentHashMap(int initialCapacity,
                                   float loadFactor, int concurrencyLevel) {
              if (!(loadFactor > 0) || initialCapacity < 0 || concurrencyLevel <= 0)  //參數(shù)檢查
                  throw new IllegalArgumentException();
              if (concurrencyLevel > MAX_SEGMENTS)    //ConcurrentcyLevel實(shí)際上就是最大并發(fā)數(shù)
                  concurrencyLevel = MAX_SEGMENTS;
              // Find power-of-two sizes best matching arguments
              int sshift = 0;
              int ssize = 1;
              while (ssize < concurrencyLevel) {
                    sshift;
                  ssize <<= 1;
              }
              this.segmentShift = 32 - sshift;
              this.segmentMask = ssize - 1;
              if (initialCapacity > MAXIMUM_CAPACITY)
                  initialCapacity = MAXIMUM_CAPACITY;
              int c = initialCapacity / ssize;
              if (c * ssize < initialCapacity)
                    c;
              int cap = MIN_SEGMENT_TABLE_CAPACITY;
              while (cap < c)
                  cap <<= 1;
              // create segments and segments[0]
              Segment<K,V> s0 =
                  new Segment<K,V>(loadFactor, (int)(cap * loadFactor),
                                   (HashEntry<K,V>[])new HashEntry[cap]);     //創(chuàng)建一個(gè)segment
              Segment<K,V>[] ss = (Segment<K,V>[])new Segment[ssize];         //創(chuàng)建一個(gè)segment數(shù)組
              UNSAFE.putOrderedObject(ss, SBASE, s0); // ordered write of segments[0]     //將s0設(shè)置為ss的第一個(gè)元素
              this.segments = ss;             //將ss作為segments
          }
      

      JDK7中的ConcurrentHashMap源碼中put方法

      
          /**
           * Maps the specified key to the specified value in this table.
           * Neither the key nor the value can be null.
           *
           * <p> The value can be retrieved by calling the <tt>get</tt> method
           * with a key that is equal to the original key.
           *
           * @param key key with which the specified value is to be associated
           * @param value value to be associated with the specified key
           * @return the previous value associated with <tt>key</tt>, or
           *         <tt>null</tt> if there was no mapping for <tt>key</tt>
           * @throws NullPointerException if the specified key or value is null
           */
          @SuppressWarnings("unchecked")
          public V put(K key, V value) {
              Segment<K,V> s;
              if (value == null)
                  throw new NullPointerException();
              int hash = hash(key);       // 計(jì)算Hash值
              int j = (hash >>> segmentShift) & segmentMask;      //計(jì)算下標(biāo)j
              if ((s = (Segment<K,V>)UNSAFE.getObject          // nonvolatile; recheck
                   (segments, (j << SSHIFT)   SBASE)) == null) //  in ensureSegment
                  s = ensureSegment(j);       //若j處有segment就返回,若沒(méi)有就創(chuàng)建并返回
              return s.put(key, hash, value, false);  //將值put到segment中去
          }
      
              // Segment 中put數(shù)據(jù)的方法
              final V put(K key, int hash, V value, boolean onlyIfAbsent) {
                  HashEntry<K,V> node = tryLock() ? null :
                      scanAndLockForPut(key, hash, value);        //如果tryLock成功,就返回null,否則。。。
                  V oldValue;
                  try {
                      HashEntry<K,V>[] tab = table;
                      int index = (tab.length - 1) & hash;        //根據(jù)table數(shù)組的長(zhǎng)度 和 hash值計(jì)算index小標(biāo)
                      HashEntry<K,V> first = entryAt(tab, index); //找到table數(shù)組在 index處鏈表的頭部
                      for (HashEntry<K,V> e = first;;) {      //從first開(kāi)始遍歷鏈表
                          if (e != null) {                    //若e!=null
                              K k;
                              if ((k = e.key) == key ||
                                  (e.hash == hash && key.equals(k))) {        //如果key相同
                                  oldValue = e.value;                 //獲取舊值
                                  if (!onlyIfAbsent) {                //若absent=false
                                      e.value = value;                //覆蓋舊值
                                        modCount;                     //
                                  }
                                  break;      //若已經(jīng)找到,就退出鏈表遍歷
                              }
                              e = e.next;     //若key不相同,繼續(xù)遍歷
                          }
                          else {              //直到e為null
                              if (node != null)   //將元素放到鏈表頭部
                                  node.setNext(first);
                              else
                                  node = new HashEntry<K,V>(hash, key, value, first); //創(chuàng)建新的Entry
                              int c = count   1;      //count 用來(lái)記錄元素個(gè)數(shù)
                              if (c > threshold && tab.length < MAXIMUM_CAPACITY)     //如果hashmap元素個(gè)數(shù)超過(guò)threshold,并且table長(zhǎng)度小于最大容量
                                  rehash(node);       //rehash跟resize的功能差不多,將table的長(zhǎng)度變?yōu)樵瓉?lái)的兩倍,重新打包entries,并將給定的node添加到新的table
                              else        //如果還有容量
                                  setEntryAt(tab, index, node);   //就在index處添加鏈表節(jié)點(diǎn)
                                modCount;     //修改操作數(shù)
                              count = c;      //將count 1
                              oldValue = null;    //
                              break;
                          }
                      }
                  } finally {
                      unlock();           //執(zhí)行完操作后,釋放鎖
                  }
                  return oldValue;        //返回oldValue
              }
      
        /**  將table的長(zhǎng)度變?yōu)樵瓉?lái)的兩倍,重新打包entries,并將給定的node添加到新的table
               * Doubles size of table and repacks entries, also adding the
               * given node to new table
               */
              @SuppressWarnings("unchecked")
              private void rehash(HashEntry<K,V> node) {
                  /*
                   * Reclassify nodes in each list to new table.  Because we
                   * are using power-of-two expansion, the elements from
                   * each bin must either stay at same index, or move with a
                   * power of two offset. We eliminate unnecessary node
                   * creation by catching cases where old nodes can be
                   * reused because their next fields won't change.
                   * Statistically, at the default threshold, only about
                   * one-sixth of them need cloning when a table
                   * doubles. The nodes they replace will be garbage
                   * collectable as soon as they are no longer referenced by
                   * any reader thread that may be in the midst of
                   * concurrently traversing table. Entry accesses use plain
                   * array indexing because they are followed by volatile
                   * table write.
                   */
                  HashEntry<K,V>[] oldTable = table;
                  int oldCapacity = oldTable.length;
                  int newCapacity = oldCapacity << 1;
                  threshold = (int)(newCapacity * loadFactor);
                  HashEntry<K,V>[] newTable =
                      (HashEntry<K,V>[]) new HashEntry[newCapacity];
                  int sizeMask = newCapacity - 1;
                  for (int i = 0; i < oldCapacity ; i  ) {
                      HashEntry<K,V> e = oldTable[i];
                      if (e != null) {
                          HashEntry<K,V> next = e.next;
                          int idx = e.hash & sizeMask;
                          if (next == null)   //  Single node on list
                              newTable[idx] = e;
                          else { // Reuse consecutive sequence at same slot
                              HashEntry<K,V> lastRun = e;
                              int lastIdx = idx;
                              for (HashEntry<K,V> last = next;
                                   last != null;
                                   last = last.next) {
                                  int k = last.hash & sizeMask;
                                  if (k != lastIdx) {
                                      lastIdx = k;
                                      lastRun = last;
                                  }
                              }
                              newTable[lastIdx] = lastRun;
                              // Clone remaining nodes
                              for (HashEntry<K,V> p = e; p != lastRun; p = p.next) {
                                  V v = p.value;
                                  int h = p.hash;
                                  int k = h & sizeMask;
                                  HashEntry<K,V> n = newTable[k];
                                  newTable[k] = new HashEntry<K,V>(h, p.key, v, n);
                              }
                          }
                      }
                  }
                  int nodeIndex = node.hash & sizeMask; // add the new node
                  node.setNext(newTable[nodeIndex]);
                  newTable[nodeIndex] = node;
                  table = newTable;
              }
      

      JDK7中的ConcurrentHashMap源碼中g(shù)et方法

      
          /**
           * Returns the value to which the specified key is mapped,
           * or {@code null} if this map contains no mapping for the key.
           *
           * <p>More formally, if this map contains a mapping from a key
           * {@code k} to a value {@code v} such that {@code key.equals(k)},
           * then this method returns {@code v}; otherwise it returns
           * {@code null}.  (There can be at most one such mapping.)
           *
           * @throws NullPointerException if the specified key is null
           */
          public V get(Object key) {
              Segment<K,V> s; // manually integrate access methods to reduce overhead
              HashEntry<K,V>[] tab;
              int h = hash(key);
              long u = (((h >>> segmentShift) & segmentMask) << SSHIFT)   SBASE;
              if ((s = (Segment<K,V>)UNSAFE.getObjectVolatile(segments, u)) != null &&
                  (tab = s.table) != null) {
                  for (HashEntry<K,V> e = (HashEntry<K,V>) UNSAFE.getObjectVolatile
                           (tab, ((long)(((tab.length - 1) & h)) << TSHIFT)   TBASE);
                       e != null; e = e.next) {
                      K k;
                      if ((k = e.key) == key || (e.hash == h && key.equals(k)))
                          return e.value;
                  }
              }
              return null;
          }
      

      JDK8中的ConcurrentHashMap源碼解讀

      JDK8中的ConcurrentHashMap取消了基于 Segment 的分段鎖思想,改用 CAS synchronized 控制并發(fā)操作,鎖的粒度變得更小,并發(fā)度更高。并且追隨JDK8的HashMap底層實(shí)現(xiàn),使用數(shù)組 鏈表 紅黑樹(shù)進(jìn)行數(shù)據(jù)存儲(chǔ)。

      img

      JDK8中的ConcurrentHashMap源碼中的主要字段

      private static final int MAXIMUM_CAPACITY = 1 << 30;
      
      private static final int DEFAULT_CAPACITY = 16;
      
      private static final float LOAD_FACTOR = 0.75f;
      
      static final int TREEIFY_THRESHOLD = 8;
      
      static final int UNTREEIFY_THRESHOLD = 6;
      
      static final int MIN_TREEIFY_CAPACITY = 64;
      
      private static final int MIN_TRANSFER_STRIDE = 16;
      
      static final int MOVED     = -1; // hash for forwarding nodes       //轉(zhuǎn)發(fā)節(jié)點(diǎn)的hash值
      static final int TREEBIN   = -2; // hash for roots of trees     //樹(shù)的根節(jié)點(diǎn)的hash值
      static final int RESERVED  = -3; // hash for transient reservations     //臨時(shí)節(jié)點(diǎn)的 hash值
      static final int HASH_BITS = 0x7fffffff; // usable bits of normal node hash //正常節(jié)點(diǎn)的hash值
      

      JDK8中的ConcurrentHashMap源碼中構(gòu)造器

      
          /**
           * Creates a new, empty map with the default initial table size (16).
           */
          public ConcurrentHashMap() {
          }
      
          /**
           * Creates a new, empty map with an initial table size
           * accommodating the specified number of elements without the need
           * to dynamically resize.
           *
           * @param initialCapacity The implementation performs internal
           * sizing to accommodate this many elements.
           * @throws IllegalArgumentException if the initial capacity of
           * elements is negative
           */
          public ConcurrentHashMap(int initialCapacity) {
              if (initialCapacity < 0)
                  throw new IllegalArgumentException();
              int cap = ((initialCapacity >= (MAXIMUM_CAPACITY >>> 1)) ?
                         MAXIMUM_CAPACITY :
                         tableSizeFor(initialCapacity   (initialCapacity >>> 1)   1));
              this.sizeCtl = cap;
          }
      
          /**
           * Creates a new, empty map with an initial table size based on
           * the given number of elements ({@code initialCapacity}) and
           * initial table density ({@code loadFactor}).
           *
           * @param initialCapacity the initial capacity. The implementation
           * performs internal sizing to accommodate this many elements,
           * given the specified load factor.
           * @param loadFactor the load factor (table density) for
           * establishing the initial table size
           * @throws IllegalArgumentException if the initial capacity of
           * elements is negative or the load factor is nonpositive
           *
           * @since 1.6
           */
          public ConcurrentHashMap(int initialCapacity, float loadFactor) {
              this(initialCapacity, loadFactor, 1);
          }
      
          /**
           * Creates a new, empty map with an initial table size based on
           * the given number of elements ({@code initialCapacity}), table
           * density ({@code loadFactor}), and number of concurrently
           * updating threads ({@code concurrencyLevel}).
           *
           * @param initialCapacity the initial capacity. The implementation
           * performs internal sizing to accommodate this many elements,
           * given the specified load factor.
           * @param loadFactor the load factor (table density) for
           * establishing the initial table size
           * @param concurrencyLevel the estimated number of concurrently
           * updating threads. The implementation may use this value as
           * a sizing hint.
           * @throws IllegalArgumentException if the initial capacity is
           * negative or the load factor or concurrencyLevel are
           * nonpositive
           */
          public ConcurrentHashMap(int initialCapacity,
                                   float loadFactor, int concurrencyLevel) {
              if (!(loadFactor > 0.0f) || initialCapacity < 0 || concurrencyLevel <= 0)
                  throw new IllegalArgumentException();
              if (initialCapacity < concurrencyLevel)   // Use at least as many bins
                  initialCapacity = concurrencyLevel;   // as estimated threads
              long size = (long)(1.0   (long)initialCapacity / loadFactor);
              int cap = (size >= (long)MAXIMUM_CAPACITY) ?
                  MAXIMUM_CAPACITY : tableSizeFor((int)size);
              this.sizeCtl = cap;
          }
      

      JDK8中的ConcurrentHashMap源碼中的put方法

      
          /**
           * Maps the specified key to the specified value in this table.
           * Neither the key nor the value can be null.
           *
           * <p>The value can be retrieved by calling the {@code get} method
           * with a key that is equal to the original key.
           *
           * @param key key with which the specified value is to be associated
           * @param value value to be associated with the specified key
           * @return the previous value associated with {@code key}, or
           *         {@code null} if there was no mapping for {@code key}
           * @throws NullPointerException if the specified key or value is null
           */
          public V put(K key, V value) {
              return putVal(key, value, false);
          }
      
          /** Implementation for put and putIfAbsent */
          final V putVal(K key, V value, boolean onlyIfAbsent) {
              if (key == null || value == null) throw new NullPointerException();
              int hash = spread(key.hashCode());      //計(jì)算hash值
              int binCount = 0;
              for (Node<K,V>[] tab = table;;) {   //自旋
                  Node<K,V> f; int n, i, fh;
                  if (tab == null || (n = tab.length) == 0)       //table==null || table.length==0
                      tab = initTable();                          //就initTable
                  else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {    //若下標(biāo) i 處的元素為null
                      if (casTabAt(tab, i, null,                           //直接用CAS操作,i處的元素
                                   new Node<K,V>(hash, key, value, null)))
                          break;                   // no lock when adding to empty bin   想emptybin中假如元素的時(shí)候,不需要加鎖
                  }
                  else if ((fh = f.hash) == MOVED)    //若下標(biāo) i 處的元素不為null,且f.hash==MOVED MOVED為常量值-1
                      tab = helpTransfer(tab, f);     //
                  else {                              //如果是一般的節(jié)點(diǎn)
                      V oldVal = null;
                      synchronized (f) {              //當(dāng)頭部元素不為null,且不需要轉(zhuǎn)換成樹(shù)時(shí),需要進(jìn)行同步操作
                          if (tabAt(tab, i) == f) {
                              if (fh >= 0) {          //若 鏈表頭部hash值 >=0
                                  binCount = 1;
                                  for (Node<K,V> e = f;;   binCount) {
                                      K ek;
                                      if (e.hash == hash &&
                                          ((ek = e.key) == key ||
                                           (ek != null && key.equals(ek)))) {     //如果key相同
                                          oldVal = e.val;
                                          if (!onlyIfAbsent)      //且不為absent
                                              e.val = value;      //舊值覆蓋新值
                                          break;
                                      }
                                      Node<K,V> pred = e;
                                      if ((e = e.next) == null), {     //如果鏈表遍歷完成,還沒(méi)退出,說(shuō)明沒(méi)有相同的key存在,在尾部添加節(jié)點(diǎn)
                                          pred.next = new Node<K,V>(hash, key,
                                                                    value, null);
                                          break;
                                      }
                                  }
                              }
                              else if (f instanceof TreeBin) {        //如果f是Tree的節(jié)點(diǎn)
                                  Node<K,V> p;
                                  binCount = 2;
                                  if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key,
                                                                 value)) != null) {
                                      oldVal = p.val;
                                      if (!onlyIfAbsent)
                                          p.val = value;
                                  }
                              }
                          }
                      }
                      if (binCount != 0) {
                          if (binCount >= TREEIFY_THRESHOLD)
                              treeifyBin(tab, i);
                          if (oldVal != null)
                              return oldVal;
                          break;
                      }
                  }
              }
              addCount(1L, binCount);
              return null;
          }
      
          /**
           * Initializes table, using the size recorded in sizeCtl.
           *///通過(guò)CAS搶sizeCtl,來(lái)?yè)屨糹nitTable的資格,其他線(xiàn)程自旋等待,直到table不為null
          private final Node<K,V>[] initTable() {
              Node<K,V>[] tab; int sc;
              while ((tab = table) == null || tab.length == 0) {
                  if ((sc = sizeCtl) < 0)
                      Thread.yield(); // lost initialization race; just spin  //線(xiàn)程讓步,讓其他線(xiàn)程優(yōu)先執(zhí)行
                  else if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {
                      try {
                          if ((tab = table) == null || tab.length == 0) {
                              int n = (sc > 0) ? sc : DEFAULT_CAPACITY;
                              @SuppressWarnings("unchecked")
                              Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n]; //初始化數(shù)組
                              table = tab = nt;               //將nt賦值給table
                              sc = n - (n >>> 2);
                          }
                      } finally {
                          sizeCtl = sc;
                      }
                      break;
                  }
              }
              return tab;
          }
      

      JDK8中的ConcurrentHashMap源碼中的get方法

          /**
           * Returns the value to which the specified key is mapped,
           * or {@code null} if this map contains no mapping for the key.
           *
           * <p>More formally, if this map contains a mapping from a key
           * {@code k} to a value {@code v} such that {@code key.equals(k)},
           * then this method returns {@code v}; otherwise it returns
           * {@code null}.  (There can be at most one such mapping.)
           *
           * @throws NullPointerException if the specified key is null
           */
          public V get(Object key) {
              Node<K,V>[] tab; Node<K,V> e, p; int n, eh; K ek;
              int h = spread(key.hashCode());
              if ((tab = table) != null && (n = tab.length) > 0 &&
                  (e = tabAt(tab, (n - 1) & h)) != null) {
                  if ((eh = e.hash) == h) {
                      if ((ek = e.key) == key || (ek != null && key.equals(ek)))
                          return e.val;
                  }
                  else if (eh < 0)
                      return (p = e.find(h, key)) != null ? p.val : null;
                  while ((e = e.next) != null) {
                      if (e.hash == h &&
                          ((ek = e.key) == key || (ek != null && key.equals(ek))))
                          return e.val;
                  }
              }
              return null;
          }
      ##轉(zhuǎn)載:https://www.cnblogs.com/coding-diary/p/11266349.html
      來(lái)源:https://www./content-4-370101.html

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶(hù) 評(píng)論公約

        類(lèi)似文章 更多