HashMap
HashMap 是一个关联数组、哈希表,它是线程不安全的,允许key为null,value为null。遍历时无序。
其底层数据结构是数组称之为哈希桶,每个桶里面放的是链表,链表中的每个节点,就是哈希表中的每个元素。
在JDK8中,当链表长度达到8,会转化成红黑树,以提升它的查询、插入效率,它实现了Map<K,V>, Cloneable, Serializable接口。
hashcode,equals , ==
capacity、loadFactor、threshold、size概念
DEFAULT_LOAD_FACTOR = 0.75f;
源码
String中的hash()
public int hashCode() {
int h = hash;
if (h == 0 && count > 0) {
int off = offset;
char val[] = value;
int len = count;
for (int i = 0; i < len; i++) {
h = 31*h + val[off++];
}
hash = h;
}
return h;
}
h
=
R
∗
h
+
v
a
l
[
o
f
f
+
+
]
h = R * h + val[off++]
h=R∗h+val[off++]
其中R = 31,
R 为什么等于31
- 31是一个不大不小的奇素数,(偶数的hash效果都比较差)
- 31 * i == (i << 5) - i ,可以被JVM优化
- 哈希分布较为均匀
扰动函数
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
扰动函数就是为了解决hash碰撞的。它会综合hash值高位和低位的特征,并存放在低位,因此在与运算时,相当于高低位一起参与了运算,以减少hash碰撞的概率。(在JDK8之前,扰动函数会扰动四次,JDK8简化了这个操作)
如何评价Hash算法好坏?
- 尽可能分布均匀
- 效率尽可能快
MurMurHash
编译原理中如何完美hash
实现hash冲突的方式
- 拉链法
- 链表
- 红黑树
- 探测法
扩容
为什么要用2的幂指数倍数
##实现一个自定义的class作为HashMap的key该如何实现?
- 覆写hashCode以及equals方法应该遵循的原则
- Immutable
hash攻击
和hashtable 区别
- 与之相比HashTable是线程安全的,且不允许key、value是null。
- HashTable默认容量是11。
- HashTable是直接使用key的hashCode(key.hashCode())作为hash值,不像HashMap内部使用static final int hash(Object key)扰动函数对key的hashCode进行扰动后作为hash值。
- HashTable取哈希桶下标是直接用模运算%.(因为其默认容量也不是2的n次方。所以也无法用位运算替代模运算)
- 扩容时,新容量是原来的2倍+1。int newCapacity = (oldCapacity << 1) + 1;
- Hashtable是Dictionary的子类同时也实现了Map接口,HashMap是Map接口的一个实现类;
和concurrentHashMap区别
https://www.jianshu.com/p/7af5bb1b57e2
https://blog.csdn.net/zxt0601/article/details/77413921