HashMap键是否可以使用可变对象?解释一下
使用可变对象作为 HashMap
的键是有风险的,但它是允许的。当你使用可变对象作为 HashMap
的键时,必须非常小心,因为对象的状态改变可能会导致它的哈希码变化,进而影响其在 HashMap
中的定位。
风险:
- 如果一个可变对象作为键被插入到
HashMap
,然后它的状态发生了改变(导致其哈希码变化),那么你可能会在HashMap
中找不到该键,或者误删除其他键。 -
这样的操作可能会导致意外的行为,比如
HashMap
包含多个看似相同的键,或者某些键变得不可访问。 -
此外,如果两个对象在插入
HashMap
时具有相同的哈希码但在后续被修改并变得不相等,那么这会导致HashMap
出现意外的行为。
应用场景:
考虑一个简单的例子,你有一个 Person
类,该类有一个属性 name
。你创建了一个 Person
对象并将其作为键插入到 HashMap
。之后,你更改了 Person
对象的 name
属性:
class Person {
String name;
Person(String name) {
this.name = name;
}
@Override
public int hashCode() {
return name.hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Person person = (Person) obj;
return Objects.equals(name, person.name);
}
}
HashMap<Person, String> map = new HashMap<>();
Person person = new Person("Alice");
map.put(person, "Engineer");
person.name = "Bob"; // 修改了作为键的对象
String profession = map.get(person); // 这里可能会返回 null,因为键的哈希码已经改变了
建议:
- 尽量避免使用可变对象作为
HashMap
的键。 -
如果确实需要使用可变对象作为键,确保对象的状态改变不会影响其
hashCode()
和equals()
方法的结果。 -
更好的选择是使用不可变对象作为键,或者在将对象作为键使用之前,先创建其深拷贝并使用该拷贝作为键。
总之,虽然可以使用可变对象作为 HashMap
的键,但这样做需要非常小心,并确保了解相关的风险和限制。