java hashmap 键为自定义类时,必须同时重写 equals() 和 hashcode() 方法。仅实现其中一个会导致哈希冲突无法正确解决或逻辑判断失效,从而引发数据丢失或查询错误。

为什么必须同时重写这两个方法
HashMap 基于哈希表实现,查找元素时先通过 hashCode() 确定桶位置,再通过 equals() 比较键是否相等。如果只重写 equals() 而不重写 hashCode(),两个逻辑上相等的对象可能拥有不同的哈希码,导致它们被放入不同的桶中,使得 get() 永远找不到值。

import java.util.HashMap;
import java.util.Map;
class Key {
private String name;
public Key(String name) { this.name = name; }
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Key)) return false;
Key key = (Key) o;
return name != null ? name.equals(key.name) : key.name == null;
}
@Override
public int hashCode() {
return name != null ? name.hashCode() : 0;
}
}
public class Main {
public static void main(String[] args) {
Map<Key, String> map = new HashMap<>;
Key k1 = new Key("test");
Key k2 = new Key("test");
map.put(k1, "value");
System.out.println(map.get(k2)); // 输出 value
}
}
如何保证哈希一致性
在重写 hashCode() 时,应使用所有参与 equals() 比较的字段。如果对象在作为键期间状态发生改变,且该改变影响了哈希码,将导致对象无法从 Map 中取出。因此,用作键的对象最好是不可变的,或者确保其状态在存入 Map 后不再变化。
立即学习“Java免费学习笔记(深入)”;

import java.util.Objects;
import java.util.HashMap;
import java.util.Map;
class SafeKey {
private final String id;
public SafeKey(String id) { this.id = id; }
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof SafeKey)) return false;
SafeKey safeKey = (SafeKey) o;
return Objects.equals(id, safeKey.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
}
public class Main {
public static void main(String[] args) {
Map<SafeKey, Integer> map = new HashMap<>;
SafeKey k = new SafeKey("123");
map.put(k, 100);
System.out.println(map.get(new SafeKey("123"))); // 输出 100
}
}
可变键导致的潜在问题
如果自定义类的字段是可变的,且在对象放入 HashMap 后修改了这些字段,对象的哈希码会发生变化。此时,即使调用 remove() 或 get(),由于哈希码与存入时不一致,Map 也无法定位到该对象,造成内存泄漏或数据访问失败。


















