大发飞艇app争霸_为什么要重写hashcode和equals方法?初级程序员在面试中很少能说清楚。

  • 时间:
  • 浏览:1
  • 来源:福建生活网_福建人的网上生活家园

     我在面试 Java初级开发的前一天,时不完会问:你有越来越 重写过hashcode法律法律依据?不少候选人直接说没写过。让他想,或许真的没写过,于是就再通过有一十个 问题确认:你在用HashMap的前一天,键(Key)累积,有越来越 放过自定义对象?而这个 前一天,候选人说放过,于是有一十个 问题的回答就自相矛盾了。

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

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

    亲戚亲戚村里人 歌词 歌词 先复习数据价值形式里的有一十个 知识点:在有一十个 长度为n(假设是40000)的线性表(假设是ArrayList)里,存放着无序的数字;而且亲戚亲戚村里人 歌词 歌词 要找有一十个 指定的数字,就不得不通过从头到尾依次遍历来查找,前一天的平均查找次数是n除以2(这里是40000)。

亲戚亲戚村里人 歌词 歌词 再来观察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对象的内存地址(假设是4000)。

    

    而且亲戚亲戚村里人 歌词 歌词 之后是调用hm.get(k1),越来越 亲戚亲戚村里人 歌词 歌词 会再次调用hashCode法律法律依据(还是返回k1的地址4000),之后根据得到的hash值,能调慢地找到k1。

    但亲戚亲戚村里人 歌词 歌词 这里的代码是hm.get(k2),当亲戚亲戚村里人 歌词 歌词 调用Object类的hashCode法律法律依据(而且Key里没定义)计算k2的hash值时,我我觉得得到的是k2的内存地址(假设是4000)。而且k1和k2是有一十个 不同的对象,之后我它们的内存地址一定不想相同,也之后我说它们的hash值一定不同,这之后我亲戚亲戚村里人 歌词 歌词 无法用k2的hash值去拿k1的意味。

    当亲戚亲戚村里人 歌词 歌词 把第16和17行的hashCode法律法律依据的注释打上去后,会发现它是返回id属性的hashCode值,这里k1和k2的id一定会1,之后我它们的hash值是相等的。

    亲戚亲戚村里人 歌词 歌词 再来更正一下存k1和取k2的动作。存k1时,是根据它id的hash值,假设这里是400,把k1对象上上放对应的位置。而取k2时,是先计算它的hash值(而且k2的id也是1,这个 值也是400),之后到这个 位置去找。

    但结果会出乎亲戚亲戚村里人 歌词 歌词 意料:明明400号位置而且有k1,但第26行的输出结果依然是null。其意味之后我越来越 重写Key对象的equals法律法律依据。

    HashMap是用链地址法来正确处理冲突,也之后我说,在400号位置上,有而且地处着多个用链表形式存储的对象。它们通过hashCode法律法律依据返回的hash值一定会400。

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