【发布时间】:2016-12-12 22:26:12
【问题描述】:
我正在努力为下面给出的 Student 类编写正确的 hashCode 函数。
1) 我认为 hashCode 应该足够好,以至于两个不同对象的 hashCode 不应该相互碰撞。
观察:对于这个实现,当我调试并检查“HashMap 的内部表对象”类时,我发现 HashMap 中的每个条目都分配了不同的存储桶位置。
问题:在每个索引处都有一个桶(列表/树)的目的是什么。
实施:
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + id;
return result;
}
2) 如果我允许 hashCode 冲突:
观察:对于这个实现,当我调试和检查时,发现“hashMap 内部表的大小”不断增加,并且只有在 hashCode 范围内的桶被使用。其余存储桶索引显示为空。
问题:如果超出 hashCode 范围的存储桶始终为空,增加内部表大小的目的是什么。
实施:
@Override
public int hashCode() {
return id%20;
}
需要帮助以正确实现 hashCode,以便可以修复上述问题。 提前感谢您的帮助。
============================代码================== =========
public class HashMapTest {
public static void main(String a[]) {
HashMap<Student, Integer> set = new HashMap<Student, Integer>();
for (int i = 0; i < 5000; i++) {
set.put(new Student(i), i);
}
set.put(new Student(5001), 5001);
System.out.println(set.size());
}
}
class Student {
private int id;
public Student(int id) {
this.id = id;
}
// Add here hashCode() provided in comments.
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if (id != other.id)
return false;
return true;
}
}
【问题讨论】:
-
假设学生由
id唯一标识,只需直接使用id作为您的哈希码。没必要弄坏它。如果您想了解更多关于HashMap内部的信息,网上有很多文章描述了哈希映射的工作原理,例如请参阅有关 Hash table (相同事物,不同名称) 的维基百科文章。 -
> "如果我允许 hashCode 冲突"。通常,无论散列函数如何,散列码冲突都是不可避免的。 Java 中的哈希码是一个整数,因此允许大约 2^32 个不同的值。生成 2^32 + 1 个不同的 Java 对象(例如 Longs)是微不足道的,因此可以保证至少发生一次冲突。话虽如此,您确实希望尽可能减少碰撞的可能性,@Andreas 的建议非常有意义。