对于HashSet而言,它是基于HashMap实现的,HashSet底层采用HashMap来保存所有元素,因此HashSet的实现比较简单,查看HashSet的源代码,可以看到如下代码:
由上面源程序可以看出,HashSet的实现其实非常简单,它只是封装了一个HashMap对象来存储所有的集合元素,所有放入HashSet中的集合元素实际上由HashMap的key来保存,而HashMap的value则存储了一个PRESENT,它是一个静态的Object对象。
HashSet的绝大部分方法都是通过调用HashMap的方法来实现的,因此HashSet和HashMap两个集合在实现本质上是相同的。
掌握上面理论知识之后,接下来看一个示例程序,测试一下自己是否真正掌握了HashMap和HashSet集合的功能。
上面程序中向HashSet里添加了一个new Name("abc","123")对象之后,立即通过程序判断该HashSet是否包含一个new Name("abc","123")对象。粗看上去,很容易以为该程序会输出true。
实际运行上面程序将看到程序输出false,这是因为HashSet判断两个对象相等的标准除了要求通过equals()方法比较返回true之外,还要求两个对象的hashCode()返回值相等。而上面程序没有重写Name类的hashCode()方法,两个Name对象的hashCode()返回值并不相同,因此HashSet会把它们当成2个对象处理,因此程序返回false。
由此可见,当我们试图把某个类的对象当成HashMap的key,或试图将这个类的对象放入HashSet中保存时,重写该类的equals(Object obj)方法和hashCode()方法很重要,而且这两个方法的返回值必须保持一致:当该类的两个的hashCode()返回值相同时,它们通过equals()方法比较也java基础分享应该返回true。通常来说,所有参与计算hashCode()返回值的关键属性,都应该用于作为equals()比较的标准。
如下程序就正确重写了Name类的hashCode()和equals()方法,程序如下:
上面程序中提供了一个Name类,该Name类重写了equals()和toString()两个方法,这两个方法都是根据Name类的first实例变量来判断的,当两个Name对象的first实例变量相等时,这两个Name对象的hashCode()返回值也相同,通过equals()比较也会返回true。
程序主方法先将第一个Name对象添加到HashSet中,该Name对象的first实例变量值为"abc",接着程序再次试图将一个first为"abc"的Name对象添加到HashSet中,很明显,此时没法将新的Name对象添加到该HashSet中,因为此处试图添加的Name对象的first也是"abc",HashSet会判断此处新增的Name对象与原有的Name对象相同,因此无法添加进入,程序在①号代码处输出set集合时将看到该集合里只包含一个Name对象,就是第一个、last为"123"的Name对象。
版权声明:
本文来源网络,所有图片文章版权属于原作者,如有侵权,联系删除。
本文网址:https://www.bianchenghao6.com/h6javajc/1556.html