为什么要重写 hashCode() 和 equals()

Object 的 hashCode() 与 equals()

hashCode

public native int hashCode();

原生的 hashCode() 是一个本地方法,返回的是根据物理地址换算出来的一个唯一值。

equals

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

原生的 equals() 比较的是物理地址是否一样。

重写 equals() 的场景

class Student{
    String name;
    String nickName;
    String age;
    //...
}

这里有一个 Student 类,如果我 new 了两个 Student 对象,但它们的属性完全相同。我现在想用 equals() 方法区分它们是不是同一个 Student。

按照 Object 的 equals() 方法的逻辑,它们是不一样的,因为物理地址不同。

但如果按我的逻辑,只要属性一样,就是同一个 Student,如何做到呢?

重写 equals() 方法,我们来看一下用 IDEA 自动生成的 equals()

@Override
public boolean equals(Object o) {
	//如果内存地址相同
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    Student student = (Student) o;
    return Objects.equals(name, student.name) &&
            Objects.equals(nickName, student.nickName) &&
            Objects.equals(age, student.age);
}

其中,

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

可以看到,只要对应属性的物理地址相同或者,equals 就可以了。而这里,属性都是 String 类型的,String 已经重写了 equals。

String 的 equals()

public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = value.length;
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            while (n-- != 0) {
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}

只要2个String的字符串数组里的每个值一样,就 equals。

重写 hashCode() 的场景

在前面重写 equals() 的场景里,完全没看到 hashCode() 的用武之地,那么在什么场景下需要重写它呢?

答案是:与 hash 有关的场景里。如 HashMap。

还是之前的 Student,我现在要统计属性一样的 Student 有多少个。很容易想到,用 HashMap<Student, Integer>。

但是,HashMap 里是这么判断两个 key 是否一样的:

p.hash == hash &&((k = p.key) == key || (key != null && key.equals(k)))

也就是说它们的 hash 值必须一样key的物理地址一样或 equals

已经重写了 equals,&& 右边的条件可以满足。

左边的 hash 值是由 hashCode() 计算来的:

static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

也就是说 hashCode() 不同,hash 就不同,key 就不同。这不是我们想要的。

所以我们需要重写 hashCode(),让属性一样的 Student 的 hashCode() 也一样。看看 IDEA 自动生成的

@Override
public int hashCode() {

    return Objects.hash(name, nickName, age);
}

其中,

public static int hash(Object... values) {
    return Arrays.hashCode(values);
}

其中,

public static int hashCode(Object a[]) {
    if (a == null)
        return 0;

    int result = 1;

    for (Object element : a)
        result = 31 * result + (element == null ? 0 : element.hashCode());

    return result;
}

让每一个属性参与运算并尽量不发生 hash 冲突(属性不同的 Student,hashCode()一样,就是 hash 冲突)。

©️2020 CSDN 皮肤主题: 岁月 设计师: pinMode 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值