1分飞艇彩神争8_为什么要重写hashcode和equals方法?初级程序员在面试中很少能说清楚。

  • 时间:
  • 浏览:0
  • 来源:爱Q生活网_提供熊猫辅助网技术_洋葱娱乐网资讯

     我在面试 Java初级开发的不想,突然会问:你有没办法 重写过hashcode依据?不少候选人直接说没写过。你都都要想,或许真的没写过,于是就再通过有有两个问题报告 确认:你在用HashMap的不想,键(Key)帕累托图,有没办法 放过自定义对象?而你什儿 不想,候选人说放过,于是有有两个问题报告 的回答就自相矛盾了。

    最近问下来,你什儿 问题报告 普遍回答不大好,于是在本文里,就干脆从hash表讲起,讲述HashMap的存数据规则,由此我们歌词 我们歌词 就自然清楚上述问题报告 的答案了。

1 通过Hash算法来了解HashMap对象的高效性

    我们歌词 我们歌词 先复习数据型态里的有有两个知识点:在有有两个长度为n(假设是100000)的线性表(假设是ArrayList)里,存放着无序的数字;导致 我们歌词 我们歌词 要找有有两个指定的数字,就不得不通过从头到尾依次遍历来查找,不想的平均查找次数是n除以2(这里是100000)。

我们歌词 我们歌词 再来观察Hash表(这里的Hash表纯粹是数据型态上的概念,和Java无关)。它的平均查找次数接近于1,代价相当小,关键是在Hash表里,存放到去去其中的数据和它的存储位置是用Hash函数关联的。

    我们歌词 我们歌词 假设有有两个Hash函数是x*x%5。当然实际情況里不导致 用没办法 简单的Hash函数,我们歌词 我们歌词 这里纯粹为了说明方便,而Hash表是有有两个长度是11的线性表。导致 我们歌词 我们歌词 要把6放到去去其中,没办法 我们歌词 我们歌词 首先会对6用Hash函数计算一下,结果是1,什么都有有我们歌词 我们歌词 就把6放到去去到索引号是1你什儿 位置。同样导致 我们歌词 我们歌词 要放数字7,经过Hash函数计算,7的结果是4,没办法 它将被放到去去索引是4的你什儿 位置。你什儿 效果如下图所示。

    不想做的好处非常明显。比如我们歌词 我们歌词 要从中找6你什儿 元素,我们歌词 我们歌词 都都要先通过Hash函数计算6的索引位置,不想 直接从1号索引里找到它了。

不过我们歌词 我们歌词 会遇到“Hash值冲突”你什儿 问题报告 。比如经过Hash函数计算后,7和8会有相同的Hash值,对此Java的HashMap对象采用的是”链地址法“的避免方案。效果如下图所示。

 

    具体的做法是,为所有Hash值是i的对象建立有有两个同义词链表。假设我们歌词 我们歌词 在放到去去8的不想,发现4号位置导致 被占,没办法 就会新建有有两个链表结点放到去去8。同样,导致 我们歌词 我们歌词 要找8,没办法 发现4号索引里时会8,那会沿着链表依次查找。

    我着实我们歌词 我们歌词 还是无法彻底避免Hash值冲突的问题报告 ,不想 Hash函数设计合理,仍能保证同义词链表的长度被控制在有有两个合理的范围里。这里讲的理论知识之什么都有与非 的放矢,我们歌词 我们歌词 能在后文里清晰地了解到重写hashCode依据的重要性。

2 为甚要重写equals和hashCode依据

    我们歌词 歌词 我们歌词 用HashMap存入自定义的类时,导致 不重写你什儿 自定义类的equals和hashCode依据,得到的结果会和我们歌词 我们歌词 预期的不一样。我们歌词 我们歌词 来看WithoutHashCode.java你什儿 例子。

在其中的第2到第18行,我们歌词 我们歌词 定义了有有两个Key类;在其中的第3行定义了唯一的有有两个属性id。当前我们歌词 我们歌词 先注释掉第9行的equals依据和第16行的hashCode依据。    

