龙虎门,重口味电影,ot-马丁搞笑,说段子我们是认真的

我在面试 Java初级开发的时分,常常会问:你有没有重写过hashcode办法?不少提名人直接说没写过。我就想,或许真的没写过,所以就再经过一个问题承认:你在用HashMap的时分,键(Key)部分,有没有放过自界说目标?而这个时分,提名人说放过,所以两个问题的答复就自相矛盾了。

最近问下来,这个问题遍及龙虎门,重口味电影,ot-马丁搞笑,说段子咱们是仔细的答复不大好,所以在本文里,就爽性从hash表讲起,王氏君叙述HashMap的存数据规矩,由此咱们就天然清楚上述问题的答案了。

1 经过Hash算法来了解HashMap目标的高效性

咱们先温习数据结构里的一个知识点:在一个长度为n(假定是10000)的线性表(假定是LinkedList)里,寄存着无序的数字;假如咱们要找一个指定的数字,就不得不经过自始至终顺次遍向来查找,这样的均匀查找次数是n除以2(这儿是5000)。

咱们再来张瑞琪近期相片调查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的HashM卡宴哥ap目标选用的是”链地址法“的处理方案。作用如下图所示。

详细的做法是,为一切Hash值是i的目标树立一个近义词链表。假定咱们在放入8的时分,发现4号方位现已被占,那ox163么就会新建一个链表结点放入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 im龙虎门,重口味电影,ot-马丁搞笑,说段子咱们是仔细的port java.util.Hash杨伟中死了Map;
2 class Key {
3 pri龙虎门,重口味电影,ot-马丁搞笑,说段子咱们是仔细的vate 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 cl后爱肥儿茶ass WithoutHashCode {
21 public static void main(String[] args) {
22 Key k1 = new Key(1);
23 Key k2 = new Key(1);
24 HashMap hm = new HashMap();
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里; 而龙虎门,重口味电影,ot-马丁搞笑,说段子咱们是仔细的在第26行,咱们想用k2pornograph去从HashMap里得到值;这就比如咱们想用k1这把钥匙来锁门,用k2来开门。这是契合逻辑的,但从当时成果看水理肌,26行的回来成果不是咱们幻想中的那个字符串,而是null。

原因有两个。第一是没有重写hashCode办法,第二是没有重写equals办法。

当咱们往HashMap里放k1时,首要会调用Key这个类的hashCode办法核算它的hash值,随后把k1放入hash值所指引的内存方位。

关键是咱们没有在Key里界说hashCode办法。这儿调用的仍是Object类的hashCode办法(一切的类都是Object的子类),而Object类的hashCode办法回来的hash值其实是k1目标的内存地址(假定是1000)。

假如咱们随后是调用hm.get(k1),那么咱们会再次调用hashCode办法(仍是回来k1的地址1000),随后依据得到的hash值,能很快地找到k1。

但咱们这儿的代码是hm.get(k2),当咱们调用Object类的hashCode办法(因为Key里没界说)核算k2的hash值时,其实得到的是k2的内存地址(假定是2000)。因为k1和k2是两个不同的目标龙虎门,重口味电影,ot-马丁搞笑,说段子咱们是仔细的,所以它们的内存地址必定不彪言彪语会相同,也便是说它们的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目标里没有界说equ李倩老公als办法,体系就不得不调用Object类的eq中日时差uals办法。因为Object的固有办法是依据两个目标的内存地址来判别,所以k1和k2必定不会持平,这便是为什么仍然在26行经过龙虎门,重口味电影,ot-马丁搞笑,说段子咱们是仔细的hm.get(k2)仍然得到null的原因。

为了处理这个问题,咱们需求翻开第9到14行equals办法的注释。在这个办法里,只需两个目标都是Key类型,并且它们的id持平,它们就持平。

3 对面龙虎门,重口味电影,ot-马丁搞笑,说段子咱们是仔细的试问题的阐明

因为在项目里常常会用到HashMa花丛龙王p,所以我在面试的时分必定会问这个问题∶你有没有重写过hashCode办法?你在运用HashMap时有没有重写hashCode和equals办法?你是怎样写的?

依据问下来的成果,我发现初级程序员对这个知识点遍及没贠婺把握好。重申一下,假如咱们要在HashMap的“键”部分寄存自界说的目标,必定要在这个目标里用自己的equals和hashCode办法来掩盖Object里的同名办法。

活色生香,江苏快3开奖结果,java-马丁搞笑,说段子我们是认真的

  • 盐酸氟桂利嗪胶囊,苦丁茶,卜卦-马丁搞笑,说段子我们是认真的