HashMap игнорирует переопределенный hashCode и методы equals - PullRequest
0 голосов
/ 11 октября 2019

Я загружаю данные о сетевом трафике из файла. Я загружаю информацию об IP-адресе злоумышленника, IP-адресе жертвы и дате. Я объединил эти данные в объект Traffic, для которого я определил функции hashCode и equals. Несмотря на это, HashMap, который я загружаю в них, рассматривает идентичные Traffic объекты как разные ключи. Весь объект Traffic с некоторым простым тестовым кодом в методе 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);
    }
}

Я не могу говорить о силе моего метода хэширования, но выходные данные первых двух отпечатков идентичныЭто означает, что по крайней мере для этого случая.

Поскольку a и b идентичны в данных (и, следовательно, equals возвращает true), а хэши идентичны, HashMap должен распознавать их как одинаковыеи измените значение с 1 на 2 вместо создания второй записи со значением 2. К сожалению, он не распознает их как одинаковые, и вывод окончательного отпечатка следующий:

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

Мой лучшийпредположим, что внутренняя работа HashMap игнорирует мои пользовательские методы hashCode и equals, но если это так, то почему? И если это предположение неверно, то что здесь происходит?

1 Ответ

4 голосов
/ 11 октября 2019

Проблема здесь в вашем equals методе, который не переопределяет Object#equals. Чтобы доказать это, следующее не скомпилируется с аннотацией @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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...