HashMap 源码分析
构造方法
1 | class HashMap { |
tableSizeFor 详解:
先来分析有关n位操作部分:
先来假设n的二进制为01xxx…xxx。接着
对n右移1位:001xx…xxx,再位或:011xx…xxx
对n右移2为:00011…xxx,再位或:01111…xxx
此时前面已经有四个1了,再右移4位且位或可得8个1
同理,有8个1,右移8位肯定会让后八位也为1。
综上可得,该算法让最高位的1后面的位全变为1。
最后再让结果n+1,即得到了2的整数次幂的值了。
现在回来看看第一条语句:
1 | int n = cap - 1; |
让cap-1再赋值给n的目的是另找到的目标值大于或等于原值。例如二进制1000,十进制数值为8。如果不对它减1而直接操作,将得到答案10000,即16。显然不是结果。减1后二进制为111,再进行操作则会得到原来的数值1000,即8。
put
1 | class HashMap { |
关于 modCount:
modCount用于记录HashMap的修改次数, 在HashMap的put(),get(),remove(),Interator()等方法中,都使用了该属性
由于HashMap不是线程安全的,所以在迭代的时候,会将modCount赋值到迭代器的expectedModCount属性中,然后进行迭代, 如果在迭代的过程中HashMap被其他线程修改了,modCount的数值就会发生变化, 这个时候expectedModCount和ModCount不相等, 迭代器就会抛出ConcurrentModificationException()异常
在java8之前,map 的扩容在多线程下会死循环(由于新链表和旧链表的顺序相反,多线程下会出现环),1.8解决了这个问题,但依然是非线程安全的,要使用线程安全的 map 建议使用 ConcurrentHashMap
get
1 | class HashMap { |
LinkedHashMap
继承 HashMap
put
未覆盖,但是重写了 newNode、afterNodeAccess 和 afterNodeInsertion
1 | class LinkHashMap { |