ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Java探究HashSet中如何完成同一个对象不重复出现

2021-10-29 18:33:29  阅读:188  来源: 互联网

标签:set Java HashSet equals hashcode 探究 test 重写 public


Java探究HashSet中如何完成同一个对象不重复出现(自定义对象作为HashSet的元素时候应该注意重写的hashcode与equals讨论)

2021.10.29 写于山威

1.继承体系

没有学过UML,自己瞎画的

2.问题讨论

我们都知道,在java的set中是不能出现重复的元素的,但是是如何保证这一问题的实现的呢?我们先买个关子,我们先想想,平时我们如何判断元素是否相等:

  • 对于基本数据类型:直接使用等于号
  • 对于引用对象:使用equals判断,当然也不排除string类这种重写hashcode等,使用hashcode来判断对象是否相等

所以我们一般都会理所应当的想到,在set中要满足插入元素没有重复的时候,一般是使用集合元素的equals方法来判断的,那么我们下面来写一段代码检测一下

//只是重写equals方法
	public static class A
	{

		@Override
		public boolean equals(Object obj) {
			return true;
		}
		
	}
	//只是重写hashcode方法
	public static class B
	{

		

		@Override
		public int hashCode() {
			return 1;
		}
		
		
	}
	//将equals方法和hashcode方法都重写
	public static class C
	{
		public boolean equals(Object obj) {
			return true;
		}

		@Override
		public int hashCode() {
			return 2;
		}
	}
	public static void main( String [] __)
	{
		//我们写了三个私有类,接下来我们测试一下
		HashSet<Object> test=new HashSet<Object>();
		test.add(new A());
		test.add(new A());
		test.add(new B());
		test.add(new B());
		test.add(new C());
		test.add(new C());
		//我们重复的加进去了六个元素,那么按照我们重写之后的方法(无论是什么都返回true与相同的hashcode)
		//这个set里面目前还有谁在保留呢?
		System.out.println(test);
	}

在这种情况下,大家猜测会输出什么呢?

[mytestDemo.Hello$B@1, mytestDemo.Hello$B@1, mytestDemo.Hello$C@2, mytestDemo.Hello$A@7de26db8, mytestDemo.Hello$A@1175e2db]
这是我的输出,可以很明显的看到,输出里面有两个A,两个B,但是只有一个C,原因其实很简单,因为重写方法的时候,我们只有对于C既重写hashcode,又重写了equals

3.源码解释

因此我们可以得到,set判断元素是否重复的时候,既使用了hashcode,又使用equals方法,具体是怎么使用,让我们进入源码看看(稍稍看看,深入看不能我能窥探的)

我们可以看到,在hashset中是有一个hashmap来保证插入的元素是不会重复的(这一点我也没有想到)

具体这里的put方法中有一个参数是hash(value),我们可以看到在这个函数里面其实就是调用了对象的hashcode函数,用得到的这个函数去检索set集合中相应位置是否有元素(set说是无序,其实内部是使用hashcode作为序的),因此会有下面的几种情况

  • 重写的hashcode计算得到的数据对应位置没有其他元素,插入进去(最好的情况)
  • 没有重写hashcode方法,使用object的hashcode方法返回地址值作为索引,因为地址值唯一,所以一定可以插入(类似于刚刚类A)
  • 重写了hashcode方法,但是没有重写equals方法,类似于刚刚类B,这里类B的情况就是对应位置有元素了,使用equals来判断是否相等,因为类B没有写equals方法,使用object的equals方法来判断,得到两个元素是不等的,所以在set中hashcode得到的索引位置建立了单链表,串联起来-->会造成set非常臃肿
  • 重写了hashcode和equals方法(规范重写:既如果hashcode相等,则equals一定相等),如同刚刚的类C,所以最终输出只有一个C

下面我来画图让大家看的更加直观,对于刚刚的插入:

大概的讲解就是这么多了,我知识水平有限....

标签:set,Java,HashSet,equals,hashcode,探究,test,重写,public
来源: https://www.cnblogs.com/oldoldcoder/p/15481781.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有