【发布时间】:2020-02-09 02:37:40
【问题描述】:
我正在从一个文件加载网络流量数据。我正在加载的信息是攻击者 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 方法,但如果是这样,那为什么呢?如果这个猜测是错误的,那么这里发生了什么?
【问题讨论】:
-
@Override注释的存在是有充分理由的。用它。 (并且不要重新发明 String 的哈希码,只需调用它即可。)(并且“如果它们的哈希码匹配,则两个对象是相同的”是定义相等性的糟糕方式。) -
你有没有试过打电话给
a.equals(b)看看是不是true? -
@OrestSavchak 在这种情况下可能会提供误报。
-
@Ecko 你在
hashCode()上使用了@Override,而不是equals(Traffic)。我怀疑 chrylis 指的是您没有始终如一地使用它。 -
@Ecko “此外,equals 确实返回 true,我正在努力看看这将如何成为误报”您调用的方法与
HashMap不同。尝试调用a.equals((Object) b)。
标签: java hash hashmap hashcode