Java面试必知:hashCode equals 和 hashMap

hashCode和 equals 方法的区别

  • 在Object类中, equals 用 == 比较 hashCode 存储地址的一部分
  • 严格说hashCode 和equals 没有必然的联系(因为可以随便重写), 但是重写时要遵循一定的规范
  • 规范:
    • hashCode相等的情况下,对象的值不一定相等,equals不一定相等
    • equals相等的情况下,hashCode一定相等
    • 如果重写了 equals方法 一定要重写 hashCode,保证原则不变

hashMap和hashTable的区别

  • hashMap线程不安全,所以效率高. hashTable线程安全,但是效率低
  • hashMap允许存放key等于null,存放在数组第0个位置
  • hashTable不允许key或者value等于null,直接报错

如何理解HashCode碰撞问题

当对象值不等,但hashCode相等,此时在存储时出现了 hashCode碰撞的问题

hashMap的put方法实现

hashMap1.7采用数组+链表实现. 采用HashEntry封装我们的键值对
根据我们的key计算HashCode得到index(存放的下标位置),如果产生hash碰撞,在下标相同的地方采用链表存放
注意:hashMap1.7采用数组+链表,采用头插法.在多线程扩充我们的数组可能产生死锁问题
HashMap根据key查询键值对在没有产生hash冲突的情况下时间复杂度为O1
在产生冲突的情况下,时间复杂度为On,所以在1.8中 当链表的长度大于8的情况下并且数组的长度为64的情况下转换为红黑树存放.

hashMap1.7是如何求index的(为什么hashMap的默认长度是2的幂)

计算存放下标index时,是通过 key的hashCode 与 长度减1进行&运算.
默认长度是2的幂 减去1后, 二进制各位数字均为1. &运算后为key hashCode的后几位 ,这样可以保证 桶尽量均匀存储
若&运算的一边 不是各位均是1 ,则 0那位和任何数字&运算 还是0 ,则 index 必有空桶.

hashMap1.7扩容如何实现

hashMap中的数组默认容量为16 加载因子为0.75 扩充倍数为2倍
为什么加载因子为0.75?
实验得到 最佳加载因子为0.75
当加载因子太小,key的冲突概率比较小,但是十分浪费内存空间
当加载因子太大时,key的冲突概率非常大,但是利用空间非常好
空间和冲突的概率的平衡值为0.75
扩容为2倍后, hash的计算有所改变(多了一位) 则需要重新计算下标位置.重新存桶.

为什么hashMap1.7会造成死锁问题

因为hashMap是线程不安全的,假如在hashMap进行扩容时, 进行hash重组.此时 如果有多个线程进行操作.很有可能到时 俩个 hashEntry 进行了 头尾相连. 此时当再次查询到此处时, 将会发生死锁现象.

可以通过精心构造的恶意请求来进行攻击,拖慢服务器性能

黑客可以进行多个造成hash碰撞的key 存入 从而影响性能
oracle 提供的解决方案:
提供随机hash种子, 当随机hash种子存在并且 key 属于string类时,使用另一套 方案计算 hash ,进行存储
在1.8中 采用了红黑树(平衡二叉树) 来解决此问题

hashMap1.8 对 hashMap 1.7进行的改进

  1. 采用尾插法,减少死锁问题
  2. hash求值,让hashcode高16位和低16位进行异或操作,让高16位参与运算,减少hash冲突
  3. 当链表的长度大于8的情况下并且数组的长度为64的情况下转换为红黑树存放,减少hash碰撞
hash计算与存储(而不是直接使用hashCode)
// 代码1
static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

// 代码2
int n = tab.length;
// 将(tab.length - 1) 与 hash值进行&运算
int index = (n - 1) & hash;
为什么不直接用 hashCode() 而是用它的高 16 位进行异或计算新 hash 值?

hashmap中数组的默认容量是16,hashcode32,如果直接使用hashcode寻址相当于只使用了低16位,高16位不参与运算。这样就会发生hash冲突大的问题,为了减少hash冲突,让高16位与低16位进行异或操作

put方法的改进

在1.8中 当链表的长度大于8的情况下并且数组的长度为64的情况下转换为红黑树存放.

红黑树为什么可以减少hash碰撞 提高效率.

链表时间复杂度On 红黑树 Olog2n.

红黑树实现原理

以后再看

hashmap和concurrenthashmap的区别

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值