我面临一个奇怪的问题,即为ArrayList返回的hashCode。下面是修改过的tuple.clj(来自Apache Storm源码)。传递给list-hash-code的列表是一个字符串列表。返回的哈希码使得(返回的代码%6)总是为4。 “(mod(.hashCode alist)6)”总是4.我真的很困惑可能会出错。由于这个问题,下一个螺栓任务的元组分布不正确。我对这里可能出现的问题一无所知。同样的问题我没有看到我从clojure REPL运行的东西。
我怎么知道正在使用哪个hashCode函数?无论如何都要检查Clojure的方法细节和Java类方法?
(ns backtype.storm.tuple
(:use [backtype.storm bootstrap])
)
(bootstrap)
(defn- print-comma-list [^List els ]
(let [ret (StringBuilder. ) ]
(do
(loop [iter (.iterator els) ]
(when (.hasNext iter)
(.append (.append ret (.next iter)) ",")
(recur iter))))
(.toString ret)))
(defn list-hash-code [^List alist comp-id group-id ]
(do
(if ( and (= comp-id "test1-bolt") ( = group-id "field1,"))
(log-message "Hashcode returned: " (.hashCode alist) " mod val " (mod (.hashCode alist) 6) " " (print-comma-list alist)))
(.hashCode alist)))
答案 0 :(得分:3)
Java hashcode
的{{1}}实现完全没有"随机"。
它实际上是在Java ArrayList
API中使用指定的算法,它以可预测的方式组合元素哈希码;见this javadoc。如果列表的元素具有可预测的顺序和可预测的哈希码,则列表哈希码是可预测的。
算法是这样的(在Java中):
List
有没有检查Clojure的方法细节和Java类方法?
Java源代码和javadocs是免费提供的。
然而,检查"方法细节"不支持来自Clojure ...假设"方法详细说明"你感兴趣的是算法。 (实际上,它也不支持Java程序!)我想,你可以以编程方式查找字节码并调用某些应用程序来反汇编或反编译它们。但是没有太多意义......鉴于 int hashCode = 1;
for (E e : list)
hashCode = 31 * hashCode + (e == null ? 0 : e.hashCode());
的真正源代码包含在每个Oracle JDK安装程序中。
答案 1 :(得分:1)
如果调用.getClass .getCanonicalName,您将获得实现正在使用的List的类的全名。 Oracle JDK中默认AbstractList的Hashcode包含在Stephen C.的答案中。如果这是使用的源,如果字符串不同,那么这种异常就没有特别的原因,尽管它取决于你的数据。
请注意,hashCode()根本不保证均匀分布。只要equals()函数区分类的不同实例,hashCode()为类的所有实例返回1是正确的。这是因为hashCode表示'弱相等',相等的对象必须具有相同的hashCode(例如,由HashMap正确找到),但反之则不然。这意味着您可以将hashCode修改为其他内容,例如List,hashCode乘以素数,只要您的函数从旧的hashcode到新的hashcode将相同的输入映射到相同的输出(无随机元素)。