其他分享
首页 > 其他分享> > JDK的equals方法都写错了,那到底该怎么写呢?(备战2022春招或暑期实习,每天进步一点点,打卡100天,Day3)

JDK的equals方法都写错了,那到底该怎么写呢?(备战2022春招或暑期实习,每天进步一点点,打卡100天,Day3)

作者:互联网

751a8ffe445fbc514b868f41fb1efccd.jpeg

1、简介

Java程序员都知道java.lang.Object类,这是所有类的超类。Object类中提供了几个public的方法,比如:

public boolean equals(Object var1) {
        return this == var1;
}

public String toString() {
    return this.getClass().getName() + "@" + Integer.toHexString(this.hashCode());
}

这些public方法第一是提供给所有的子类去扩展(覆盖),第二是明确了Java中的类所具备的通用约定。因此Java中的类在覆盖这些方法是,都需要遵守通用约定,避免程序员们各玩各的。 ​

那具体应该怎么覆盖,又应该遵守那些通用约定呢? 其实这是一个非常复杂的问题,正如Java大师约书亚·布洛克(Joshua Bloch)所说:它看似简单,但是往往很多高级程序员也无法完全正确的实现,并且如果不严格遵守,往往会导致非常严重的后果。

e18d20c94006dfe0-2857e2f09ca9e0a0-b4596c2feef70f864b7b745c5630fc44.gif

2、正文

2.1 什么时候需要重写equals方法

总结一句话就是:当我们需要比较两个对象是否“逻辑相等”时,可能需要考虑重写equals方法,比如我们需要比较值类型的类Integer、String,这些类经常需要用于承载和比较值是否相等,或者用于做个Map、Set等集合的Key值,在这些场景下我们是需要严格的去重写equals方法的。(我这里说的是可能,是因为很多情况下无招胜有招,我们或许不需要重写equals方法,至于那些场景不需要重写equals方法这个会在后面说!) ​

2.2 什么时候不需要重写equals方法

不需要实现equals方法的场景非常多,我们大致的举例说明一下:

Set_AbstractSet之equals方法.png

2.3 重写equals方法需要遵守哪些规则

重写equals方法有几条看起来很简单,但是实现起来几乎无法完全保证的约定:

  1. 自反性(Reflexivity):非null情况下,x.equals(x)必须为true

  2. 对称性(Symmetry):非null情况下,x.equals(y) = true则y.equals(x) = true

  3. 传递性(Transitive):非null情况下,x.equals(y) = true && y.equals(z) = true则x.equals(z) = true

  4. 一致性(Consistent):非null情况下,x.equals(y) = true只要x或y其中任意一个对象不被修改,那么x.equals(y) = true应该恒成立

  5. 非空性(Non-nullity):x不为null的情况下,x.equals(null)必须返回false

看到这五条规则是不是觉得头大,平时我们在写的时候,压根就没考虑过这么多条条框框,只有能实现功能上的逻辑相等了就行!

79b32118bb90cfe7.jpg

其实我觉得这么想也不能说是完全不对,因为如果一定要完完全全的按照它这个规范来,那么面向对象很多功能都用不了了,比如说继承。 其实Java的JDK中也是有些代码不满足上面说的这五条规范的,比如我们看下如下这段代码(猜猜它会输出什么?):

package com.lizba.tips;

import java.sql.Timestamp;
import java.util.Date;

/**
 * <p>
 *    Java自带jdk equals方法的对称性测试
 * </p>
 *
 * @Author: Liziba
 * @Date: 2021/10/24 14:48
 */
public class EqualsDemo {


    public static void main(String[] args) {
        Date date = new Date();
        Timestamp timestamp = new Timestamp(date.getTime());
        System.out.println("Date equals to Timestamp: " + date.equals(timestamp));
        System.out.println("Timestamp equals to Date: " + timestamp.equals(date));
    }

}

是的你没看错,第一个输出了true,第二个输出了false。很显然这不满足第二点:对称性(Symmetry)。

Date equals to Timestamp: true
Timestamp equals to Date: false

基于这种情况,Java并没有很好的办法去解决。只能说告诉你不用混用Date和Timestamp,并且无论如何不要去equals比较Date和Timestamp,这个在Timestamp中的类和equals方法上也是有说明的! ​

2.4 实现高质量equals方法的诀窍

上面聊了一些什么时候需要重写equals方法、什么时候不需要重写equals方法、重写equals方法需要遵守的规则。这里我们聊一聊实现高质量equals方法的诀窍。 在这里我将会引用java.util.AbstractSet类中的equals方法来阐述如何写一个高质量的equals方法,因为小捌发现它非常经典。

java.util.AbstractSet中的equals方法:

public abstract class AbstractSet<E> extends AbstractCollection<E> implements Set<E> {
 
    // ...
    
    public boolean equals(Object o) {
        if (o == this)
            return true;

        if (!(o instanceof Set))
            return false;
        Collection<?> c = (Collection<?>) o;
        if (c.size() != size())
            return false;
        try {
            return containsAll(c);
        } catch (ClassCastException unused)   {
            return false;
        } catch (NullPointerException unused) {
            return false;
        }
    }
    
    // ...
    
}

第一点:o == this 使用==操作符,判断比较对象和当前对象的引用是否相等,如果相等代表同一个对象,那就直接返回true。 ​

第二点:o instanceof Set 通过instanceof操作符检查参数类型是否正确,如果类型都不对就不需要比较了。 ​

第三点:c.size() != size() 这是在Abstract中的特殊存在,并不是所有的都需要这样比较,提前比较大小的好处是无需进行每个域的比较,如果大小都不相等,就可以直接返回了。通常情况下,这样做性能更好! ​

第四点:containsAll(c) 对该类中的每一个域进行比较,如果所有的域都相等则返回true,如果不相等返回false。 ​

第五点:重写hashcode 重写equals方法时一定要重写hashcode方法,比如java.util.AbstractSet中重写了hashCode()方法,它将每个域的hashcode进行了拼接

public int hashCode() {
    int h = 0;
    Iterator<E> i = iterator();
    while (i.hasNext()) {
        E obj = i.next();
        if (obj != null)
            h += obj.hashCode();
    }
    return h;
}

第六点:不要修改equals(Object o)的参数类型 这一点看似很简单,但是如果你不是用IDE自动生成的equals方法,而是自己手动敲得代码,很容易会将Object类型,改成当前类的类型,这种做法是不对的哈!因为这不是重写(Override),这是重载(Overload)

标签:JDK,true,方法,equals,春招,Timestamp,Date,打卡,重写
来源: https://blog.csdn.net/qq_41125219/article/details/120937004