第9条:覆盖equals时总要覆盖hashCode

来源:互联网 发布:ip地址网络字节序 编辑:程序博客网 时间:2024/06/06 12:40

第9条:覆盖equals时总要覆盖hashCode

在每一个覆盖equals方法的类中,都必须覆盖hashCode方法,如果不这么做,会导致这个类无法结合所有基于散列的集合的正常使用,如HashMap,HashSet,Hashtable。

Object规范中有这么一条:

如果两个对象根据equals(Object)方法比较是相等的,那么调用这对象中任意一个对象的hashCode方法都必须产生同样的整数结果。

因为对于两个对象A和B,如果A.equals(B)为true,则代表A与B在逻辑上是相等的,但是Object中的hashcode方法,则是根据对象的内存地址来生成hashcode,这也就会导致两个逻辑上相等的对象的hashcode却是不同的。这在使用基于hashcode的散列表(如HashMap)时会出现问题:

public class PhoneNumber{    private int areaCode;    private int prefix;    private int lineNumber;    public PhoneNumber(int areaCode,int prefix,int lineNumber){        this.areaCode = areaCode;        this.prefix = prefix;        this.lineNumber = lineNumber;    }    @Override    public boolean equals(Object o){        if(o == this){            return this;        }        if(!(o instanceof PhoneNumber)){            return false;        }        PhoneNumber pn = (PhoneNumber)o;        return pn.lineNumber == lineNumber             && pn.prefix == prefix             && pn.areaCode == areaCode;    }}
Map<PhoneNumber, String> m = new HashMap<PhoneNumber, String>();m.put(new PhoneNumber(707, 867, 5309), "Jenny");m.get(new PhoneNumber(707, 867, 5309));    //return null

因为在HashMap中,会先根据传入对象的hashcode找到相应的桶,然后再在桶中寻找相等的对象,换言之如果连两个对象的hashcode都不同,那么也不会去比较这两个对象是否相等。

一个好的hashcode方法将会为不同的对象产生不同的hashcode,在最理想的情况下,应该把集合中所有不相等的对象均匀分布到所有可能的值上。

在hashcode的计算过程中,可以将冗余域(即可以通过参与计算的其它值计算出来的值)排除在外,还有必须排除equals方法中没有的所有值,否则有可能出现两个对象逻辑相等但是生成的不同的状况。

如果一个类中参与hashcode计算的变量都是不可变(final)的,而且hashcode计算的开销又非常大,那么可以在创建这个对象,或第一次使用hashcode时计算这个值,然后将hashcode保存在这个对象内部。

0 0