Eclipse生成的hashCode函数好用吗? [英] Is the hashCode function generated by Eclipse any good?

查看:29
本文介绍了Eclipse生成的hashCode函数好用吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Eclipse 源菜单有一个生成 hashCode/equals 方法",它可以生成如下所示的函数.

字符串名称;@覆盖公共 int hashCode(){最终 int 素数 = 31;整数结果 = 1;结果 = 素数 * 结果 + ((name == null) ? 0 : name.hashCode());返回结果;}@覆盖公共布尔等于(对象 obj){如果(这 == 对象)返回真;如果(obj == null)返回假;if (getClass() != obj.getClass())返回假;CompanyRole 其他 = (CompanyRole) obj;如果(名称 == 空){if (other.name != null)返回假;} else if (!name.equals(other.name))返回假;返回真;}

如果我在生成 hashCode()equals() 时选择多个字段,Eclipse 使用上面显示的相同模式.

我不是哈希函数方面的专家,我想知道生成的哈希函数有多好"?什么情况下它会发生故障并导致过多的碰撞?

解决方案

java.util.ArrayList中可以看到hashCode函数的实现

public int hashCode() {int hashCode = 1;迭代器 Ei = 迭代器();而(i.hasNext()){E obj = i.next();hashCode = 31*hashCode + (obj==null ? 0 : obj.hashCode());}返回哈希码;}

这是一个这样的示例,您的 Eclipse 生成的代码遵循类似的实现方式.但是如果你觉得你必须自己实现你的 hashCode,Joshua Bloch 在他的名著 Effective Java.我将发布该书第 9 项中的重要观点.那些是,

<块引用>

  1. 在名为 result 的 int 变量中存储一些常量非零值,例如 17.
  2. 对于对象中的每个重要字段 f(即 equals 方法考虑的每个字段),请执行以下操作:

    一个.计算字段的 int 哈希码 c:

    我.如果该字段是布尔值,则计算 (f ? 1 : 0).

    二.如果字段是 byte、char、short 或 int,则计算 (int) f.

    三.如果字段是长的,则计算 (int) (f ^ (f >>> 32)).

    四.如果该字段是浮点数,则计算 Float.floatToIntBits(f).

    v.如果该字段是双精度,则计算 Double.doubleToLongBits(f),然后像步骤 2.a.iii 中一样对结果进行散列.

    六.如果该字段是一个对象引用,并且此类的 equals 方法通过递归调用 equals 来比较该字段,则在该字段上递归调用 hashCode.如果需要更复杂的比较,请为此字段计算规范表示"并在规范表示上调用 hashCode.如果该字段的值为null,则返回0(或其他一些常量,但0是传统的)

    七.如果该字段是一个数组,则将其视为每个元素都是一个单独的字段.也就是说,通过应用计算每个重要元素的哈希码这些规则递归,并在每个步骤 2.b 中组合这些值.如果每个数组字段中的元素很重要,您可以使用其中一种1.5 版中添加的 Arrays.hashCode 方法.

    b.将步骤 2.a 中计算的哈希码 c 组合成如下结果:

     结果 = 31 * 结果 + c;

  3. 返回结果.

  4. 写完 hashCode 方法后,问问自己是否相等的实例具有相等的哈希码.编写单元测试来验证你的直觉!如果相等的实例具有不相等的哈希码,找出原因并解决问题.

Java 语言设计者和 Eclipse 似乎遵循我想的类似准则.快乐编码.干杯.

Eclipse source menu has a "generate hashCode / equals method" which generates functions like the one below.

String name; 
@Override
public int hashCode()
{
    final int prime = 31;
    int result = 1;
    result = prime * result + ((name == null) ? 0 : name.hashCode());
    return result;
}

@Override
public boolean equals(Object obj)
{
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    CompanyRole other = (CompanyRole) obj;
    if (name == null)
    {
        if (other.name != null)
            return false;
    } else if (!name.equals(other.name))
        return false;
    return true;
}

If I select multiple fields when generating hashCode() and equals() Eclipse uses the same pattern shown above.

I am not an expert on hash functions and I would like to know how "good" the generated hash function is? What are situations where it will break down and cause too many collisions?

解决方案

You can see the implementation of hashCode function in java.util.ArrayList as

public int hashCode() {
    int hashCode = 1;
    Iterator<E> i = iterator();
    while (i.hasNext()) {
        E obj = i.next();
        hashCode = 31*hashCode + (obj==null ? 0 : obj.hashCode());
    }
    return hashCode;
}

It is one such example and your Eclipse generated code follows a similar way of implementing it. But if you feel that you have to implement your hashCode by your own, there are some good guidelines given by Joshua Bloch in his famous book Effective Java. I will post those important points from Item 9 of that book. Those are,

  1. Store some constant nonzero value, say, 17, in an int variable called result.
  2. For each significant field f in your object (each field taken into account by the equals method, that is), do the following:

    a. Compute an int hash code c for the field:

    i. If the field is a boolean, compute (f ? 1 : 0).

    ii. If the field is a byte, char, short, or int, compute (int) f.

    iii. If the field is a long, compute (int) (f ^ (f >>> 32)).

    iv. If the field is a float, compute Float.floatToIntBits(f).

    v. If the field is a double, compute Double.doubleToLongBits(f), and then hash the resulting long as in step 2.a.iii.

    vi. If the field is an object reference and this class’s equals method compares the field by recursively invoking equals, recursively invoke hashCode on the field. If a more complex comparison is required, compute a "canonical representation" for this field and invoke hashCode on the canonical representation. If the value of the field is null, return 0 (or some other constant, but 0 is traditional)

    vii. If the field is an array, treat it as if each element were a separate field. That is, compute a hash code for each significant element by applying these rules recursively, and combine these values per step 2.b. If every element in an array field is significant, you can use one of the Arrays.hashCode methods added in release 1.5.

    b. Combine the hash code c computed in step 2.a into result as follows:

       result = 31 * result + c;
    

  3. Return result.

  4. When you are finished writing the hashCode method, ask yourself whether equal instances have equal hash codes. Write unit tests to verify your intuition! If equal instances have unequal hash codes, figure out why and fix the problem.

Java language designers and Eclipse seem to follow similar guidelines I suppose. Happy coding. Cheers.

这篇关于Eclipse生成的hashCode函数好用吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