2分彩破解_为什么要重写hashcode和equals方法?初级程序员在面试中很少能说清楚。

  • 时间:
  • 浏览:0

     我在面试 Java初级开发的刚刚,突然会问:你有没办法 重写过hashcode法律法律依据?不少候选人直接说没写过。让他想,或许真的没写过,于是就再通过另另还还有一个 多多多多问題确认:你在用HashMap的刚刚,键(Key)要素,有没办法 放过自定义对象?而什儿 刚刚,候选人说放过,于是另另还还有一个 多多多多问題的回答就自相矛盾了。

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

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

    我门我门我门 我门我门我门 我门我门我门 先复习数据特征里的另另还还有一个 多多多多知识点:在另另还还有一个 多多多多长度为n(假设是500)的线性表(假设是ArrayList)里,存放着无序的数字;意味着着我门我门我门 我门我门我门 我门我门我门 要找另另还还有一个 多多多多指定的数字,就不得不通过从头到尾依次遍历来查找,原本的平均查找次数是n除以2(这里是500)。

我门我门我门 我门我门我门 我门我门我门 再来观察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对象的内存地址(假设是50)。

    

    意味着着我门我门我门 我门我门我门 我门我门我门 我应该 是调用hm.get(k1),没办法 我门我门我门 我门我门我门 我门我门我门 会再次调用hashCode法律法律依据(还是返回k1的地址50),我应该 根据得到的hash值,能调慢地找到k1。

    但我门我门我门 我门我门我门 我门我门我门 这里的代码是hm.get(k2),我门我门我门 我门我门我门 我门我门我门 歌词 调用Object类的hashCode法律法律依据(意味着着Key里没定义)计算k2的hash值时,我我随便说说得到的是k2的内存地址(假设是50)。意味着着k1和k2是另另还还有一个 多多多多不同的对象,很多它们的内存地址一定不需要相同,也很多 说它们的hash值一定不同,这很多 我门我门我门 我门我门我门 我门我门我门 无法用k2的hash值去拿k1的意味着着。

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

    我门我门我门 我门我门我门 我门我门我门 再来更正一下存k1和取k2的动作。存k1时,是根据它id的hash值,假设这里是50,把k1对象放到 到对应的位置。而取k2时,是先计算它的hash值(意味着着k2的id也是1,什儿 值也是50),我应该 到什儿 位置去找。

    但结果会出乎我门我门我门 我门我门我门 我门我门我门 意料:明明50号位置意味着着有k1,但第26行的输出结果依然是null。其意味着着很多 没办法 重写Key对象的equals法律法律依据。

    HashMap是用链地址法来解决冲突,也很多 说,在50号位置上,有意味着着指在着多个用链表形式存储的对象。它们通过hashCode法律法律依据返回的hash值全部刚刚50。

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