代码之家  ›  专栏  ›  技术社区  ›  InsertNickHere

来自一个字段的Java哈希代码

  •  5
  • InsertNickHere  · 技术社区  · 14 年前

    编辑:准备在HashMap中使用的对象。

    在读了一些关于如何生成哈希代码的内容之后,我现在有点困惑了。我的问题是,当我有一个字段可以使用时,我应该如何实现hashCode方法?我能直接用这个吗?

    3 回复  |  直到 12 年前
        1
  •  16
  •   polygenelubricants    14 年前

    如果您的对象是可变的,那么可以接受它的哈希代码随着时间的推移而改变。当然,您应该更喜欢不可变对象( 有效Java第2版,第15项:最小化可变性

    这是乔希·布洛赫的哈希代码配方,来自 有效Java第2版,第9项:始终覆盖 hashCode equals

    有效的Java第二版哈希代码配方

    • 存储一些非零值,比如17,在一个 int result .
    • 计算 哈希码 c
      • 如果字段是 boolean ,计算 (f ? 1 : 0)
      • 如果字段是 byte, char, short, int ,计算 (int) f
      • long (int) (f ^ (f >>> 32))
      • 如果字段是 float Float.floatToIntBits(f)
      • double ,计算 Double.doubleToLongBits(f) ,然后散列结果 长的
      • 如果该字段是对象引用且该类 方法通过递归调用 ,递归调用 哈希码 在球场上。如果字段的值为 null ,返回0。
      • Arrays.hashCode 在版本1.5中添加的方法。
    • 合并哈希代码 结果 具体如下: result = 31 * result + c;

    即使只有一个字段,照着配方来做也是正确的。只需根据字段的类型执行适当的操作。

    HashCodeBuilder Apache Commons Lang ,或者只是 Arrays.hashCode/deepHashCode java.util.Arrays

    这些库允许您简单地编写如下内容:

    @Override public int hashCode() {
        return Arrays.hashCode(new Object[] {
            field1, field2, field3, //...
        });
    }
    

    Apache Commons语言示例

    下面是一个更完整的示例,使用apachecommons Lang中的构建器来简化一个方便且可读的 , 哈希码 , toString compareTo :

    import org.apache.commons.lang.builder.*;
    
    public class CustomType implements Comparable<CustomType> {
        // constructors, etc
        // let's say that the "significant" fields are field1, field2, field3
        @Override public String toString() {
            return new ToStringBuilder(this)
                .append("field1", field1)
                .append("field2", field2)
                .append("field3", field3)
                    .toString();
        }
        @Override public boolean equals(Object o) {
            if (o == this) { return true; }
            if (!(o instanceof CustomType)) { return false; }
            CustomType other = (CustomType) o;
            return new EqualsBuilder()
                .append(this.field1, other.field1)
                .append(this.field2, other.field2)
                .append(this.field3, other.field3)
                    .isEquals();
        }
        @Override public int hashCode() {
            return new HashCodeBuilder(17, 37)
                .append(field1)
                .append(field2)
                .append(field3)
                    .toHashCode();
        }
        @Override public int compareTo(CustomType other) {
            return new CompareToBuilder()
                .append(this.field1, other.field1)
                .append(this.field2, other.field2)
                .append(this.field3, other.field3)
                    .toComparison();
        }
    }
    

    众所周知,这四种方法的编写非常繁琐,而且很难确保所有契约都得到遵守,但幸运的是,库至少可以帮助简化这项工作。一些ide(例如Eclipse)也可以自动为您生成其中的一些方法。

    另请参见

        2
  •  2
  •   Peter Lawrey    14 年前

    如果您希望具有不同id的对象由该id标识,那么您所需要做的就是返回/比较它。

    private final int id;
    
    public int hashCode() { return id; }
    
    public boolean equals(Object o) { 
        return o instanceof ThisClass && id == ((ThisClass)o).id;
    }
    
        3
  •  1
  •   卢声远 Shengyuan Lu    14 年前

    但和你一起工作很重要 . 如果A等于B,则它们的哈希码必须相同。