简体   繁体   中英

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. I've combined these data into a Traffic object, for which I've defined the hashCode and equals functions. Despite this, the HashMap I'm loading them into treats identical Traffic objects as different keys. The entire Traffic object complete with some simple test code in the main method follows:

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.

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:

{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? And if that guess is wrong then what is happening here?

The problem here is your equals method, which does not override Object#equals . To prove this, the following will not compile with the @Override annotation:

@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. Your equals method should accept an Object as a parameter instead:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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