equals方法和hashCode方法是Object类中的两个基本方法,它们共同判断两个对象是否相等。为什么要这样设计?究其原因,就在于“性能”二字。使用HashMap后,我们知道经过hash计算后,我们可以直接定位到某个值存放的位置,那么试想一下,如果现在要查询某个值是否在集合中呢?如果元素(存储位置)不是通过hash方法直接定位的,那么只能按照集合的顺序一个一个比较,这种顺序比较的效率明显低于hash定位方法。这是hash和hashCode的值。当我们比较两个对象是否相等时,可以先用hashCode来比较。如果比较的结果为真,那么我们可以用equals再次确认两个对象是否相等。如果比较的结果为真,则两个对象相等,否则认为两个对象不相等。这大大提高了对象比较的效率,这也是为什么Java设计使用hashCode和equals来确认两个对象是否相等的原因。那么为什么不直接使用hashCode来判断两个对象是否相等呢?这是因为不同对象的hashCode可能相同;但是hashCode不同的对象一定不相等,所以第一次使用hashCode可以快速判断对象是否相等。但是即使知道了上面的基础知识,还是解决不了本文的问题,即:为什么重写equals时一定要重写hashCode?要弄清楚这个问题的根源,就得从这两种方法说起。1.equals方法Object类中的equals方法用于检测一个对象是否等于另一个对象。在Object类中,此方法将确定两个对象是否具有相同的引用。如果两个对象具有相同的引用,则它们必须相等。equals方法的实现源码如下:publicbooleanequals(Objectobj){return(this==obj);}通过上面的源码和equals的定义,我们可以看出在大多数情况下equals的判断是无意义的!例如,在Object中使用equals来比较两个自定义对象是否相等是完全没有意义的(因为无论对象是否相等,结果都是false)。这个问题可以用下面的例子来说明:publicclassEqualsMyClassExample{publicstaticvoidmain(String[]args){Personu1=newPerson();u1.setName("Java");u1.setAge(18);Personu2=newPerson();u1。setName("Java");u1.setAge(18);//打印等于结果System.out.println("equalsresult:"+u1.equals(u2));}}classPerson{privateStringname;privateintage;publicStringgetName(){returnname;}publicvoidsetName(Stringname){this.name=name;}publicintgetAge(){returnage;}publicvoidsetAge(intage){this.age=age;}}上面程序的执行结果如下图所示,所以一般情况下,如果我们要判断两个对象是否相等,就必须重写equals方法,这也是为什么要重写equals方法的原因。2、hashCode方法hashCode翻译成中文就是哈希码,它是从一个对象派生出来的一个整数值,这个值可以是任意整数,包括正数或负数。需要注意的是:哈希码是不规则的。如果x和y是两个不同的对象,则x.hashCode()和y.hashCode()基本上永远不会相同;但如果a和b相等,则a.hashCode()必须等于b.hashCode()。Object中的hashCode源码如下:publicnativeinthashCode();从上面的源码可以看出,Object中的hashCode调用了一个(native)本地方法,返回一个int类型的整数。当然,这个整数可以是正数也可以是负数。hashCode使用等值hashCode必须相同例子:publicclassHashCodeExample{publicstaticvoidmain(String[]args){Strings1="Hello";Strings2="Hello";Strings3="Java";System.out.println("s1hashCode:"+s1.hashCode());System.out.println("s2hashCode:"+s2.hashCode());System.out.println("s3hashCode:"+s3.hashCode());}}的执行结果以上程序,如下图所示:不同值的hashCode也可能有相同的例子:publicclassHashCodeExample{publicstaticvoidmain(String[]args){Strings1="Aa";Strings2="BB";System.out.println("s1hashCode:"+s1.hashCode());System.out.println("s2hashCode:"+s2.hashCode());}}以上程序的执行结果如下图所示:3、为什么要一起重写?接下来回到本文的主题,为什么重写equals的时候一定要重写hashCode呢?为了解释这个问题,我们需要从下面的例子说起。3.1SetSet集合的正常使用是用来保存不同的对象,相同的对象会被Set合并,最后留下唯一的一条数据。它的正常用法如下:add("Java");set.add("MySQL");set.add("MySQL");set.add("Redis");System.out.println("设置集合长度:"+set.size());System.out.println();//打印Set中的所有元素set.forEach(d->System.out.println(d));}}以上程序的执行结果如图下图:从上面的结果可以看出,重复的数据已经被Set集合“合并”了,这也是Set集合最大的特点:去重。3.2Set集合的“异常”然而,如果我们在Set集合中存储一个自定义对象,只重写equals方法,有趣的事情就会发生,如下代码所示:;importjava.util.Set;publicclassEqualsExample{publicstaticvoidmain(String[]args){//对象1Persionp1=newPersion();p1.setName("Java");p1.setAge(18);//对象2Persionp2=newPersion();p2.setName("Java");p2.setAge(18);//创建一个Set集合Set
