秒秒快3官方安卓_为什么要重写hashcode和equals方法?初级程序员在面试中很少能说清楚。

  • 时间:
  • 浏览:0
  • 来源:黑域基地_提供零度娱乐网技术_酷玩娱乐网资讯

     我在面试 Java初级开发的日后,老要会问:你有没法 重写过hashcode土法律法律依据?不少候选人直接说没写过。我你要想,或许真的没写过,于是就再通过有另另一四个问题图片图片确认:你在用HashMap的日后,键(Key)要素,有没法 放过自定义对象?而这名 日后,候选人说放过,于是有另另一四个问题图片图片的回答就自相矛盾了。

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

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

    我们歌词 我们歌词 儿先复习数据特性里的有另另一四个知识点:在有另另一四个长度为n(假设是1000)的线性表(假设是ArrayList)里,存放着无序的数字;不可能 我们歌词 我们歌词 儿要找有另另一四个指定的数字,就不得不通过从头到尾依次遍历来查找,日后 的平均查找次数是n除以2(这里是1000)。

我们歌词 我们歌词 儿再来观察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对象的内存地址(假设是100)。

    

    不可能 我们歌词 我们歌词 儿之后是调用hm.get(k1),没法 我们歌词 我们歌词 儿会再次调用hashCode土法律法律依据(还是返回k1的地址100),之后根据得到的hash值,能调慢地找到k1。

    但我们歌词 我们歌词 儿这里的代码是hm.get(k2),我们歌词 我们歌词 我们歌词 儿调用Object类的hashCode土法律法律依据(不可能 Key里没定义)计算k2的hash值时,觉得得到的是k2的内存地址(假设是100)。不可能 k1和k2是有另另一四个不同的对象,很多它们的内存地址一定不必相同,也很多我说它们的hash值一定不同,这很多我我们歌词 我们歌词 儿无法用k2的hash值去拿k1的原因分析分析。

    我们歌词 我们歌词 我们歌词 儿把第16和17行的hashCode土法律法律依据的注释加进去后,会发现它是返回id属性的hashCode值,这里k1和k2的id后会1,很多它们的hash值是相等的。

    我们歌词 我们歌词 儿再来更正一下存k1和取k2的动作。存k1时,是根据它id的hash值,假设这里是100,把k1对象插进到对应的位置。而取k2时,是先计算它的hash值(不可能 k2的id也是1,这名 值也是100),之后到这名 位置去找。

    但结果会出乎我们歌词 我们歌词 儿意料:明明100号位置不可能 有k1,但第26行的输出结果依然是null。其原因分析分析很多我没法 重写Key对象的equals土法律法律依据。

    HashMap是用链地址法来处置冲突,也很多我说,在100号位置上,有不可能 发生着多个用链表形式存储的对象。它们通过hashCode土法律法律依据返回的hash值后会100。

     我们歌词 我们歌词 我们歌词 儿通过k2的hashCode到100号位置查找时,觉得会得到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核心技术及面试指南这本书中相关内容改编而来。