简体   繁体   English

HashMap 忽略覆盖的 hashCode 和 equals 方法

[英]HashMap ignoring overridden hashCode and equals methods

I am loading data on network traffic from a file.我正在从文件中加载有关网络流量的数据。 The information I'm loading is attacker IP address, victim IP address, and date.我正在加载的信息是攻击者 IP 地址、受害者 IP 地址和日期。 I've combined these data into a Traffic object, for which I've defined the hashCode and equals functions.我已将这些数据组合成一个Traffic object,为此我定义了hashCodeequals函数。 Despite this, the HashMap I'm loading them into treats identical Traffic objects as different keys.尽管如此,我正在将它们加载到的HashMap将相同的Traffic对象视为不同的键。 The entire Traffic object complete with some simple test code in the main method follows:整个Traffic object在main方法中加上一些简单的测试代码如下:

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);
    }
}

I can't speak to the strength of my hash method, but the outputs of the first two prints are identical, meaning it at least holds for this case.我不能说我的 hash 方法的强度,但前两个打印的输出是相同的,这意味着它至少适用于这种情况。

Since a and b are identical in data (and therefore equals returns true), and the hashes are identical, the HashMap should recognize them as the same and update the value from 1 to 2 instead of creating a second entry with value 2. Unfortunately, it does not recognize them as the same and the output of the final print is the following:由于 a 和 b 的数据相同(因此equals返回 true),并且哈希值相同,因此HashMap应该将它们识别为相同并将值从 1 更新为 2,而不是创建第二个值为 2 的条目。不幸的是,它不认为它们是相同的,最终打印的 output 如下:

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

My best guess at this is that HashMap 's internal workings are ignoring my custom hashCode and equals methods, but if that's the case then why?我对此的最佳猜测是HashMap的内部工作忽略了我的自定义hashCodeequals方法,但如果是这样,那为什么呢? And if that guess is wrong then what is happening here?如果这个猜测是错误的,那么这里发生了什么?

The problem here is your equals method, which does not override Object#equals .这里的问题是您的equals方法,它不会覆盖Object#equals To prove this, the following will not compile with the @Override annotation:为了证明这一点,以下代码不会使用@Override注释进行编译:

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

The implementation of HashMap uses Object#equals and not your custom implementation. HashMap的实现使用Object#equals不是您的自定义实现。 Your equals method should accept an Object as a parameter instead:您的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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM