电光石火-穿越时空电光石火-穿越时空


HashSet集合中hashCode及equals方法详解

首先我们熟知HashSet集合中元素存储的特点:

1)不允许元素重复

2)不会记录元素添加的先后顺序

3)HashSet中比较两个对象是否相同,要使用equals()方法,不能使用 ==;

 4)底层依然使用哈希表(散列)算法,其本质就是数组形式,采用此算法就为提高查询的效率;

5)插入速度也比较快,但适合于少量元素插入操作;一旦所存储元素个数满足(size * loadFoctor > size),哈希表就要扩容,此时操作速度极慢,性能就会降低!


由于HashSet集合中的元素不能重复存储,那应该怎样做呢?

1)先判断两个对象的hashCode()方法返回值是否相同,即存储的位置;

2)然后再判断两个对象的equals()方法返回值是否为true,即存储实际的对象值。


接下来我们就来讲解一下采用哈希表(散列)算法实现元素不可重复存储,具体的思想:

第一:

1)Set集合中元素没有顺序,不能重复;

2)元素重复是指:存储对象的重复;

3)何为对象的重复:内存中,所在内存编号一致(相同);

4)内存编号表示:哈希码值(哈希码值一般是  类名  和  对象所在内存地址的十六进制数字表示的集合)


第二:(现实共同观念)

现实生活中只要属性相同,我们就认为这两个对象就是同一个对象,但这与计算机比较同一个对象的方法不同(计算机使用内存地址,即哈希码值);Object类中的hashCode()方法是不可能返回两个相同的哈希码值(一个哈希码值唯一的标志了一个对象),即地址的唯一性。但是这样就不能让程序的运行符合现实生活(现实逻辑:属性相同的对象被看作是同一个对象)

于是就需要重写equals()和hashCode()方法,并且基本数据类型都重写了这两个方法!


第三:

重写这两个方法有什么用呢?

主要目的:属性相同的两个对象,返回的哈希码值是相同的!

程序向HashSet集合中添加一个元素时,先调用对象的hashCode()方法计算出该对象的哈希码值;

比较:

(1)如果该对象与集合中所存储的全部对象的哈希码值不一致,则该对象就不重复,计算出该对象在哈希表中的索引位置,直接添加;

(2)如果该对象与集合中存储的某一对象哈希码值一致(重码现象),那就需要通过equals()方法判断相同哈希码值的对象是否为同一对象(判断标准:属性是否相同);

a)相同对象,新值覆盖旧值;

b)不相同,在该索引位置,以头插的形式插入链表中。


第四:有两个疑问

(1)为什么哈希码值相同了,还有可能是不同的对象?

虽然重写hashCode()方法的主要目的:属性相同的两个对象,返回的哈希码值是相同的!

但是在重写hashCode()方法时,几乎所有的写法都无法避免一个bug:有一些对象(当然是不同的对象),会返回相同的哈希码(即重码),此时就需要借助equals()方法;

在哈希码相同的情况下,再使用equals()方法判断两个对象的属相是否一样,就可以做到万无一失了

(2)为什么经过比较哈希码值,还需要借助equals()方法判断呢?

HashSet集合底层采用了哈希算法实现,多个不同的对象可能返回的哈希码值不同,但是通过计算得到的哈希表中的索引位置相同,这样就再次需要通过equals()方法来判断这两个对象的属性值是否相同,比较完再做相应的处理!


总思路:哈希码不同时,则必为不同的对象,重写hashCode()方法时,哈希码相同(可能出现重码现象),则根据euqals()方法判断是否新值覆盖旧值;两者都是以链表头插方式!在HashSet、HashMap、HashTable中都存在这一问题!

本博客所有文章如无特别注明均为原创。作者:似水的流年
版权所有:《电光石火-穿越时空》 => HashSet集合中hashCode及equals方法详解
本文地址:http://ilkhome.cn/index.php/archives/236/
欢迎转载!复制或转载请以超链接形式注明,文章为 似水的流年 原创,并注明原文地址 HashSet集合中hashCode及equals方法详解,谢谢。

评论