为什么要同时重写 equals 和 HashCode?这个经典面试题你会答吗?

写了多年Java的你,如果被问到: equals和hashCode为什么要同时重写呢? 你有信心能完整地回答上来吗?

不得不说这是一个很基础的问题,但又不失为一个经典的面试题。 如果在面试中真碰到这个问题,我想有可能会有很多小伙伴儿们栽在这个问题上,不信你自己来回答下试试?

equals和hashCode是object类的重要方法

如果重写了equals不一定但最好重写hashCode

言归正传,关于是否要同时重写equals和hashCode的问题,我的答案是: 如果重写了equals最好重写hashCode,这几乎是默认的规则。

因为Java对于没有重写equals和hashCode时的规定如下:

如果两个对象通过equals方法比较相等,则他们hashCode的返回值一定要相等。但如果两个对象的hashCode值相等,他们通过equals方法比较的返回值则不一定相等。

如果两个对象hashCode的返回值相等,不能判断两个对象是相等的。但如果两个对象的hashCode的返回值不相等,则可以判定两个对象一定不相等。

以上所说的规则可以简单归纳为:

  • 两个对象相等,hashCode一定相等

  • 两个对象不等,hashCode不一定不等

  • hashCode相等,两个对象不一定相等

  • hashCode不等,两个对象一定不等

可以说如果理解了这四句话,你就能明白equals和hashCode要不要同时重写的问题了。 看到这里,你完全明白了吗? 如果你刚要准备点头却又慢慢摇起头来,那么你可能就是面试被刷的那个人了,你还得接着往下看,下面是对以上总结的具体解释。

equals和hashCode是两个形影不离的好朋友,但彼此又不那么信任

也许对很多常写增删改查的小伙儿伴来说,这两个方法可能一个都没有重写过,更别说去琢磨是否要同时重写了呢? 所以,要想弄明白不同时重写equals和hashCode会发生怎样的后果,我们需要先整明白以下几点:

  1. equals和hashCode有什么作用? 他们是什么关系?

  2. 为什么要重写equals和hashCode?

  3. 为什么重写了equals最好也重写hashCode?

  4. 如何重写equals和hashCode才正确?

前方高能预警,大家坐稳扶好,老司机要发车了~

01.equals和hashCode有什么作用?他们是什么关系?

要了解这两个方法的作用,咱们得往Java的祖坟上刨,那就得看看Object这个根类了,因为Object是这两个方法的最终发源地。

先来看equals方法的源码:

public boolean equals(Object obj) {
        return (this == obj);
}

怎么样是不是很简单? 就是这么粗暴,一个==号就解决了。 很明显equals方法就是比较两个对象是否相等,通过其引用地址值来进行比较。

相比较equals方法,hashCode方法就没有那么简单了,其源码如下:

public native int hashCode();

它是一个native方法,可以根据平台自行实现,但它对其实现提出了一定的要求:

  1. 在同样的条件下,同一个对象无论运行多少次,返回的hash值必须一样。

  2. 如果两个对象通过equals方法比较判定相等,则他们通过hashCode方法返回的hash值也必须相等。

  3. 如果两个对象通过equals方法比较判定不相等,则不必保证他们通过hashCode返回的hash值不相等。

因此,这两个方法的作用就是为了对象间的比较,而他们之间的关系都和其方法的规则和约束有关,就像我们上文总结的规则一致,小伙伴们可以再返回上文回味一下,说不定会有新的领悟哦~

02.为什么要重写equals和hashCode?

因为这两个方法都跟对象的比较有关,所以如果在程序中要做对象比较,那大概率要重写这两个方法了。 因为equals默认的比较逻辑就是对象的地址进行比较,两个对象内存地址肯定不同,所以无论如何两个对象通过eqals比较肯定返回false。

但在实际编程中,我们经常会遇到去重,或者将对象放到有序集合中,或者将对象存入无重复的集合中,这时如果没有重写equals和hashCode,则无法达到需求。

举个例子,系统中同时存在两个对象,对象A和对象B,其姓名和身份证号一模一样。 此时,在系统内存中是两个对象,但其内容一致分明是一个人同时产生了两条重复信息。 如果使用默认的equals方法比较,则这两个对象永远不相等,永远不能比出来是一条相同的重复信息。 所以,要重写equals和hashCode方法来达到以上需求效果。

03.为什么重写了equals最好也重写hashCode?

这个问题其实上面的规则已经讲的很明白了,如果你能理解上面两者的约束关系,你基本不会有这个疑问。 但既然提出来了,我就再啰嗦两句。 接着上面的例子讲,如果有很多对象的信息要放到一个HashSet集合中,我们都知道HashSet有去重唯一的特点,此时,若让这些元素去一个个的equals比较,未免太损耗性能。

所以HashSet的实现引入了HashCode,先比较其HashCode值,如果相等再比较equals,这样就大大提高了效率。所以,如果你只重写了equals而没有重写hashCode,在使用集合时可能会出现意想不到的结果哦!

04.如何重写equals和hashCode才正确?

关于这个问题,你不但要理解上文的重写它们的原因,你必须要遵循好上文提到的规则和约束,否则就会出现你不想看到的状况结果。 此外,再总结下equals重写时必须遵守的规范特性,以确保重写的正确性:

  • 自反性: x.equals(x)==true,自己永远equals自己

  • 对称性: 如果x.equals(y)==true,那么y.equals(x)==true,相同的两个对象互相equals比较永远相等

  • 一致性: 在x、y没有修改的情况下,多次比较x.equals(y)的结果一致

  • 传递性: 如果x.equals(y)==true且y.equals(z)==true,则x.equals(z)==true

总结:以上就是对于equals和hashCode方法为什么要同时重写的经典Java面试题的解答,小伙伴儿们掌握了吗?如果有更多见解,欢迎留言讨论!

我来评几句
登录后评论

已发表评论数()

相关站点

+订阅
热门文章