1. 等价性equals()与==
首先先谈一下引用等价性与对象等价性,试想有两个同样的产品AB,那么A是否等价于B呢?
先说结论从引用等价性来讲A不等价于B,而从对象等价性来讲A等价于B。
原因:A与B是同样的产品,所以样子形状等等属性都是一样的所以对象等价性等价,但A与B虽说一模一样,但毕竟是两个物品,所以引用等价性不等价。
回到正题,此处==代表引用等价性,而equals代表对象等价性,其本质是引用等价性是通过判断两个对象指向存储空间的地址是否相等来判断是否等价,而对象等价性是通过判断两个对象属性的值是否相等来判断等价性。
值得一提的是默认情况下equals默认是判断引用等价性的,但往往不符合实现者期望,所以就需要重写equals方法使其满足对象等价性。(记住equals重写时,参数类型要记得是Object哦,不然那个叫重载。→w→)
另外equals方法有以下特性:equals()的自反、传递、对称。
2. hashCode()
1.equals()相等的两个对象他们的hashCode()肯定相等,也就是用equals()对比是绝对可靠的。
2.hashCode()相等的两个对象他们的equals()不一定相等,也就是hashCode()不是绝对可靠的。
具体原因大家可以参考这篇博客,写的很清楚详细。(其实就是哈希散列的技术)
总之记住,重写了equals方法一定要重写hashcode方法!
最后给大家安利一个重写hashCode的方法——Objects.hashCode。谁用谁知道~
3. 可变对象的观察等价性、行为等价性
行为等价性:调用对象的任何方法,允许调用两个对象的任何方法,包括mutator,都展示出一致的结果 。(指向的地址应相同)
对可变类型,实现行为等价性即可,也就是说,只有指向同样内存空间的objects,才是相等的。
什么意思?就是假设有一个可变的数据类型Person(人啊,都是善变的),我们new两个PersonA和B,那么此时即使AB所有属性都相等,那么我们也不应该重写equals方法判定他们相等,因为他们指向两个地址。(形象点就是假设现在A和B都喜欢一个男孩,但是不意味着A与B会一直喜欢下去。如果突然有一天A突然意识到自己也是男孩,喜欢妹子了。那这个时候AB就不等价了嘛。呵,男人!哼,都是鳝变的。)
所以对可变类型来说,无需重写这两个函数,直接继承 Object对象的两个方法即可。 如果一定要判断两个可变对象看起来是否一致,最好定义一个新的方法。
equals()和hashCode()的最终规则
对于不可变类型:
- equals应该比较抽象值。这与说equals应该提供行为等价性是一样的。
- hashcode应该将抽象值映射为一个整数。
对于可变类型:
- equals应该比较引用,就像==。再说一次,这与说equals应该提供行为等价一样。
- hashcode应该将引用映射为一个整数。