gpt4 book ai didi

java - 两个不同的 Class 实例给出相同的 hashCode

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:59:53 25 4
gpt4 key购买 nike

我在 JBoss 服务器上遇到一个奇怪的问题,其中两个类生成相同的 hashCode()

Class<?> cl1 = Class.forName("fqn.Class1");
Class<?> cl2 = Class.forName("fqn.Class2");
out.println(cl1.getCanonicalName());
out.println(cl2.getCanonicalName());
out.println(cl1.hashCode());
out.println(cl2.hashCode());
out.println(System.identityHashCode(cl1));
out.println(System.identityHashCode(cl2));
out.println(cl1 == cl2);
out.println(cl1.equals(cl2));
out.println(cl1.getClassLoader().equals(cl2.getClassLoader()));

产生:

fnq.Class1
fnq.Class2
494722
494722
494722
494722
false
false
true

我通常不会在意,但我们正在使用一个框架,该框架使用由类的哈希码和属性名称组成的键来缓存 setter。这是一个糟糕的缓存设计,但目前它超出了我的控制范围(最新的 Struts 2.3.24 中的 OGNL 3.0.6,请参阅 source 。更新的 OGNL 解决了这个问题,但它不会在 Struts 中直到 2.5 ,目前处于测试阶段。)

让我觉得这个问题有点奇怪的是

  • 使用几天后出现问题...我很确定这两个类/属性在这段时间内都被缓存了。这让我相信类实例哈希码实际上正在改变...几天后它们变得相等。
  • 我们已经在非常过时的 Hotspot 1.6 和现在的 1.7.0_80 中观察到了这种行为。两者都是基于 Sun Sparc 的 32 位版本
  • JVM 报告 -XX:hashCode 为“0”

我读到 Hotspot 中的 RNG 哈希码生成器(“0”策略)可以在线程竞争时生成重复项,但我无法想象类加载会触发该行为。

Hotspot 在创建 Class 实例时是否使用特殊的哈希码处理?

最佳答案

  1. java.lang.Class 不会覆盖 hashCode,JVM 也不会以某种方式特殊处理它。这只是从 java.lang.Object 继承的常规身份 hashCode。
  2. -XX:hashCode=0(JDK 6 和 JDK 7 中的默认值)时,使用全局 Park-Miller 随机数生成器计算身份 hashCode。该算法生成周期为 2^31-2 的唯一整数,因此除了以下原因外,两个对象几乎不可能具有相同的 hashCode。
  3. 由于该算法依赖于非同步的全局变量,因此确实存在两个不同线程由于竞争条件而生成相同随机数的可能性(the source) .这显然是您的情况。
  4. Identity hashCode 不是在创建对象时生成的,而是在第一次调用hashCode 方法时生成的。因此,何时以及如何加载类并不重要。如果同时调用 hashCode,则任何两个对象都可能发生此问题。
  5. 我建议使用 -XX:hashCode=5(JDK 8 中的默认值)。此选项使用线程本地 Xorshift RNG。它不受竞争条件的限制,也比 Park-Miller 算法更快。

关于java - 两个不同的 Class 实例给出相同的 hashCode,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32344176/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com