认识HashMap源码

1、Hashmap类图结构

HashMap继承于AbstractMap,实现了Map,Cloneable,Serializable接口

2、HashMap数据结构

HashMap是使用数组加链表实现,jdk1.8之后当链表个数为8的时候,链表就会转换为红黑树(平衡二叉树)

3、HashMap重要参数

 static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16

HashMap默认初始容量为16

static final int MAXIMUM_CAPACITY = 1 << 30;

HashMap最大容量为1的30次方

static final float DEFAULT_LOAD_FACTOR = 0.75f

HashMap的加载因子为0.75,即当hashmap内存储元素超过hashmap此时容量的0.75,hashmap就会进行扩容

为什么为0.75? 通常加载因子需要在时间和空间成本上寻求一种折衷,加载因子过高,例如为1,虽然节省了空间开销,提高了空间利用率,但同时也增加了查询时间的成本;加载因子过低,例如为0.5,虽然可以减少查询时间的成本,但是空间利用率很低,同时提高了rehash操作的次数。在设置初始容量时应该考虑到映射中所需的条目数及其加载因子

,以便最大限度地减少rehash的操作次数,所以一般在使用hashmap创建时建议根据预估值设置初始容量,减少扩容操作。选择0.75为加载因子,完全是时间和空间成本上折衷的选择。

static final int TREEIFY_THRESHOLD = 8;

Hashmap一个链表元素个数当超过1.8之后就会进行转红黑树(平衡二叉树)。

为什么为8?

这在HashMap源码中给出了解释,理想情况下使用随机的哈希码,容器中节点分布在hash桶中的频率遵循泊松分布,按照泊松分布计算出的对照表,当为8时,概率就很小了(0.00000006),所以就采用了8

4、HashMap方法分析

在介绍HashMap常用方法源码分析前,我们先了解下HashMap内的hash函数

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

hashcode产生的是一个int类型的数据,长度最大为32位,h>>>16即取了key hashcode的低16位

4.1 HashMap的put

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;
//判断tab是不是为空,如果是是空,那么就进行HashMap初始化
if ((tab = table) == null || (n = tab.length) == 0) n = (tab = resize()).length;//n为HashMap的容量 if ((p = tab[i = (n - 1) & hash]) == null)
//通过 i=(n-1) & hash运算刚好可以得到一个0到n-1的整数,刚好在hash桶的范围内
//假设n=16 n-1=15 15表示为0000000000001111 hash为00001001010010110 通过&运算 同1才为1,进行运算后肯定在0-15之中

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

猜你喜欢

转载自www.cnblogs.com/liujunj/p/8987336.html