您的位置:首页 > 编程语言 > Java开发

[回到起点]看看Java HashMap的源码和实现

2016-10-12 17:58 417 查看
  刚出来工作的时候,老大要我从文本提取一些数据, 筛选排序什么的,那时我只晓得用ArrayList, 结果事情是做完了,执行却有点慢。老大看代码说我是在写C语言, 让我试试用HashMap处理, 结果是哇,快好多,从此对HashMap很有好感。年复一年的面试, HashTable,HashMap,TreeMap有啥区别啊,为什么那么快啊之类, 每个工程师都会在面试中得到锻炼和成长:p。面试受打击了,可能网上一搜这个面试题,喔原来答案是这个。真去看下源码的人估计不多,老实说笔者最近才仔细拜读-_-,结合搜索的分享的文章,结果发现自己的源码太新了:p
JDK1.8的,大多文章还是JDK1.7的,突然想起看过一篇文章关于JDK重写了HashMap为了解决哈希碰撞的事。JDK能对已有老的库能升级也是蛮罕见的事,所以就有了这篇文章。

  先看JDK1.7的HashMap为什么快?



  HashMap使用Entry<K,V>[] table保存数据, 每个节点Entry.next指向另外Entry节点, next存在则表示有相同的key哈希, JDK1.7使用链表保存解决冲突。

static class Entry<K,V> implements Map.Entry<K,V> {
final K key;
V value;
Entry<K,V> next;
int hash;  HashMap查找快关键的因素是key hashcode在table数组有一个对应的下标。indexFor是精心设计过的,table.length必须为2的整数次幂, 即length-1为奇数, 奇数做位与才可能产生奇数或偶数(偶数位与就都是偶数了), 保证Entry在table数组中的均匀分布。

final Entry<K,V> getEntry(Object key) {
if (size == 0) {
return null;
}

int hash = (key == null) ? 0 : hash(key);
for (Entry<K,V> e = table[<span style="color:#FF0000;">indexFor</span>(hash, table.length)];
e != null;
e = e.next) {
Object k;
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
}
return null;
}
/**
* Returns index for hash code h.
*/
static int indexFor(int h, int length) {
//<span style="color:#FF0000;"> assert Integer.bitCount(length) == 1 : "length must be a non-zero power of 2"</span>;
return <span style="color:#FF0000;">h & (length-1)</span>;
}  话说redis,php哈希采用了类似的数据结构, 可能redis的哈希算法可能冲突会小些。
  那哈希冲突会带来什么问题呢?假设我们写个POJO, hashCode()总是返回0,这个POJO作为HashMap key值的就都冲突了,所有的Entry就退化为链表了,查找就是链表的线性效率了,有人恶意造数据造成了冲突,系统查找响应就很慢, 导致DOS拒绝服务。所以JDK1.8就稍微优化了下。

JDK1.8 HashMap改进
当哈希冲突的链表达到一定长度(好像是8),就改用红黑树解决保存节点,就算冲突多查找也不会太慢。

虎头蛇尾。。。下班了。。see you very soon。

Cheers
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: