来自字段字符串连接的哈希码与自动生成的方法

时间:2021-04-22 14:36:55

标签: java hash hashmap collision hashcode

如果我们有一个像下面这样的类:

class ConnectedPair {
        private String source;
        private String destination;

        public ConnectedPair(String source, String destination) {
            if(source == null || destination == null) {  
                throw new NullPointerException();
            }
            this.source = source;
            this.destination = destination;
        }
}  

我们想在 HashMapHashSet 中使用它,我们需要实现 equalshashCode
此类的自动生成的 hashCode 是:

@Override
public int hashCode() {
    int result = source.hashCode();
    result = 31 * result + destination.hashCode();
    return result;
}  

但我想知道我们是否做了以下事情:

@Override
public int hashCode() {
    return (source + "=>" + destination).hashCode();
}  

这比自动生成的方法好还是差?正如我所见,在其他脚本语言中也使用了类似的方法,我想知道生成的哈希是好是坏(或者没有区别)。

注意:假设它可以被缓存并因此被优化

1 个答案:

答案 0 :(得分:2)

  1. 如果您只关心有效的实现并且对意外和/或故意碰撞的可能性没有具体要求,那么它们都可以。这是大多数情况:您可以在此处停止调查。
  2. 这两者都受到 String.hashCode() 相当糟糕的定义的影响。由于历史原因,String.hashCode() 对它的工作方式有一个固定的定义,而这个定义是……糟糕的。它很容易发生意外碰撞,并且很容易构建故意碰撞。
  3. 第二个(使用字符串连接)使得构建两个具有相同哈希码 (ConnectedPair) 的 new ConnectedPair("a=>b", "c").hashCode() == new ConnectedPair("a","b=>c").hashCode() 对象非常变得简单。另一个选项并不能完全避免这种情况,但会使构建样本变得稍微困难​​一些。
  4. 这听起来可能很傻,但生成的代码是惯用的:每个看到此代码的 Java 开发人员都会很快理解您在做什么。您的“自定义”实现似乎并没有明显更糟,但需要更多的脑力来解析。请记住:代码的阅读频率远高于编写频率。