HashMap键是否可以使用可变对象?解释一下

使用可变对象作为 HashMap 的键是有风险的,但它是允许的。当你使用可变对象作为 HashMap 的键时,必须非常小心,因为对象的状态改变可能会导致它的哈希码变化,进而影响其在 HashMap 中的定位。

风险

  1. 如果一个可变对象作为键被插入到 HashMap,然后它的状态发生了改变(导致其哈希码变化),那么你可能会在 HashMap 中找不到该键,或者误删除其他键。

  2. 这样的操作可能会导致意外的行为,比如 HashMap 包含多个看似相同的键,或者某些键变得不可访问。

  3. 此外,如果两个对象在插入 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,因为键的哈希码已经改变了

建议

  1. 尽量避免使用可变对象作为 HashMap 的键。

  2. 如果确实需要使用可变对象作为键,确保对象的状态改变不会影响其 hashCode()equals() 方法的结果。

  3. 更好的选择是使用不可变对象作为键,或者在将对象作为键使用之前,先创建其深拷贝并使用该拷贝作为键。

总之,虽然可以使用可变对象作为 HashMap 的键,但这样做需要非常小心,并确保了解相关的风险和限制。

发表评论

后才能评论