zoukankan      html  css  js  c++  java
  • 关于HashMap的一个有趣的小问题

    最近面试被问到了一个很有意思的问题,是关于HashMap的。之前没看到过类似的问题,感觉很有趣,所以想记录一下。问题很简单,基于一个很简单的常识,即重写equals方法必须同时重写hashCode方法。问题的内容是,假如只重写了equals方法,或者只重写了hashCode方法,分别会出现什么情况?

    个人理解HashMap的核心其实就两点,即如何根据key定位bucket,以及如何判断两个key相等。这个问题主要和第二个问题相关,但是涉及的源码很简单,就下面这一句,p是根据hash值定位到的第一个node,put和get是一样的判断逻辑。

    p.hash==hash&&(p.key==key||(key!=null&&key.equals(p.key)))
    

    接下来考虑这两个场景,在这两个场景下分析可能出现的一些case。①put之后用等价的key再次put,②put之后用等价的key尝试get。

    首先看只重写equals方法的情况。场景①会发生什么情况?场景②会发生什么情况?

    等价的key,equals方法必然返回true,但是由于未重写hashCode方法,所以返回的hash值有两种情况,可能相同也可能不同。假如相同,则两个key会冲突到同一个bucket。假如不相同,又有两种情况,可能冲突到同一个bucket,也可能是不同的bucket。所以这里有3种case:
    case a:hash值相同
    case b:hash值不同但冲突到同一个bucket
    case c:hash值不同且bucket不同

    场景①(put之后用等价的key再次put)
    case a的结果是第二次put的值会替换掉第一次put的值;
    case b由于hash值比对不通过,所以会被认为是不同的key,导致在同一bucket中重复插入;
    case c都不在一个bucket,肯定也会重复插入。
    所以结论是case a勉强能用,b、c都有问题。

    场景②(put之后用等价的key尝试get)
    case a的结果是get方法可以获取到put插入的数据;
    case b由于hash值比对不通过,所以无法正确匹配key,结果就是返回null;
    case c定位的bucket都错了,肯定返回null。
    所以结论是case a勉强能用,b、c都有问题。

    简单总结一下,若只重写equals方法,未重写hashCode方法,只有在两个key的hashCode恰好相等的情况下,才能表现出正常的行为,其他所有的情况都无法正常工作。我们知道两个对象的hashCode重复的概率是极低的,所以能正常工作的可能性也极低。

    再看只重写hashCode方法的情况。场景①会发生什么情况?场景②会发生什么情况?

    等价的key,equals方法默认比较的是地址,所以必然返回false。但是hashCode方法有重写,所以等价的key会定位到同一个bucket。此时我们再来看以上两种场景会发生什么事情。

    场景①(put之后用等价的key再次put)
    等价的key冲突到同一个bucket,此时先比较hash值,虽然相等,但是后续的地址比较的equals比较必然为false,所以会重复插入数据,显然是不可用的。

    场景②(put之后用等价的key尝试get)
    等价的key会定位到同一个bucket,和上面类似,两个key永远无法被判定为相等,所以get必然返回null,所以也是不可用的。

    简单总结一下,只重写hashCode方法时,所有case下HashMap都是无法正常工作的。

    所以,不管是只重写equals方法,还是只重写hashCode方法,都是无法确保HashMap正常工作的,以上就是可能出现的一些case。我个人的建议是,如果没有必要,使用JDK本身提供的不变类作为key是最好的。非要用自定义类作为key,必须同时正确实现equals方法和hashCode方法。

  • 相关阅读:
    POJ 2976 Dropping tests
    【学习笔记-中国剩余定理】POJ1006 Biorhythms
    2017.10.6北京清北综合强化班DAY6
    P1607 [USACO09FEB]庙会班车Fair Shuttle
    2017.10.5北京清北综合强化班DAY5
    洛谷 P1379 八数码难题
    A. 拼音魔法
    A
    K
    A
  • 原文地址:https://www.cnblogs.com/shen-smile/p/13975396.html
Copyright © 2011-2022 走看看