[回到起点]看看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
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
相关文章推荐
- Java中HashMap详解 - HashMap源码及实现原理
- java中hashmap源码分析和实现
- Java HashMap实现原理 源码剖析
- Java集合-HashMap源码实现深入解析
- Java菜鸟面试突破系列Java集合源码解读系列:HashMap实现原理
- Java java.util.HashMap实现原理源码分析
- Java集合之HashMap源码实现分析
- [置顶] [Java容器]HashMap实现原理和源码分析
- 看看源码怎么处理,Java中Hashtable,Hashmap,ConcurrentHashMap,Key Value为null时
- Java中HashMap底层实现原理(JDK1.8)源码分析
- Java集合源码学习(20)_Map接口的实现HashMap
- Java中HashMap底层实现原理(JDK1.8)源码分析
- (10) java源码分析 ---- HashMap源码分析 及其 实现原理分析
- (转载)Java中HashMap底层实现原理(JDK1.8)源码分析
- 哈希算法-----JAVA 源码中实现的HashMap学习总结
- Java集合源码学习(24)_ConcurrentMap的实现类ConcurrentHashMap
- [转]Java HashMap实现原理与源码分析
- Java源码---HashMap的底层实现
- Java 源码分析HashMap的工作原理及实现
- 【Java深入】HashMap的实现原理与源码剖析(一)