HashMap源码解读

 

 

 

 

 

以前看源码的时候,都是草草看过,并没有去认真理解。今天准备把这个过程写下来。

写一个main函数:

Map<String, Person> personMap = new HashMap<String, Person>();

personMap.put("张三", new Person("张三", 22));

personMap.put("李四", new Person("李四", 21));

  看看构造函数:newHashMap<>();

 public HashMap() {
        this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
    }

  就是初始化了一个负载因子: DEFAULT_LOAD_FACTOR ,默认为0.75.

static final float DEFAULT_LOAD_FACTOR = 0.75f;

  好,看put方法。

public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
    }

   看hash(key),这个key 就是 我们的String,嗯,无非就是 对象的hashCode()方法,因此我们一定要重写key 的hashCode()方法,因为String已经重写了,所以我们不需要做这一步。得到hashCode,然后做一些无符号位移,然后是或运算。大家可以理解为这是在处理hashKey。

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

  然后看 putVal(hash(key), key, value, false, true);

 

 

  很长,嗯,没关系一点一点看。

我们看到了一个Node<K,V>[] tab; 这个Node是什么,一看,原来是HashMap的内部类。  

static class Node<K,V> implements Map.Entry<K,V> {
        final int hash;
        final K key;
        V value;
        Node<K,V> next;

}

  

其实很简单,一些属性,一个key,一个value,用来保存我们往Map里放入的数据,next用来标记Node节点的下一个元素。

  //hashMap的成员变量

transient Node<K,V>[] table;   

 

  

 

 if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;

 

  第一次put的时候,resize() 会分配一个长度,赋值给n,待会儿在看release(),比较复杂;

关键的代码 

因此,newCap=16,newThr = 12;

 

 

table 就是HashMap的成员变量。 因此,当我们放入第一个元素时,如果底层数组还是null,系统会初始化一个长度为16的Node数组,这一点像极了ArrayList的初始化。

 接下来,

 

这个hash值是字符串张三这个对象的hashCode方法与hashMap提供hash()方法共同计算出来的结果,n是数组的长度,目前数组长度为16,不管这个hash的值是多少,经过(n - 1) & hash计算出来的i 的值一定在0~n-1之间。刚好是底层数组的合法下标,用i这个下标值去底层数组里去取值,如果为null,创建一个Node放到数组下标为i的位置。 i 是Node数组的下标,然后,根据传过来的key,value 新建一个Node对象。就是tab[i] 的值了。

然后就是

modCount 一看就知道记录的是修改次数。

然后,return null ; 因此,hashMap put的时候,只要没有hash冲突,返回的是null。并不是value;这点要注意。

 

第二次put。

还是我们的putVal();

 

 只要算出来的下标,数组是空的,都会继续往Node里面添加新的元素。

如果,产生了冲突,也就是说,hash算出来的下标,已经有元素了,怎么办?看看hashMap怎么处理。

也就是说new一个新的Node对象并把当前Nodenext引用指向该对象,也就是说原来该位置上只有一个元素对象,现在转成了单向链表。

 

链表长度到8时,将链表转化为红黑树来处理,

JDK1.7及以前的版本中,HashMap里是没有红黑树的实现的,在JDK1.8中加入了红黑树是为了防止哈希表碰撞攻击,当链表链长度为8时,及时转成红黑树,提高map的效率

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

转载于:https://www.cnblogs.com/myJavaCareerLife-yewei/p/8043848.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值