你真的了解HashSet吗?

151 阅读3分钟

参考:https://mp.weixin.qq.com/s/TE225z9vKrq_DmLE_QciKA



只见一尘号召了所有的弟子,把他们的名字都添加到他自己构造出的一个List集合里面去了。




这里一尘选择了 ArrayList


然后用 contains() 方法判断输入的那个名字在没在 List 集合里。




结果:




HashSet 它实现了 Set 接口,而Set集合的特性就是没有重复元素,所以他可以自动的去掉重复元素。并且它的底层是使用 散列表来实现的,所以它的一些常用操作。


不理解散列表的可以看:

神速Hash(上)

神速Hash(下)

什么是HashMap?


比如:添加元素add(),移除元素remove(),是否包含某个元素contains()的时间复杂度都为O(1)

到时候每查一个人,你只需要判断它在没在集合里,你可以用 contains() 来判断。

和List在使用上没有多大区别,把List换成Set就行。



HashSet会自动帮你去重。







可以看到,它的构造函数其实是new了一个HashMap。

这个map是HashSet的一个成员变量


HashMap底层使用了散列表,所以速度很快



可以看到,在用HashSet的add()方法的时候,其实就是将你要add的元素 e 作为 HashMap的 Key,把 PRESENT 作为Value进行存储的。

PRESENT 是一个固定不变的 Object



元素被 add 进 HashSet 中的样子是这样的:



HashSet容量为 8


当 HashSet 被add()进两个相同的元素的时候,此时 HashMap 中之前存在的Key不会发生改变


只是 Value 被替换了,然后就return了。这样也就达到了去重的目的(第二个重复的Key没有被添加进来)


此段代码在HashMap的 put() 方法之中






然后再主程序中加入到Set中就行了。





看一下下面的代码:



两个名字和性别都一样的学生,按理来说应该是同一个人了(逻辑上一样),但是它的 set 集合输出却有两个一尘,都是男的,没有去重







可以看到 会调用 k 的hashCode. k就是你add进去的 Key,对 Key不重写hashCode就会默认调用父类Object的hashCode方法。



而 Object 的 hashCode 是 native 的,这个 hashCode 根据虚拟机的策略可能会返回和对象地址相关联的值。

你上面new的两个Student虽然逻辑上一样,但是两个对象的地址不一样,所以它们的hashCode可能会根据地址来计算,就会产生不同的hashCode,从而落在了不同的位置(桶)中了。

因为key在被put进map中的时候,它到底落在哪个位置(桶)是由它的hashCode决定的。




HashMap中的put方法

这里可以看到,就算你的两个对象的hashCode一样(e.hash==hash),落在了同一个位置(桶),但是如果你不重写equals方法,那么在判断HashMap集合里是否存在相同的元素的时候,就会根据Object的equals方法来判断。



可以看到Object的equals是比较的对象的地址,而你new了两个对象,他们的地址不一样,所以这里就不 return,而是把你的逻辑相同的Student加入到 HashMap之中

这样还是有重复元素。



只见慧能随手一写: