幸运pk10下载安装 _为什么要重写hashcode和equals方法?初级程序员在面试中很少能说清楚。

  • 时间:
  • 浏览:1
  • 来源:山东网_专注山东新闻_山东的主流媒体

     我在面试 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法律法律方法?你是缘何写的?

    根据问下来的结果,我发现初级线程池池员对你这人 知识点普遍没掌握好。重申一下,原因分析分析我你都可不可以 们我你都可不可以 们要在HashMap的“键”每段存放自定义的对象,一定要在你这人 对象里用当时人的equals和hashCode法律法律方法来覆盖Object里的同名法律法律方法。 

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