HashMap源码

1、 构造

// 只初始化关键参数,并没有初始table(node 数据)
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;
  // 2的整数次幂
  this.threshold = tableSizeFor(initialCapacity);
}

2、put(k, v)

public V put(K key, V value) {
   return putVal(hash(key), key, value, false, true);
}
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
               boolean evict) {
  Node<K,V>[] tab; Node<K,V> p; int n, i;
  // node 数组懒加载,如果为空,先创建table
  if ((tab = table) == null || (n = tab.length) == 0)
    n = (tab = resize()).length;
  if ((p = tab[i = (n - 1) & hash]) == null)
    // 如果该位置没有值,构建一个node,直接放这
    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)))) // 同一个key
      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)))) // 同一个key
          break;
        p = e; // 相当于p= p.next
      }
    }
    // 返回旧值
    if (e != null) { // existing mapping for key
      V oldValue = e.value;
      if (!onlyIfAbsent || oldValue == null)
        e.value = value;
      afterNodeAccess(e); // linked hashmap 的回调
      return oldValue;
    }
  }
  ++modCount;
  if (++size > threshold)
    resize();
  afterNodeInsertion(evict); // linked hashmap 的回调
  return null;
}

3、resize()

/**初始化,或者扩容2倍*/
final Node<K,V>[] resize() {
  Node<K,V>[] oldTab = table;
  int oldCap = (oldTab == null) ? 0 : oldTab.length;
  int oldThr = threshold;
  int newCap, newThr = 0;
  // 原来数组不为空
  if (oldCap > 0) {
    // 达到最大长度,把扩容阈值改成最大
    if (oldCap >= MAXIMUM_CAPACITY) {
      threshold = Integer.MAX_VALUE;
      return oldTab;
    }
    // 数组长度2倍
    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];
  table = newTab;
  // 移动原来数组中的node
  if (oldTab != null) {
    for (int j = 0; j < oldCap; ++j) {
      Node<K,V> e;
      if ((e = oldTab[j]) != null) {
        oldTab[j] = null; // fixme ??辅助GC?
        if (e.next == null)  // 该位置只有一个节点, //比如e.hash=7,oldCap=4,newCap=8,新的节点要么在3位置,要么在7位置
          newTab[e.hash & (newCap - 1)] = e;
        else if (e instanceof TreeNode) // 该位置是个树
          ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
        else { // preserve order // 按原顺序,遍历链表中的每个node
          Node<K,V> loHead = null, loTail = null;
          Node<K,V> hiHead = null, hiTail = null;
          Node<K,V> next;
          do {
            // 比如e.hash = 7,oldCap = 4,newCap = 8,新的节点要么在3位置,要么在 7 =(3 + odlCap)位置
            next = e.next;
            // hash = 7, 1 1 1
            // oldCap=4  1 0 0
            // 与计算结果为 1 0 0 =4,说明该节点在数组7位置,
            // 如果hash=3, 0 1 1,
            //  oldCap=4   1 0 0 ,
            //  与结果为0,说明在原来位置
            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); // 遍历链表的每个node
          if (loTail != null) {
            loTail.next = null;
            newTab[j] = loHead; // 线程不安全的位置,可能覆盖其他线程放在j位置的节点
          }
          if (hiTail != null) {
            hiTail.next = null;
            newTab[j + oldCap] = hiHead; // 线程不安全的位置,可能覆盖其他线程放在j位置的节点
          }
        }
      }
    }
  }
  return newTab;
}

4、为什么hashmap选择红黑树?

二叉平衡搜索树,需要频繁旋转来维持平衡,插入和删除效率差
红黑树除了旋转之外还可以通过变色来维持平衡,查询效率最差为2logn,最好为logn

红黑树:https://zhuanlan.zhihu.com/p/370703859

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值