一.
哈希表中判断元素是否相同的方式到底是什么?我们要探索一下。
刚才我们存储ab的时候,表中已经有ab了。再往里面存储ab的时候,首先要放入算法中计算地址。一算完,这个地址是5,然后到表中去寻找,发现5的位置上已经有元素了。接下来就不往里面存了么?不一定,我们只能说这个位置上已经有元素了,不能保证这个元素是ab。我有两个元素算出来的地址都是5,不能因此就判断这个元素就是相同的。
举例来看,ab和ba,这两个字符串是不一样的,通过哈希算法得到的结果是一致的。它们的位置一样,但是内容是不相同的。
在哈希表中,必须不能有重复的,那涉及一个问题,哈希表是如何确定元素是重复的呢?光凭哈希算法的结果不完全准。先看值,后判断。
不是说哈希值得出的结果相同,就是同一元素,毕竟是转借了一个过程,通过这个过程得到的相同,和直接判定相同是两回事。
如果哈希值都不相同,那就不存在第二步的判断内容了。
现在讲一下哈希表中特殊的东西,当哈希值相同时,内容不相同,那么就需要存储,这就是哈希冲突(哈希值一样)。两个对象一样,但是哈希值不一样。
这种情况不多,因为一般哈希算法比较复杂。
这种情况是有的,解决的措施不唯一,比如说顺延。万一顺延到后面没位置怎么办呢?将数组长度延长,或者串联。
串联比较有趣,位置是5,挂一个出来,如下图所示。这种串联它会继续算它的位置,是基于5来算的。
体系中有很多方式来存储这样的元素,而这些元素本身也有自己的规则和位置。(不可能说,两个哈希值一样,内容不一样,就直接覆盖掉,没有那么理想化)
不用担心,直接用算法来实现就可以了。
我们担心是这件事情,如果我想在这个数组中去查询到底有没有ba,首先到算法中去计算,得到一个位置。算到这个位置后,就到这个位置上去寻找这个元素。
和它一样吗?先比较ab,发现不一样,但是这个位置上不止一个元素,再往下找ba,发现有,这时候就不存了。这是它内部产生的规律,并 不冲突。
(其实我比较好奇,哈希冲突,尤其是这样挂着的形式,在内存中是怎样的体现形式?)
搞定完以后,现在回头来说一下,如果我们想要搞定哈希表,往里面存这样的对象,我们要注意hashcode和equals方法,观看原先的例子。
往哈希表中存储的是字符串,在存储的时候,就采用了hashcode方法。
我们来看一下字符串的hashcode方法是什么样的。找到String类,它本身就覆盖了object类中的hashcode方法,这个方法定义了字符串中的哈希码,或者说哈希算法,同时也覆盖了object中的equals方法,定义了自己的判断内容是否相同的依据。
接下来我们看一下,它到底是怎么完成的。打开String的源码,左侧的outline是大纲视窗,这里面列出了当前类里面的所有成员,这样寻找起来比较方便。
找到hashcode,下图显示的就是字符串哈希算法。它怎么算的,不用管,它是根据字符串自身的特点来计算的。
这里的value,其实是字符串对应的数组。
再看它的equals,它也是在判断其中的每一位。体系本身已经做了hashcode和equals的定义。
到目前为止讲述了这么多,要说一件重要的事儿,往里面存储一些自定义对象。