`
dingjob
  • 浏览: 181063 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

《Effective Java》阅读体会之三--通用方法(覆盖equals必须覆盖hashCode)

阅读更多

JSL规定,调用两个Equals的对象,其hashCode必须相等。

 

假如我们没有覆盖hashCode,则在和集合类对象HashMap、HashSet、和HashTable一起使用时,会出现问题。例子所示:

 

public class Money {
    private BigDecimal ammount;
    private String unit;

    public Money(BigDecimal ammount, String unit){
        this.ammount= ammount;
        this.unit = unit;
    }

    public BigDecimal getAmmount() {
        return ammount;
    }

    public void setAmmount(BigDecimal ammount) {
        this.ammount = ammount;
    }

    public String getUnit() {
        return unit;
    }

    public void setUnit(String unit) {
        this.unit = unit;
    }
    @Override
    public boolean equals(Object o) {
        if (!(o instanceof Money)) {
            return false;
        }
        Money m = (Money) o;
        return (ammount == null) || ammount.equals(m.getAmmount()) && (unit == null) || unit.equals(m.getUnit());
    }
}

 在执行如下测试方法时会发现,print的结果为null

  public static void main(String[] args) {
        Map m = new HashMap();
        m.put(new Money(new BigDecimal(10),"CNY"), 1);
        System.out.println(m.get(new Money(new BigDecimal(10),"CNY")));
    }

 

这是因为在Map的get方法中,调用了key的hashCode,如下:

 

 public V get(Object key) {
        if (key == null)
            return getForNullKey();
        int hash = hash(key.hashCode());
        for (Entry<K,V> e = table[indexFor(hash, table.length)];
             e != null;
             e = e.next) {
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
                return e.value;
        }
        return null;
    }

 不覆盖的情况下会直接用object的hashCode,不会产生正确结果。即hash算法把对象放在一个散列桶里,而get方法却从另一个散列桶取值。

 

如果在Money类里加上如下散列方法:

 

@Override
    public int hashCode() {
        int h=17;
        h= 31*h+ ammount.hashCode();
        h= 31*h+ unit.hashCode();
        return h;
    }

 

 

运行test,则可以得到正确结果:1

 

至于为什么使用这种hash散列,这里借鉴了经典hash算法的规则,有一点需要强调,能够运用JVM直接完成的算法(移位等)则要使用这些能够提高速度的方法。*31正是运用了新JVM的特性  他可以转换为  (i<<5)-i

 

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics