奇怪的Java Hashcode(使用Lombok)非确定性行为

时间:2015-07-21 02:10:20

标签: java hashcode lombok

我得到了一些我不了解Java Hashcode(使用Lombok)的行为。我有一个抽象的对象可存储在我存储在各种数据存储中的东西。

public abstract class Storable implements Serializable {
  ...
}

@Data
@EqualsAndHashCode(of="url", callSuper=false)
@Slf4j
@ToString(of="url")
public final class Foo extends Storable {

  private URL url;

  public Foo(@NonNull URL url, ...) {

    super();
    this.url = url;
    ...
  }

  ...
}

当我使用新的Foo(新的URL(" http:///www.foo.com"))新建多个Foos时,我迭代它们并检查每个foo.hashCode()我得到相同的值。但是如果我终止程序然后开始另一次运行,新运行中的foos具有不同的hashCode值,即使它们从数据的角度看起来相同。这种差异让我感到悲伤,因为我试图使用hashCode来识别从运行到运行的唯一对象。或许更奇怪的是,对于我用于测试的给定URL,我每次都会看到相同的4个整数中的1个。

我是否遗漏了Java默认的getHashcode()实现或Lombok的@EqualsAndHashCode实现?或者有什么关于URL会导致它具有不同的hashCode值?在此先感谢您的帮助!

2 个答案:

答案 0 :(得分:3)

如果您使用的是Java 7,则可能使用备用murmur哈希码实现,但不保证在JVM实例(或同一JVM多次运行)中生成相同的哈希码

Article that discusses the change to hashcode in Java 7

相关部分:

  

关于替代哈希码的几句话:

     
      
  • 它不会通过String类公开公开。您可以使用(非官方)sun.misc.Hashing.stringHash32方法

  • 访问它   
  • 与原始哈希码不同,hash32对于包含相同字符但在不同JVM中运行的两个字符串(在同一台机器上或在不同的机器上)并不保证是相同的(实际上很可能它赢了)是的,因为在使用当前时间在JVM启动时初始化的计算中包含“HASHING_SEED”值

  •   
  • 替代哈希代码的目的是使用String键为HashMap和相关类提供更好的性能,并阻止哈希冲突拒绝服务攻击

  •   
  • 默认情况下不启用其用法。您需要设置“jdk.map.althashing.threshold”属性才能启用它。如果将其设置为值X,则HashMap和容量至少为X的相关类将使用备用哈希算法。

  •   
     

如果你想要启用替代哈希,请注意:在Java 7u40之前(即Java 7u6和Java 7u39之间的所有版本)都存在性能问题,这意味着在启用备用哈希时创建HashMap的速度比需要的要快是。因此,如果要启用备用散列,请确保拥有最新的Java 7运行时。

这是在Java 7u6中添加的,但已在Java 8中删除。

这是Java 7的杂音哈希函数 on grep code的内部实现。

这里是Java 7的HashMap实现的链接,如果地图中的键是字符串http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/7u40-b43/java/util/HashMap.java#HashMap.hash%28java.lang.Object%29

,则使用新的哈希码计算

答案 1 :(得分:2)

对象的哈希码通常不需要是确定性的。只有当类明确的文档表明哈希码是确定性的时,才可以认为它是确定性的。