简体   繁体   English

奇怪的Java Hashcode(带有Lombok)不确定性行为

[英]Odd Java Hashcode (with Lombok) Non-Deterministic Behavior

I'm getting some behavior that I don't understand with Java Hashcode (using Lombok). 我收到一些Java Hashcode无法理解的行为(使用Lombok)。 I've got an abstract object Storable for things that I'm storing in various DataStores. 我有一个抽象对象Storable,用于存储在各种DataStore中的事物。

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;
    ...
  }

  ...
}

When I new up multiple Foos with new Foo(new URL(" http:///www.foo.com ")) and I iterate over them and check each foo.hashCode() I get the same value. 当我用新的Foo(new URL(“ http:///www.foo.com ”))新建多个Foos并对其进行迭代并检查每个foo.hashCode()时,我会得到相同的值。 But if I terminate the program and then start another run, the foos in the new run have a different hashCode value even though they look identical from a data standpoint. 但是,如果我终止程序然后开始另一次运行,即使从数据的角度来看它们相同,新运行中的foo也具有不同的hashCode值。 The discrepancy is causing me grief because I'm trying to use hashCode to identify unique objects from run to run. 这种差异使我感到悲伤,因为我试图使用hashCode从运行中识别唯一的对象。 Perhaps even more oddly, for a given URL that I'm using for testing I'm seeing 1 of the same 4 integers every time. 也许更奇怪的是,对于我用于测试的给定URL,我每次都看到相同的4个整数之一。

Am I missing something about either Java's default getHashcode() implementation or Lombok's @EqualsAndHashCode implementation? 我是否缺少有关Java的默认getHashcode()实现或Lombok的@EqualsAndHashCode实现的信息? Or is there something about URL that would cause it to have a different hashCode value? 还是关于URL的某些东西会导致它具有不同的hashCode值? Thanks in advance for the help! 先谢谢您的帮助!

If you are using Java 7 this is probably using the alternate murmur hashcode implementation which is not guaranteed to produce the same hashcode across JVM instances (or the same JVM run multiple times) 如果您使用的是Java 7,则可能正在使用备用murmur哈希代码实现,该实现不能保证在JVM实例之间生成相同的哈希代码(或同一JVM运行多次)

Article that discusses the change to hashcode in Java 7 讨论Java 7中对哈希码的更改的文章

Relevant section: 相关部分:

A couple more words about the alternative hash code: 关于备用哈希码的更多信息:

  • it isn't exposed publicly through the String class. 它不会通过String类公开公开。 You can access it using the (unofficial) sun.misc.Hashing.stringHash32 method 您可以使用(非正式)sun.misc.Hashing.stringHash32方法访问它

  • unlike the original hash code, hash32 for two strings containing the same characters but running in different JVMs (on the same machine or on different machines) isn't guaranteed to be the same (in fact most likely it won't be, since a “HASHING_SEED” value is included in the calculation which is initialized on JVM startup using the current time) 与原始哈希码不同,对于包含相同字符但在不同JVM(在同一台计算机或不同计算机上)运行的两个字符串,hash32不能保证是相同的(事实上,很可能不会相同),因为计算中包括“ HASHING_SEED”值,该值在JVM启动时使用当前时间初始化)

  • the purpose of alternative hash code is to give better performance for HashMap and related classes with String keys and to thwart hash-collision denial of service attacks 备用哈希码的目的是通过字符串键为HashMap和相关类提供更好的性能,并阻止哈希冲突拒绝服务攻击

  • Its usage isn't enabled by default. 默认情况下未启用其用法。 You need to set the “jdk.map.althashing.threshold” property to enable it. 您需要设置“ jdk.map.althashing.threshold”属性来启用它。 If you set this to a value X, then HashMap and related classes with a capacity at least X will use the alternative hashing algorithm. 如果将此值设置为X,则HashMap和容量至少为X的相关类将使用备用哈希算法。

A word of caution if you want to enable alternative hashing: prior to Java 7u40 (ie. all versions between Java 7u6 and Java 7u39) had a performance issue which meant that HashMap creation while alternative hashing was enabled was slower than needed to be. 如果要启用替代哈希,请谨慎使用:在Java 7u40之前(即Java 7u6和Java 7u39之间的所有版本)都存在性能问题,这意味着在启用替代哈希的情况下创建HashMap的速度比需要的要慢。 Thus if you want to enable alternative hashing, ensure that you have the latest Java 7 runtime. 因此,如果要启用备用哈希,请确保您具有最新的Java 7运行时。

This was added in Java 7u6 but has been removed in Java 8. 它是在Java 7u6中添加的,但在Java 8中已被删除。

Here's the internal implementation of Java 7's murmur hash function on grep code . 这是Java 7的grep代码杂音哈希函数的内部实现。

Here's the link to Java 7's HashMap implementation that uses the new hash code calculation if the key in the map is a String http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/7u40-b43/java/util/HashMap.java#HashMap.hash%28java.lang.Object%29 这是指向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%

The hash code of an object is not in general required to be deterministic. 通常,不需要对象的哈希码是确定性的。 Only if the documentation of a class explicitly says the hash code is deterministic may you assume it is deterministic. 仅当类的文档明确指出哈希码是确定性的时,您才可以假定它是确定性的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM