注意可变的 hashCode()

Map 是很好的集合,为我们带来了在其他语言(比如 Perl)中经常可见的好用的键/值对集合。 JDK 以 HashMap 的形式为我们提供了方便的 Map 实现,它在内部使用哈希表实现了对键的对应值的快速查找。 但是这里也有一个小问题:支持哈希码的键依赖于可变字段的内容,这样容易产生 bug,即使最耐心的 Java 开发人员也会被这些 bug 逼疯。

假设清单 3 中的 Person 对象有一个常见的 hashCode() (它使用 firstName、lastName 和 age 字段 — 所有字段都不是 final 字段 — 计算 hashCode() ), 对 Map 的 get() 调用会失败并返回 null

清单 3. 可变 hashCode() 容易出现 bug

 

// Person.java
import java.util.*;

public class Person implements Iterable<Person> {
    public Person(String fn, String ln, int a, Person... kids) {
        this.firstName = fn; this.lastName = ln; this.age = a;
        
        for (Person kid : kids)
            children.add(kid);
    }
    
    // ...
    
    public void setFirstName(String value) { this.firstName = value; }
    public void setLastName(String value) { this.lastName = value; }
    public void setAge(int value) { this.age = value; }
    
    public int hashCode() {
        return firstName.hashCode() & lastName.hashCode() & age;
    }

    // ...

    private String firstName;
    private String lastName;
    private int age;
    private List<Person> children = new ArrayList<Person>();
}


// MissingHash.java
import java.util.*;

public class MissingHash {
    public static void main(String[] args) {
        Person p1 = new Person("Ted", "Neward", 39);
        Person p2 = new Person("Charlotte", "Neward", 38);
        System.out.println(p1.hashCode());
        
        Map<Person, Person> map = new HashMap<Person, Person>();
        map.put(p1, p2);
        
        p1.setLastName("Finkelstein");
        System.out.println(p1.hashCode());
        
        System.out.println(map.get(p1));
    }
}


很显然,这种方法很糟糕,但是解决方法也很简单:永远不要将可变对象类型用作 HashMap 中的键。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值