为什么要在重写了equals方法时还要重写hashcode方法

       上篇博客中遗留了““重写了Objectequals方法,当所引用的对象是同一类对象且属性内容相等时,它们却不一定是相同的对象,这是为什么?我们又该如何解决”或则个问题?

问题一:我们先来看为什么会出现这样的问题?

       首先,出现这个问题的根源在于哈希表的集合类型上

       也就是说在我们的程序中如使用了hashmap时,要比较两个对象是否相等,hashmap是通过key的hashcoe来查找,所以即使我们重写了equals方法,但是如果没有重写hashcode方法,得到的两个对象仍然不相等。那么,对于一些其他的类,即使我们不重写hashcode方法,编译器也不会报错,也不会影响到我们的使用。

       在jdk中“注意:当此方法被重写时,通常有必要重写hashCode方法,以维护hashCode方法的常规协定,该协定声明相等对象必须具有相等的哈希码。”这样描述,所以我觉得还是在重写equals时,重写hashcode为好。

问题二:什么是hashCode方法?

hashCode的方法: publicnative int hashCode();

作用:

支持此方法是为了提高哈希表(例如java.util.Hashtable 提供的哈希表)的性能。

解析:

       如果原来集合中已经有10000个元素了,那么放入10001个元素,难道要将前面的所有元素都进行比较,看看是否有重复,这个效率可想而知。

       然而,有了hashcode,java就采用了hash表,利用哈希算法(也叫散列算法),就是将对象数据根据该对象的特征使用特定的算法将其定义到一个地址上,那么在后面定义进来的数据只要看对应的hashcode地址上是否有值,那么就用equals比较,如果没有则直接插入,这样就大大减少了equals的使用次数,执行效率就大大提高了。

问题三:以实例解析为什么重写equals时需要重写hashcode?

1、  创建一个key类,作为hashMap的key
 class key
 {
	 int i;
	 public key(int i){
	    this.i = i;
	 }
}
2、  创建一个value类,作为hashMap的value
 class value
 {
	 int j;
	 public value(int j){
	    this.j =j;
	 }

	 public String toString(){
	    return " " + j; 
	 }
 }
3、  测试类:
 public class test
 {
	 public static void main(String args[]){
	     HashMap hm = new HashMap();

		 key k = new key(1);  //第一处
		 value v = new value(2);

		 hm.put(k,v);
         if (hm.containsKey(k))//第二处
         {
			 System.out.println(hm.get(k));//第三处
         }else{
		     System.out.println("没有这样一个键值");
		 }
	 }
}

        在测试类test中,hashmap中的key是用上面的key类new出来的一个对象,然后把这个对象作为hashmap的key,这里突出了hashmap的查找原理,hashmap是通过key类的hashcode方法来找到hashmap中的key(可以参考Hashmap中hashCode源码理解)。在测试类中,hashmap中放的是一个key类的对象引用,去get或者containsKey也是是这个对象引用,所以第一处、第二处、第三处的key是完全相同的,都是指向同一个对象,所以结果如下:


HashMap中的hashCode方法:

 public int hashCode() {

        int h = 0;

        Iterator<Entry<K,V>> i =entrySet().iterator();

        while (i.hasNext())

            h += i.next().hashCode();

        return h;

} 
4、  现在修改测试类
 public class test
 {
	 public static void main(String args[]){
	   
         HashMap hm = new HashMap();
		 hm.put(new key(1),new value(2));
		 if (hm.containsKey(new key(1)))
		 {
			 System.out.println(hm.get(new key(1)));
		 }else{
		     System.out.println("没有这样一个键值");
		 }
	 }
 }

        在这里hashmap中的key放的不是应用,而是new出来的对象,然后get或者containsKey的时候也通过new一个key类的对象,虽然我们初始化的内容完全相同,都是放int 1进去,也就是说对象内容完全相同,但是他们却不是指向同一个对象,所以最后输出的结果是:


5、  重写key类的equals方法
 class key
 {
	 int i;
	 public key(int i){
	    this.i = i;
	 }

	 public boolean equals(Object obj){
	    if (obj instanceof key)
	    {
		if (((key)obj).i == i)
		{
		return true;
		}
	    }
		return false;
	 }	
 }

      既然重写了equals方法,那么比较的就是两个对象的内容,而不是地址,那么我们看一下运行结果:

 

      显然,针对哈希表的这种集合光重写equals方法还是不行的,并不能说我们规定内容相同对象就可以相同,我们还必须重写hashcode方法。

6、  重写key类的hashCode方法
 class key
 {
	 int i;
	 public key(int i){
	    this.i = i;
	 }

	 public boolean equals(Object obj){
	    if (obj instanceof key)
	    {
		if (((key)obj).i == i)
		{
		     return true;
		}
	    }
		return false;
	 }

         public int hashCode(){
	   return i;
        }
 }

       这里我们重写了hashcode这个方法,让它返回一个我们初始化进去的i,这样你每次new一个对象,因为是通过hashcode找key,而你的hashcode有只是值i,所以只要i相等,你就可以找到你的key的地址,然后再用equals方法比较两个对象是不是相同,即开始比较我们传来的寻找valuekeyhashmap中的key是不是同一个key,如果是那就找到了value

运行结果:

 

达到了我们想要的运行效果。

小结:

        为什么必须要重写hashcode方法,其实简单的说就是为了保证同一个对象,保证在equals相同的情况下hashcode值必定相同,如果重写了equals而未重写hashcode方法,可能就会出现两个没有关系的对象equals相同的(因为equal都是根据对象的特征进行重写的),但hashcode确实不相同的。

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REaDME.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值