根据我所读到的,
要使用对象作为 hashMap 的键,它必须提供正确的覆盖和实现equals和hashCode 方法。HashMap get(Key k) 方法调用键对象上的 hashCode 方法,并将返回的hashValue 应用到它自己的静态哈希函数中,以找到一个存储桶位置(后备数组),其中键和值以嵌套类的形式存储,称为 Entry (Map.入口)。HashMap 的内部散列方法可以抵御低质量的散列函数。
为了测试这些契约,我编写了一个 bean 类,其中包含不正确但合法的equals和hashCode方法实现。
班上:
public class HashVO {
private String studentName;
private int age;
private boolean isAdult;
public HashVO(String studentName, int age, boolean isAdult) {
super();
this.studentName = studentName;
this.age = age;
this.isAdult = isAdult;
}
public String getStudentName() {
return studentName;
}
public void setStudentName(String studentName) {
this.studentName = studentName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public boolean isAdult() {
return isAdult;
}
public void setAdult(boolean isAdult) {
this.isAdult = isAdult;
}
@Override
public String toString() {
return studentName + " : " + age + " : " + isAdult;
}
@Override
public boolean equals(Object obj) {
return false;
}
@Override
public int hashCode() {
return 31;
}
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,HashMap的hash方法,
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
Run Code Online (Sandbox Code Playgroud)
也应该每次都返回相同的值,因为哈希码总是返回 31。所以如果类 HashVO 的对象被用作 hashMap 的键,那么 get 方法应该不起作用,因为它应该去同一个桶来检索对象和 equals 方法始终返回 false,因此它将无法找到关键对象的匹配项。
但是当我使用这种方法时,
public static void main(String[] args) {
HashMap<HashVO, String> voMap = new HashMap<HashVO, String>();
HashVO vo = new HashVO("Item1", 25, true);
HashVO vo1 = new HashVO("Item2", 12, false);
HashVO vo2 = new HashVO("Item3", 1, false);
voMap.put(vo, "Item");
voMap.put(vo1, "Item1");
voMap.put(vo2, "Item2");
System.out.println(voMap.get(vo));
System.out.println(voMap.get(vo1));
System.out.println(voMap.get(vo2));
}
Run Code Online (Sandbox Code Playgroud)
输出是正确的,并显示
Item
Item1
Item2
Run Code Online (Sandbox Code Playgroud)
我想了解为什么即使 Equals 和 HashCode 方法实现不正确,也会出现这个正确的输出。
HashMap在使用之前比较对象引用有一个小技巧equals。由于您使用相同的对象引用来添加元素和检索它们,因此HashMap将正确返回它们。
在此处查看 Java 7 源代码(Java 8HashMap对它进行了相当大的改造,但它也做了类似的事情)
final Entry<K,V> getEntry(Object key) {
if (size == 0) {
return null;
}
int hash = (key == null) ? 0 : hash(key);
for (Entry<K,V> e = table[indexFor(hash, table.length)];
e != null;
e = e.next) {
Object k;
// HERE. Uses == with the key
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
}
return null;
}
Run Code Online (Sandbox Code Playgroud)
请注意,这不是文档的一部分,所以不要依赖它。
| 归档时间: |
|
| 查看次数: |
1617 次 |
| 最近记录: |