HashMap 忽略重写的 hashCode 和 equals 方法

HashMap ignoring overridden hashCode and equals methods

我正在从文件中加载有关网络流量的数据。我正在加载的信息是攻击者 IP 地址、受害者 IP 地址和日期。我已将这些数据合并到一个 Traffic 对象中,并为其定义了 hashCodeequals 函数。尽管如此,我将它们加载到的 HashMap 将相同的 Traffic 对象视为不同的键。 main 方法中包含一些简单测试代码的整个 Traffic 对象如下:

import java.util.HashMap;

public class Traffic {

    public String attacker;
    public String victim;
    public int date;

    //constructors, getters and setters

    @Override
    public int hashCode() {
        long attackerHash = 1;
        for (char c:attacker.toCharArray()) {
            attackerHash = attackerHash * Character.getNumericValue(c) + 17;
        }

        long victimHash = 1;
        for (char c:victim.toCharArray()) {
            victimHash = victimHash * Character.getNumericValue(c) + 17;
        }

        int IPHash = (int)(attackerHash*victimHash % Integer.MAX_VALUE);
        return (IPHash + 7)*(date + 37) + 17;
    }

    public boolean equals(Traffic t) {
        return this.attacker.equals(t.getAttacker()) && this.victim.equals(t.getVictim()) && this.date == t.getDate();
    }

    public static void main(String[] args) {
        Traffic a = new Traffic("209.167.099.071", "172.016.112.100", 7);
        Traffic b = new Traffic("209.167.099.071", "172.016.112.100", 7);
        System.out.println(a.hashCode());
        System.out.println(b.hashCode());

        HashMap<Traffic, Integer> h = new HashMap<Traffic, Integer>();
        h.put(a, new Integer(1));
        h.put(b, new Integer(2));
        System.out.println(h);
    }
}

我无法说明我的散列方法的强度,但前两次打印的输出是相同的,这意味着它至少适用于这种情况。

由于 a 和 b 在数据上相同(因此 equals returns 为真),并且哈希值相同,HashMap 应该将它们识别为相同并更新值从 1 到 2,而不是创建第二个值为 2 的条目。不幸的是,它无法将它们识别为相同,最终打印的输出如下:

{packagename.Traffic@1c051=1, packagename.Traffic@1c051=2}

我最好的猜测是 HashMap 的内部工作忽略了我的自定义 hashCodeequals 方法,但如果是这样,那为什么呢?如果这个猜测是错误的,那么这里发生了什么?

这里的问题是您的 equals 方法没有覆盖 Object#equals。为了证明这一点,以下将 not 使用 @Override 注释编译:

@Override
public boolean equals(Traffic t) {
    return this.attacker.equals(t.getAttacker()) && 
        this.victim.equals(t.getVictim()) && 
        this.date == t.getDate();
}

HashMap 的实现使用 Object#equals 不使用 您的自定义实现。您的 equals 方法应该接受 Object 作为参数:

@Override
public boolean equals(Object o) {
    if (!(o instanceof Traffic)) {
        return false;
    }

    Traffic t = (Traffic) o;

    return Objects.equals(attacker, t.attacker) &&
        Objects.equals(victim, t.victim) &&
        date == t.date;
}