`
dingjob
  • 浏览: 183294 次
  • 性别: 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

 

 

 

分享到:
评论

相关推荐

    Effective Java第三版1

    2. **hashCode方法**:当覆写`equals`时,必须同时覆写`hashCode`,以保持哈希表的正确性。 3. **toString方法**:为每个类提供一个有意义的字符串表示,方便调试和日志记录。 4. **clone方法**:`clone`方法的覆写...

    effective java 读书笔记

    - Item9:当覆盖equals时,必须同时覆盖hashcode,以保持哈希表的行为一致性。 - Item10:toString方法应返回对象状态的简洁表示,便于调试和日志记录。 - Item11:谨慎覆盖clone方法,因为它涉及到对象的深拷贝...

    java优秀源码-Effective-Java-Concepts:Java源代码可以强化概念,我正在从JoshuaBloch的出色著作“Eff

    3. **方法覆盖和重载**:Item 26 "优先考虑使用泛型方法" 提示我们如何通过泛型提高方法的通用性,而Item 27 "避免在重写方法中抛出新异常或不抛出异常" 关注的是多态性的正确实现。 4. **异常处理**:Item 36 "尽...

    java effective 第二版中英文二份文件

    15. **覆盖equals()时,也应覆盖hashCode()**:这样可以确保对象在哈希表(如HashMap)中的正确行为。 以上只是《Effective Java》第二版部分关键知识点的概述,实际上,书籍中还包含更多关于类设计、方法设计、多...

    Effictive Java

    - 在覆盖`equals`方法的同时覆盖`hashCode`方法。 - 两个根据`equals`方法相等的对象必须具有相同的哈希码。 ##### Item9:始终覆盖`toString` - **目的**:提高调试和日志记录的便利性。 - **实现方式**: - ...

    Java核心技术(1).pdf

    - **项04:始终覆盖hashCode**:当重写了equals方法时,必须同时重写hashCode方法以保持一致性。 - **项05:谨慎覆盖finalize**:finalize方法主要用于执行资源清理工作,但其效率低下且不可预测,应尽量避免使用。 ...

    effective-java:阅读《有效的Java》一书

    《有效的Java》是Java开发领域的一本经典著作,由Joshua Bloch撰写,它为Java程序员提供了一系列实用的编程准则和最佳实践。本书的核心理念是提高代码质量、可读性和可维护性,通过一系列条目介绍了如何编写更高效、...

    java代码规范

    8. ** equals() 和 hashCode()**:如果重写了`equals()`方法,一定要同时重写`hashCode()`以保持一致性。 9. **代码风格**:遵循一定的代码风格,例如Google的Java编程风格指南,它规定了如何处理导入、空格、注释...

Global site tag (gtag.js) - Google Analytics