Java中的equals()和hashCode() - 超详细篇 (2)

比如下面的代码

public class EqualsDemo { private int m; private String str; public static void main(String[] args) { EqualsDemo demo1 = new EqualsDemo(1, "JavaLover1"); EqualsDemo demo2 = new EqualsDemo(1, "JavaLover1"); System.out.println(demo1.equals(demo2)); } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof EqualsDemo)) return false; EqualsDemo demo = (EqualsDemo) o; // 改了这行 return m == demo.m && str.equals(demo.str); } }

可以看到,多了一个String对象引用作为属性

那我们在比较的时候,根据套娃的原则,再次利用String对象的equals方法进行比较即可

其他的部分都一样

好了,现在equals方法写完了,我上个厕所先

真的写完了吗?我不信(脑补ing。。。)

因为还是有潜在的空指针异常

设想一下,上面str真的会存在吗?如果str为null怎么办?

所以我们还要对str进行空指针判断,不过不需要我们来做,而是通过Objects这个工具类(Java7诞生的一个工具类),它内置的equals

方法可以帮你在比较两个对象的同时加上null判断

Objects.equals方法如下:

public final class Objects { public static boolean equals(Object a, Object b) { return (a == b) || (a != null && a.equals(b)); } }

改了以后的equals()最终代码如下:

@Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof EqualsDemo)) return false; EqualsDemo demo = (EqualsDemo) o; return m == demo.m && Objects.equals(str,demo.str); }

好了,万事俱备了,只欠东风

东风

东风?什么东风?

东风就是你的父亲啊

如果是在子类中定义equals,那么还要考虑到父类(如果直接继承自Object则不考虑)

改了之后的代码如下:

@Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof EqualsDemo)) return false; // 加了这一行 if(!super.equals(o)) return false; EqualsDemo demo = (EqualsDemo) o; return m == demo.m && Objects.equals(str,demo.str); }

你可能想知道,为啥放到第三行?

那是因为前两行属于最外侧的判断

你可以这样想,如果传来的对象o是父类的对象,那么父类super的判断放在这个位置就很合适了

(因为此时o instanceof EqualsDemo肯定返回false,这样就省去了super.equals()的判断)

好了,我累了,可以结束了吗?

img

等一下,地球还没有毁灭,事情也还没有结束。

上面的instanceof有个很大的缺陷,就是违反了equals的对称性

下面我们顺藤摸瓜,来说下equals方法规范的5个特性:

自反性:就是自己反过来跟自己比,要返回true;比如x.equals(x) == true

对称性:就是x.equals(y) == true时,也要y.equals(y) == true

传递性:就是x.equals(y) == true,同时y.equals(z) == true,那么x.equals(z) == true

一致性:就是传说中的幂等性,即x.equals(y)调用多次,都应该返回一样的结果

非空和空比较则返回false的特性:就是x.equals(y)中,如果x非空,而y空,则返回false

好了,回到instanceof,上面提到它没有满足对称性

是因为用了instanceof来做比较的话,Son.equals(Father)永远不会为真,而Father.equals(Son)却有可能为真,这就不对称了

所以干脆就让Father.equals(Son)也永远不为真

那要怎么做呢?

答案就是instanceof的弟弟:getClass

instanceof用来判断是否为当前类或者子类

而getClass只用来判断是否为当前类

改了之后,代码如下

public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; if(!super.equals(o)) return false; EqualsDemo demo = (EqualsDemo) o; return m == demo.m && Objects.equals(str,demo.str); }

好了,看朋友们也累了,今天的equals方法就先到这里了

over

下面总结下equals方法的核心内容,总共就是五步(这次真的是结束了):

判断两个引用指向的对象是否相等

判断传来的参数是否为空

判断传来的参数是否属于当前类

如果有继承父类,则也需要调用父类的super.equals()方法(Object除外)

最后比较各个属性值是否相等(如果属性为对象引用,则需要通过Objects.equals(a,b)方法来比较引用对象的属性值)

什么是hashCode()方法

hashCode也叫散列码(哈希码),它用来计算对象中所有属性的散列值

关于散列这里就不展开了,我们在这里只需要知道两点:

散列值为整数,可以为负值

散列值可以用来确定元素在散列表中的位置(有可能两个元素拥有相同的散列值,这个就是散列冲突)

在Object中,hashCode()是一个本地方法,因为Object没有属性,所以默认返回的是对象的内存地址

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zydjyp.html