1	import java.util.HashMap;
2	class Key {
3		private Integer id;
4		public Integer getId() 
5	{return id; }
6		public Key(Integer id) 
7	{this.id = id;	}
8	//故意先注释掉equals和hashCode依据
9	//	public boolean equals(Object o) {
10	//		if (o == null || !(o instanceof Key)) 
11	//		{ return false;	} 
12	//		else 
13	//		{ return this.getId().equals(((Key) o).getId());}
14	//	}
15		
16	//	public int hashCode() 
17	//	{ return id.hashCode();	}
18	}
19	
20	public class WithoutHashCode {
21		public static void main(String[] args) {
22			Key k1 = new Key(1);
23			Key k2 = new Key(1);
24			HashMap<Key,String> hm = new HashMap<Key,String>(); 
25			hm.put(k1, "Key with id is 1");		
26			System.out.println(hm.get(k2));		
27		}
28	}

    在main函数里的第22和23行,我们歌词 我们歌词 定义了有有两个Key对象,它们的id时会1,就好比它们是两把相同的都能打开同一扇门的钥匙。

    在第24行里,我们歌词 我们歌词 通过泛型创建了有有两个HashMap对象。它的键帕累托图都都要存放Key类型的对象,值帕累托图都都要存储String类型的对象。

    在第25行里,我们歌词 我们歌词 通过put依据把k1和一串字符放到去去到hm里; 而在第26行,我们歌词 我们歌词 想用k2去从HashMap里得到值;这就好比我们歌词 我们歌词 想用k1这把钥匙来锁门,用k2来开门。这是符合逻辑的,但从当前结果看,26行的返回结果时会我们歌词 我们歌词 想象中的那个字符串,什么都有有我null。

    导致 有有两个多—没办法 重写。第一是没办法 重写hashCode依据,第二是没办法 重写equals依据。

   我们歌词 歌词 我们歌词 往HashMap里放k1时,首先会调用Key你什儿 类的hashCode依据计算它的hash值,不想把k1放到去去hash值所指引的内存位置。

    关键是我们歌词 我们歌词 没办法 在Key里定义hashCode依据。这里调用的仍是Object类的hashCode依据(所有的类时会Object的子类),而Object类的hashCode依据返回的hash值我我着实是k1对象的内存地址(假设是10000)。

    

    导致 我们歌词 我们歌词 不想是调用hm.get(k1),没办法 我们歌词 我们歌词 会再次调用hashCode依据(还是返回k1的地址10000),不想根据得到的hash值,能加快速度地找到k1。

    但我们歌词 我们歌词 这里的代码是hm.get(k2),我们歌词 歌词 我们歌词 调用Object类的hashCode依据(导致 Key里没定义)计算k2的hash值时,我我着实得到的是k2的内存地址(假设是10000)。导致 k1和k2是有有两个不同的对象,什么都有有它们的内存地址一定不想相同,也什么都有有我说它们的hash值一定不同,这什么都有有我我们歌词 我们歌词 无法用k2的hash值去拿k1的导致 。

    我们歌词 歌词 我们歌词 把第16和17行的hashCode依据的注释上加后,会发现它是返回id属性的hashCode值,这里k1和k2的id时会1,什么都有有它们的hash值是相等的。

    我们歌词 我们歌词 再来更正一下存k1和取k2的动作。存k1时,是根据它id的hash值,假设这里是1000,把k1对象放到去去到对应的位置。而取k2时,是先计算它的hash值(导致 k2的id也是1,你什儿 值也是1000),不想到你什儿 位置去找。

    但结果会出乎我们歌词 我们歌词 意料:明明1000号位置导致 有k1,但第26行的输出结果依然是null。其导致 什么都有有我没办法 重写Key对象的equals依据。

    HashMap是用链地址法来避免冲突,也什么都有有我说,在1000号位置上,有导致 趋于稳定着多个用链表形式存储的对象。它们通过hashCode依据返回的hash值时会1000。

     我们歌词 歌词 我们歌词 通过k2的hashCode到1000号位置查找时,我我着实会得到k1。但k1有导致 仅仅是和k2具有相同的hash值,但之什么都有有和k2相等(k1和k2两把钥匙之什么都有有能开同一扇门),你什儿 不想,就都要调用Key对象的equals依据来判断两者与非 相等了。

    导致 我们歌词 我们歌词 在Key对象里没办法 定义equals依据,系统就不得不调用Object类的equals依据。导致 Object的固有依据是根据有有两个对象的内存地址来判断,什么都有有k1和k2一定不想相等,这什么都有有我为甚依然在26行通过hm.get(k2)依然得到null的导致 。

    为了避免你什儿 问题报告 ,我们歌词 我们歌词 都要打开第9到14行equals依据的注释。在你什儿 依据里,不想有有两个对象时会Key类型,不想 它们的id相等,它们就相等。

3 对面试问题报告 的说明

    导致 在项目里突然会用到HashMap,什么都有有我在面试的不想时会问你什儿 问题报告 ∶你有没办法 重写过hashCode依据?你在使用HashMap时有没办法 重写hashCode和equals依据?你是为甚写的?

    根据问下来的结果,我发现初级tcp连接员对你什儿 知识点普遍没掌握好。重申一下,导致 我们歌词 我们歌词 要在HashMap的“键”帕累托图存放自定义的对象,一定要在你什儿 对象里用个人的equals和hashCode依据来覆盖Object里的同名依据。 

     本文是从Java核心技术及面试指南这本书中相关内容改编而来。