【问题标题】:Java.util.ArrayList hashCode is returning not so random values on a Storm topologyJava.util.ArrayList hashCode 在 Storm 拓扑上返回的值不是那么随机
【发布时间】:2014-08-23 03:58:45
【问题描述】:

我遇到了一个为 ArrayList 返回的 hashCode 的奇怪问题。下面是修改后的 tuple.clj(来自 Apache Storm 源代码)。传递给 list-hash-code 的列表是一个字符串列表。返回的哈希码使得 (returned-has-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)))

【问题讨论】:

    标签: java clojure apache-storm


    【解决方案1】:

    Java ArrayListhashcode 的实现根本不是“随机的”。

    它实际上是使用Java List API 中指定的算法,以可预测的方式组合元素哈希码;见this javadoc。如果列表的元素具有可预测的顺序和可预测的哈希码,则列表哈希码是可预测的。

    算法是这样的(在 Java 中):

     int hashCode = 1;
     for (E e : list)
         hashCode = 31 * hashCode + (e == null ? 0 : e.hashCode());
    

    是否有办法检查 Clojure 中的 Java 类方法的详细信息和方法?

    Java 源代码和 javadocs 是免费提供的。

    但是,不支持从 Clojure 中检查“方法详细信息”...假设您感兴趣的“方法详细信息”是算法。 (事实上​​,Java 程序也不支持它!)我想,您可以通过编程方式查找字节码并调用一些应用程序来反汇编或反编译它们。但是没有什么意义......因为java.util.*的真正源代码包含在每个Oracle JDK安装程序中。

    【讨论】:

    • 感谢 Stephen C。但我面临的问题是,当从 Storm 拓扑调用“list-hash-code”时,返回值是这样的“(mod the-returned-hash 6)" 总是 4。因此,下一步中的任务 4 总是在处理数据。有没有办法打印方法的字节码以及加载类的包位置?
    • 您认为通过打印加载的字节码以及从何处加载它们将实现什么?据我所知,hashcode 方法的行为与指定的行为方式相同!
    • 那我看看有没有被篡改过。基本上,我想查看 hashCode 源。使用 Java 和 Eclipse,这很容易。我只是在 hashCode 调用行或该方法中打断,然后进入,我看到了 hashCode 的源代码。但我的困难是,这里是 Clojure 调用 java,事情不是那么容易,不能从 Eclipse 做很多事情。
    • 如果您甚至怀疑您的 Java 安装已被篡改,只需重新安装即可。但这听起来像是在浪费时间。正如我所说,哈希码的行为与其应有的行为相同。以相同顺序包含相同元素的列表具有相同的哈希码。这就是类的设计工作方式
    • 谢谢。我会试试你的建议。传递给 list-hash-code 的列表通常具有随机(UUID 字符串)。
    【解决方案2】:

    如果您调用 .getClass .getCanonicalName,您将获得实现正在使用的 List 的类的全名。 Oracle JDK 中默认 AbstractList 的哈希码包含在 Stephen C. 的答案中。如果这就是所使用的来源,那么如果字符串不同,则不会出现这种异常的特殊原因,但这取决于您的数据。

    请注意,hashCode() 根本不保证是均匀分布的。只要 equals() 函数区分类的不同实例,就可以让 hashCode() 为类的所有实例返回 1。那是因为 hashCode 代表“弱相等”,相等的对象必须具有相同的 hashCode(例如被 HashMap 正确找到),但反之则不然。这意味着您可以将 hashCode 修改为其他内容,例如 List,hashCode 乘以素数,只要您的函数从旧 hashcode 到新 hashcode 将相同的输入映射到相同的输出(无随机元素)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-04-16
      • 2019-08-04
      • 2016-08-30
      • 2019-05-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多