HashMap源码分析

目录

hashmap1.8源码大纲

那么问题来了?

hashmap的数据结构?

为什么扩容长度必须是2的指数次幂也就是2的n次方?

为什么加载因子是0.75?

为什么数组转链表阈值是8?

key能否为空?

hashmap为什么线程不安全?


hashmap1.8源码大纲

1 HashMap继承与AbstratMap实现了Map、cloneable、serilizable接口。

2 首先有一个静态长整型serialVersionUID。

3 然后是一些常量的定义比如默认初始容量16,最大容量2的30次方,浮点数默认加载因子0.75,链表转树树阈值8,树转链表阈值6,最小转成树的map容量为64。

4 然后是 节点类node继承与Map的Entry,Node类有四个成员变量 hash,key,value,next,构造方法还有getKey,getValue,toString,hashCode,setvalue,equals方法。

5 然后是静态公用工具方法,比如hash(Object),comparableClassFor(Object),compareComparables(),tableSizeFor(),

6 然后是一些成员变量,Node数组table,Entry Set entrySet,size,modCount,int threshold,浮点数loadfactor, 

7 然后是一些公共的操作,HashMap的四个构造函数,putMapEntries(),size(),isEmpty(),get(),getNode(),containsKey(),put(),putVal(),resize(),treeifyBin(),putAll(),remove(),removeNode(),clear(),containsValue(),keySet(),类KeySet,values,类Values,entrySet(),类EntrySet,

8 然后是一些覆盖的方法,比如getOrDefault(),putIfAbsent(),remove(),replace(),replace(),compareIfAbsent(),compareIfAbsent(),compute(),merge(),forEach(),replaceAll(),clone(),

9 然后是一些其他的方法loadFactor(),capacity(),writeObject(),readObjet(),

10 然后是迭代器相关,抽象类HashIterator,类keyItetator,valueIterator,EntryIterator,

11 然后是分离器相关,HashMapSpliterator,keySpliterator,ValueSpliterator,EntrySpliterator,

12 然后是链表支持,newNode(),replacementNode(),newTreeNode(),replacementTreeNode(),reinitialize(),afterNodeAccess(),afterNodeInsertion(),afterNodeRemoval()

13 最后是TreeNode类,继承于LinkedHashMap.Entry

那么问题来了?

hashmap的数据结构?

数组  链表 红黑树(java>1.7)

为什么用数组?数组索引下标存取快,O(1),查找的时候也要遍历链表,

红黑树对链表性能做了优化,接近于平衡二叉树,

查找插入删除

 

为什么扩容长度必须是2的指数次幂也就是2的n次方?

因为hash运算之后存储在数组的那个位置是有hash值对数组长度取模计算完成。

1取模运算的效率低于位运算

2必须是2的n次方取模和位运算才能划等号,h&length-1 == h%length

3Java8以下会rehash,rehash将会非常消耗性能

为什么加载因子是0.75?

牛顿二项式 时间空间的平衡 .net是0.72

为什么数组转链表阈值是8?

泊松分布 8的概念非常小亿分之六,而且链表为8但是数组长度不满64也不会转红黑树。链表为8其实意味着当前链表长度为9,因为是算的表头以外长度为8.

key能否为空?

可以为空,HashMap最多只允许一条记录的键为null,允许多条记录的值为null(hashtable是不允许的,会报异常)。

static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    } //来自hashmap源码
 HashMap mHashMap = new HashMap();
        mHashMap.put(null, "11");
        mHashMap.put(null, 11);
        mHashMap.put(null, 11.9f);
        System.out.println(mHashMap.size()); //打印的值为1
 HashMap mHashMap = new HashMap();
        mHashMap.put(1, null);
        mHashMap.put(2, null);
        mHashMap.put(3, null);
        System.out.println(mHashMap.size());//打印的值为3

hashmap为什么线程不安全?

因为扩容死锁会形成链表死环。

10个线程,每个线程put100万次

为什么会形成链表死环?

扩容,链表调换顺序,第二个线程就会杨过和小龙女互相指向,形成链表死环。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值