问题 从string和int创建哈希


我记得eclipse和idea有这个模板根据其属性自动创建一个对象的hashCode。

如果使用数字和字符串,其中一种策略是这样的。

  return stringValue.hashCode() + intValue * 32;

这样的东西。

我手头没有也没有日食或想法,我想创造这样的功能。

编辑

根据答案,我创建了这个迷你课程

    class StringInt {
        private final String s;
        private final int i;

        static StringInt valueOf( String string , int value ) {
            return new StringInt( string, value );
        }
        private StringInt( String string, int value ) {
            this.s = string;
            this.i = value;
        }
        public boolean equals( Object o ) {
            if( o != null && o instanceof StringInt ){
                StringInt other = ( StringInt ) o;
                return this.s == other.s && this.i == other.i;
            }

            return false;
        }
        public int hashCode() {
            return s != null ? s.hashCode() * 37 + i : i;
        }
    }

这个类将用作大内存映射的键(> 10k元素)我不想每次迭代它们以查找String和int是否相同。

谢谢。

ps .. mmh可能它应该是StringIntKey的名字。


9249
2017-07-30 21:57


起源

奥斯卡,我认为这是一个很好的课程。 hashCode方法清晰,可靠,高效。如何阻止字符串为空?在构造函数中,如果它为null,则抛出NPE。然后你可以删除equals和hashCode中的那些空值守卫。最后,为这些问题保留一份“Effective Java”。 Eclipse和IDEA创建的hashCode方法基于该书。 - Steve McLeod
在你的equals方法中应该比较字符串使用equals而不是==。 - Steve Kuo


答案:


使用Apache Commons HashcodeBuilder:

public int hashCode() {
    new HashCodeBuilder(17, 37).
           append(myString).
           append(myInt);
}

链接在这里: http://commons.apache.org/lang/api-2.3/org/apache/commons/lang/builder/HashCodeBuilder.html

和这里:

http://www.koders.com/java/fidCE4E86F23847AE93909CE105394B668DDB0F491A.aspx


8
2017-07-30 21:59



HashCodeBuilder源代码是否在线? ......我会看看它。 - OscarRyz
它说:string.hashCode * 37 + intValue !!对我来说够多的了 !!谢谢 - OscarRyz


或者,如果您不想添加其他库,请执行以下操作:

public int hashCode() {
    StringBuilder builder = new StringBuilder();
    builder.append(myString);
    builder.append(myInteger);
    return builder.toString().hashCode();
}

3
2017-07-30 22:05



Doh!..有时我想念这种解决方案!是的我不想添加另一个库。感谢您的建议 - OscarRyz
@aperkins:只需编写“return(myString + myInteger).hashCode()”就更简单了。 Java编译器会将此编译为StringBuilder.append调用的等效序列。 - Stephen C
@perkins:另外一件事,如果你真的关心速度,那么这种方法比计算和组合组件哈希码要慢得多。 - Stephen C
hashCode应该很快,采用字符串的hashCode并使用整数进行简单的整数数学运算会好得多。 - Steve Kuo
速度问题可能是正确的,但是在我们编写的代码中,我从未注意到使用此方法的显着减速。通常,我们的性能问题与线传输或算法更改有关。 - aperkins


Eclipse总是执行大致相同的散列函数,这是一个带有in和String as字段的类的示例

    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + this.interger;
        result = prime * result + ((this.string == null) ? 0 : this.string.hashCode());
        return result;
    }

它们总是选择31作为素数,然后通过构建哈希函数或者如果它是原语的值来选择多个。像这样的东西并不难创造出一种方法。

     public int hashCode(Object ... things) {
         final int prime = 31;
         int result = 1;
         for(Object thing : things) {
             result = prime * result + thing.hashCode();
         }
         return result;
     }

3
2017-07-30 22:08





哈希码方法可能被多次调用,因此值得优化。如果计算很复杂,请考虑记住哈希值。此外,避免做一些需要更多计算的事情。 (例如,StringBuilder解决方案花费大部分时间创建临时String。)

我要指出的另一件事是哈希的质量很重要。您希望避免使用映射许多公共密钥的任何哈希码算法。如果发生这种情况,哈希表查找可能不再是O(1)。 (在最坏的情况下,它将是O(N)...即等效于线性搜索!)。这是一个糟糕的哈希函数的例子:

int hashcode() {
    int hash = 1;
    for (int val : this.values) {
        hash = hash * value;
    }
    return hash;
}

考虑如果一个元素会发生什么 this.values 是零......


1
2017-07-31 04:26





除了最近的编辑,如果检索速度比存储问题更重要,您可以在构建时预先计算并存储哈希码 StringInt 类。这是安全的,因为你已经标记了 String 和 int 作为 final,并且也给了它 String 是不可改变的。

此外,你可以优化你的 equals 方法通过检查被比较的对象== this 在进行全面比较之前。我还建议在比较字符串字段之前先进行更便宜的基于int的比较。

另一个最终建议:你可以改变你的 valueOf(String, int) 构造一个的方法 StringInt 或返回先前创建的实例(如果已存在的实例) String 和int值。这使得建筑更加昂贵,但比较非常便宜,因为你可以比较 StringInt在没有两个知识的情况下使用“==” StringInts将永远与之相同 String 和 int 值。


0
2017-07-30 23:14





你也可以使用 Objects 来自 java.util.Objects 包快速获取哈希码。

@Override
public int hashCode() {
    return Objects.hash(this.string, this.integerValue, this.otherDataTypes);
}

0
2018-02-20 10:00