java – 提供相同hashCode的两个不同的Class实例

我在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

我通常不会在意,但是我们正在使用一个框架,它使用由类和属性名称的哈希码构成的密钥来缓存设置器.这是缓存的一个坏设计,但目前无法控制(OGNL 3.0.6在最新的Struts 2.3.24,请参阅source.一个较新的OGNL修复了这个问题,但直到2.5,Struts将不会在目前在beta.)

这个问题让我有些奇怪

>问题出现在使用几天后,我很确定在这段时间内,类/属性都被缓存.这使我相信类实例哈希码实际上正在改变…他们在几天后变得平等.
>我们已经观察到一个非常过时的Hotspot 1.6的行为,现在在1.7.0_80.两者都是Sun Sparc上的32位构建
> JVM报告-XX:hashCode为“0”

我读到,HotSpot中的RNG哈希码生成器(“0”策略)可以产生重复的,如果有赛车线程,但我无法想象类加载触发该行为.

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

解决方法

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

相关文章

最近看了一下学习资料,感觉进制转换其实还是挺有意思的,尤...
/*HashSet 基本操作 * --set:元素是无序的,存入和取出顺序不...
/*list 基本操作 * * List a=new List(); * 增 * a.add(inde...
/* * 内部类 * */ 1 class OutClass{ 2 //定义外部类的成员变...
集合的操作Iterator、Collection、Set和HashSet关系Iterator...
接口中常量的修饰关键字:public,static,final(常量)函数...