Map的key是否可重复

我们都知道Map的一大特性是key唯一不可重复,可是真的是这样的吗?

我们来试验一下:

 

 

 运行结果:

  

 

 我们可以看到在map里有两个同样的person作为key,打破了map的key不可重复的特性。

我们平时操作map一般不会出现这样的结果,怎样操作会出现上述的现象呢?

1、首先有前提条件,作为key的person必须重写hashCode与equals这两个方法保证我们在改变person的属性之后,该person的hash值发生变化。

2、其次是我们在map中put一个以person对象作为key的元素,然后我们修改该person对象的某一个属性,再次把该person对象作为key值put到map中,就得到了上述结果。

为什么会出现上述的问题呢?

  我们要明白map的数据结构以及数据是如何存储到map中的

  JDK1.7 HashMap是数组+链表的结构

  JDK8之后HashMap是数组+链表+红黑树的结构

    tips:当然这里我们就不过多的讨论7与8结构的区别

  我们在put一个元素的时候,(其余逻辑省略,这里只关注元素如何定位到数组的桶位置),先拿到key对象的hash值h1,h1无符号右移16位得到h2,

  再把h1与h2进行异或运算得到h3,h3与数组的(length-1)进行与运算得到元素在数组上的最终位置

    

    tips:如果数组长度较小的时候(大多数情况下map的长度不大),key产生的hash值如果高位变化较大很大,而地位变化很小时,

    如果直接拿key的hash值与上(length-1)很容易产生hash冲突,所以无符号右移16位在异或低16位使得高混乱区域与低混乱区域做一个中和,提高hash高低位的一个随机性,减少hash冲突

上面我们讲述了map是如何把元素放入到数组中的,我们再回到上面的问题,第一次把person作为key放入map之后,修改了person的name属性之后,person的hash值发生变化,从而计算出的

桶位置也随之而改变(大概率会改变,不是绝对的)再次put到map中就得到两个相同key值的map。

 

那么在生产应用中我们要避免使用类似于person这样的对象作为key值存储在Map中,可以使用Integer、String这样一些不可变的对象来作为key就可以避免上述情况的发生。

  插一句题外话,HashSet是无序不可重复的,它其实也存在上面的情况,原因很简单HashSet的底层就是HashMap

    附HashSet相关代码截图

  

 

 

 

  

 

posted @ 2022-03-23 22:29  搬砖党路过  阅读(3745)  评论(0编辑  收藏  举报