equals():反映的是对象或变量具体的值,即两个对象里面包含的值,可能是对象的引用,也可能是值类型的值。Object中的equals匹配的是对象的引用。
hashCode():计算出对象实例的哈希码,并返回哈希码,又称为散列函数。根类Object的HashCode()方法的计算依赖于对象实例的内存地址,所以每个Object对象的hashCode都是唯一的;当然如果对象所在的类重写了hashCode方法时,这个就说不一定了。
之所有了equals方法后还存在hashCode方法是因为在批量的对象比较重,hashCode要比equals快很多,也更节省资源。很多的集合都用到了hashCode
两个Obj,如果equals()相等,hashCode()一定相等。
两个Obj,如果hashCode()相等,equals()不一定相等
记得上面这两句话还是在参加工作前夕背面试题的时候看到的
所以,在集合中判断两个对象是否相等的规则是:
第一步,如果hashCode()相等,则查看第二步,否则不相等;
第二步,查看equals()是否相等,如果相等,则两个Obj相等,否则还是不相等
1.首先,equals()和hashcode()这两个方法都是从object类中继承过来的。
equals()是对两个对象的地址值进行比较(即比较是否引用同一个对象)
hashCode()是一个本地方法,它的实现是根据本地机器相关的
2.Java语言对equals()的要求如下,这些要求是必须遵循的:
A 对称性:如果x.equals(y)返回的是”true”,那么y.equals(x)也应该返回的是”true”
B 反射性:x.equals(x)必须返回的是”true”
C 类推性:如果x.equals(y)返回的是”true”,而且y.equals(z)返回的是”true”,那么z.equals(x)也应该返回的是”true”
D一致性:如果x.equals(y)返回的是”true”,只要x和y内容一直不变,不管重复x.equals(y)多少次,返回的都应该是”true”
任何情况下,x.equals(null)永远返回的是”false”;x.equals(和x不同类型的对象)永远返回的是”false”
3.equals()相等的两个对象,hashCode()一定相等。
反过来说:hashCode()不等,equals()也一定不等
hashCode()相等,equals()可能相等,也可能不等。
为什么使用hashCode方法
以java.lang.Object来理解,JVM每new一个Object,它都会将这个Object丢到一个Hash表中去,这样的话,下次做Object的比较或者取这个对象的时候,它会根据对象的hashCode再从Hash表中取这个对象。这样做的目的是提高取对象的效率。
具体的过程看得我懵懵懂懂的:
1.new Object(),JVM根据这个对象的Hashcode值,放入到对象的Hash表对应的key上,如果不同的对象确实产生了相同的hash值,也就是发生了Hash Key相同导致冲突的情况,那么就在这个Hash Key的地方产生一个链表,将所有产生相同hashCode的对象放到这个单链表上去,穿在一起。
2.比较两个对象的时候,首先根据它们的HashCode去hash表中找它的对象,当两个对象的hashCode相同,那么就是说他们这两个对象放在Hash表中的同一个key上,那么它们就一定在这个key的链表上。那么此时就只能根据Object的equals方法来比较这个对象是否相等。当两个对象的hashCode不同的话,肯定不相等,也就不用equals()。
就想我之前的那篇博文《Java中的Set,List,Map》中讲到的list和set的区别。
list是可以重复的,set是不可以重复的。那么set存储数据的时候是怎样判断存进去的数据是否存在。使用equals()方法呢,还是hashCode()方法?假如使用equals(),那么存储一个元素就要跟已存在的所有元素比较一遍,比如已存入100个元素,那么存101个元素的时候,就要调用equals方法100次。但如果使用hashCode()方法的话,它就利用了hash算法来存储数据的,这样的话每寸一个数据就调用一次hashCode方法,得到一个hashCode值及存入的位置。如果该位置不存在数据那么就直接存入,否则调用一次equals()方法,不相同则存,相同不存。这样下来整个存储也不需要调用几次equals方法。相比前面效率高了不少。
为什么要重写equals
因为Object的equals方法默认是两个对象引用的比较,意思就是指向同一内存,地址则相同,否则不想等。但是假如现在你需要利用对象里面的值来判断是否相等,则须要重写equals方法。
记得刚开始学习Java的时候,被String对象的equals()方法和“==”纠结过很长一段时间,当时我们知道String对象中的equals方法是判断值的,而“==”是地址判断。
所以说,在JDK中,String,Math等封装类都对Object中的equals()方法进行了重写。
我们先看看Object中equals方法的源代码:
我们都知道所有的对象都拥有标识(内存地址)和状态(蜀),同时“==”比较两个对象的内存地址,所以说使用Object的equals()方法是比较两个对象的内存地址是否相等。即若object1.equals(object2)为true,则表明equals1和equals2实际上是引用的同一个对象,虽然有的时候equals()方法可以满足我们的一些基本的要求,但是我们必须要清楚我们很大部分时间都是进行两个对象的比较而不是地址的比较。这个时候Object的equals()方法就不可以了,所以才会有String这些类对equals方法的改写,一次类推Dobule,Integer,Math……等等这些类都是重写了equals()的,从而进行的是内容上面的比较。
重写equals时需要重写hashCode
java.lang.Object中对hashCode的约定为:
1.在一个应用程序执行期间,如果一个对象的equals方法做比较所用到的信息没有修改的话,则对该对象调用hashCode方法多次,它必须始终如一的返回同一个整数。2.如果两个对象根据equals(Object o)方法是相同的,则调用这两个对象中任一对象的hashCode方法必须产生相同的证书结果。
3.如果两个对象根据equals(Object o)方法是不相等的,则调用这两个对象中任一对象的hashCode方法,不要求产生不同的证书结果,但如果能不同,则可能提高散列表的性能。
根据上个问题,实际上我们已经能很简单的解释这一点了,比如改写String中的equals为基于内容上的比较而不是内存地址上的比较的话,那么虽然equals相等,但并不代表内存地址相等,由于hashCode方法的定义可知内存地址不同,没改写的hashCode值也可能不同。所以违背了第二条约定。
又比如new一个对象,再new一个内容相等的对象,调用equals方法返回的true,但它们的hashCode值不同,将两个对象存入HashCode中,会使得其中包含两个相等的对象,因为是先检索hashCode值,不等的情况下才会去比较equals方法的。
07-18
07-18
07-18
07-18
07-18
“相关推荐”对你有帮助么?
-
非常没帮助
-
没帮助
-
一般
-
有帮助
-
非常有帮助
提交