面试必问hashCode和equals_JVM

面试必问hashCode与equals

hashCode和equals用来标识对象,两个方法协同工作可用来判断两个对象是否相等。这两方法来源于:java.lang.Object

面试必问hashCode和equals_JVM_02




众所周知,根据生产的哈希将数据散列开来,可以是存取元素更快,对象通过调用Object.hashCode();生成哈希值;由于不可避免地存在哈希值冲突的情况,因此,当hashCode相同时,还需要进行equals方法比较,但是,若hashCode不同,将直接判定两个对象不相等,跳过equals,这加快了冲突处理效率。

Object类定义中对hashCode和equals要求如下:



在Map和Set类集合中,用到这两个方法时,首先判断hashCode的值,如果hash值相等,则在判断equals的结果,HashMap中get方法判断如下:



先进性hash值比较,然后进行equals比较。如果hash只不相等则equals方法都不用比较了。

这样一来就是要求hashCode方法要求就高了很多,一个优秀的哈希算法应尽可能地让元素均匀分布,降低冲突概念,即就是尽量在equals不相等的情况下hash值也不相等,这样使用&&或者||短路操作一旦生效,会极大地提高程序的执行效率。如果自定义Map的键,那么必须重写equals和hashCode方法。

此外,因为Set存储的是不重复的对象,依据hashCode和equals进行判断,所以Set存储的自定义对象也必须重写这两个方法。此时,如果重写equals而不重写hashCode,到底会有什么影响呢?

请看下面的代码:



输出结果:3

看源码发现Object中的hashCode方法是native方法:



那就只能去看虚拟机中的源码了,源码下载地址:

openJDK 7下载地址1:http://download.java.net/openjdk/jdk7

网上找找比什么盘,CSDN上都可以找到,并且下载的快,自己看着办咯。

进入openjdk\jdk\src\share\classes\java\lang目录下,可以看到 Object.java源码,打开



打开openjdk\jdk\src\share\native\java\lang\目录,查看Object.c文件,可以看到hashCode()的方法被注册成有JVM_IHashCode方法指针来处理:



JVM_IHashCode方法指针在 openjdk\hotspot\src\share\vm\prims\jvm.cpp中定义,如下:



如上可以看出,JVM_IHashCode方法中调用了ObjectSynchronizer::FastHashCode方法

ObjectSynchronizer::fashHashCode()方法在 openjdk\hotspot\src\share\vm\runtime\synchronizer.cpp文件中实现。



以上这么多代码的核心部分:



这里也就印证了:hashCode就是根据对象的地址进行相关计算得到int类型数值的。

上面EqualsDemo没有写hashCode,所以导致最后的结果是3,如果不想存储重复的元素,那么需要在EqualsDemo类中重写hashCode方法,代码如下:



最后运行Test类,得出的结果:1

因为上面的name是String类型,并且String类重写了hashCode方法了,所以这里就直接使用了。

equals的实现方式与类的具体业务逻辑有关,但又各不相同,因而应尽量分享源码来确定其判断结果,比如下面的代码:

输出:equal

两个不同的集合,结果输出相等。让我们来看看这两个集合的equals方法是怎么实现的:

看其源码发现两个集合都是使用AbstractList中的equals方法(JDK版本是1.8),每个版本可能有差别。

面试题

两个对象的equals为true,则两个对象的hashCode相等。

两个对象的hashCode相等,两个对象的equals不一定为true。