hashCode() 和 equals()的区别

hashCode() 和 equals()的区别

equals()

equals() 办法用于比拟两个对象能否相等,它与 == 相等比拟符有着实质的不同。

在万物皆对象的 Java 体系中,系统把判别对象能否相等的权利交给程序员。详细的措施是把 equals() 办法写到 Object 类中,并让一切类继承 Object 类。 这样程序员就能在自定义的类中重写 equals() 办法, 从而完成本人的比拟逻辑。

hashCode()

hashCode() 的意义是哈希值, 哈希值是经哈希函数运算后得到的结果,哈希函数可以保证相同的输入可以得到相同的输出(哈希值),但是不可以保证不同的输入总是能得出不同的输出。

当输入的样本量足够大时,是会产生哈希抵触的,也就是说不同的输入产生了相同的输出。

暂且不谈抵触,就相同的输入可以产生相同的输出这点而言,是及其珍贵的。它使得系统只需求经过简单的运算,在时间复杂度O(1)的状况下就能得出数据的映射关系,依据这种特性,散列表应运而生。

一种主流的散列表完成是:用数组作为哈希函数的输出域,输入值经过哈希函数计算后得到哈希值。然后依据哈希值,在数组种找到对应的存储单元。当发作抵触时,对应的存储单元以链表的方式保管抵触的数据。

两者关系

在大多数编程理论中,归根结底会落实到数据的存取问题上。 在汇编言语时期,你需求老诚实实地对每个数据操作编写存取语句。

而随着时期开展到今天,我们都用更便当灵敏的高级言语编写代码,比方 Java。

Java 以面向对象为中心思想,封装了一系列操作数据的 api,降低了数据操作的复杂度。

但在我们对数据停止操作之前,首先要把数据依照一定的数据构造保管到存储单元中,否则操作数据将无从谈起。

但是不同的数据构造有各自的特性,我们在存储数据的时分需求选择适宜的数据构造停止存储。 Java 依据不同的数据构造提供了丰厚的容器类,便当程序员选择合适业务的容器类停止开发。

经过继承关系图我们看到 Java 的容器类被分为 Collection 和 Map 两大类,Collection 又能够进一步分为 List 和 Set。 其中 Map 和 Set 都是不允许元素反复的,严厉来说Map存储的是键值对,它不允许反复的键值。

值得留意的是:Map 和 Set 的绝大多数完成类的底层都会用到散列表构造。

讲到这里我们提取两个关键字不允许反复和散列表构造,

回忆 hashCode() 和 equals() 的特性,你能否想到了些什么东西呢?

equals()力不从心

上面提到 Set 和 Map 不寄存反复的元素(key),这些容器在存储元素的时必需对元素做出判别:在当前的容器中有没有和新元素相同的元素?

你可能会想:这容易呀,直接调用元素对象的 equals() 办法停止比拟不就行了吗?

假如容器中的存储的对象数量较少,这的确是个好主见,但是假如容器中寄存的对象到达了一定的范围,要调用容器中一切对象的 equals() 办法和新元素停止比拟,就不是一件容易的事情了。

就算 equals() 办法的比拟逻辑简单无比,总的来说也是一个时间复杂度为 O(n) 的操作啊。

hashCode() 小力出奇观

但在散列表的根底上,判别新对象能否和已存在对象相同就容易得多了。

由于每个对象都自带有 hashCode(),这个 hashCode 将会用作散列表哈希函数的输入,hashCode 经过哈希函数计算后得到哈希值,新对象会依据哈希值,存储到相应的内存的单元。

我们无妨假定两个相同的对象,hashCode() 一定相同,这么一来就表现出哈希函数的能力了。

由于相同的输入一定会产生相同的输出,于是假如新对象,和容器中已存在的对象相同,新对象计算出的哈希值就会和已存在的对象的哈希值产生抵触。

这时容器就能判别:这个新参加的元素曾经存在,需求另作处置:掩盖掉原来的元素(key)或舍弃。

依照这个思绪,假如这个元素计算出的哈希值所对应的内存单元没有产生抵触,也就是没有反复的元素,那么它就能够直接插入。

所以当运用 hashCode() 时,判别能否有相同元素的代价,只是一次哈希计算,时间复杂度为O(1),这极大地进步了数据的存储性能。

总结

1、假如两个对象相同(即用equals比拟返回true),那么它们的hashCode值一定要相同;

2、假如两个对象的hashCode相同,它们并不一定相同(即用equals比拟返回false)。

为了进步程序的效率才完成了hashcode办法,先停止hashcode的比拟,假如不同,那没就不用在停止equals的比拟了,这样就大大减少了equals比拟的次数。

你可能感兴趣的:(hashcode)