【问题标题】:How to deep copy a hasher in Java如何在 Java 中深度复制哈希器
【发布时间】:2018-10-08 13:34:00
【问题描述】:

我想在 Java 中散列大量 int[]。我的数组包含从根到树中节点的路径(节点已编号),因此它们在第一个值上非常相似(因为所有路径都来自根)。

我正在使用Google Guava Hasher,我将数组的每个值添加到哈希器以获取 hashCode:

HashFunction hashFunction = Hashing.murmur3_128();
Hasher hasher = hashFunction.newHasher();
for (int i: myArray) {
    hasher.putInt(i);
}
int hashCode = inthasher.hash().asInt();

我想避免为每个路径再次散列整个数组,并且只通过将最后一个值添加到我的散列器副本来散列最后一个值。像这样:

anotherHasher = hasher.clone();
anotherHasher.putInt(someInt);
int hashCode = hasher.hash().asInt();
int anotherHashCode = anotherHasher.hash().asInt();

但是Hasher不存在克隆方法。

这种复制会节省计算时间吗?是否可以使用包含Hasher 的包装器来实现Cloneable,即使后者不可克隆?如果是怎么办?还有其他方法吗?

编辑: 根据记录,使用 Guava 进行散列需要花费时间的不是使用 hasher.putInt(someInt) 添加元素,而是在末尾使用 hasher.hash() 调用散列本身。因此,即使深度复制也很快(不是,请参阅 Tomasz Linkowski 的回答),我的方法不相关,不值得进一步研究。

【问题讨论】:

  • 我认为不支持clone方法,因为很难确定Array是否被修改..或者实际上它的状态不是恒定的。
  • 为什么知道数组是否被修改很重要?如果我克隆了 Hasher,我希望它独立于前一个,那么我为什么要关心它是否被修改(或它源自的 Array)?
  • 或者您的意思是在复制期间对哈希器进行某种锁定很难实现?
  • 最好的方法是覆盖 .deepClone() 并在克隆时设置自己的参数,因为类会更深入。

标签: java hash guava


【解决方案1】:

这可以借助执行对象deep copy 的库来完成(这里有一些deep copy library recommendations)。

一个这样的库是Kryo,可以通过以下方式实现:

  1. 实例化Kryo(请注意,创建此对象非常昂贵+它不是线程安全的):

    Kryo kryo = new Kryo();
    kryo.setInstantiatorStrategy(new StdInstantiatorStrategy());
    
  2. 拨打Kryo.copy(T):

    Hasher anotherHasher = kryo.copy(hasher)
    

但是,请注意,这可能比散列两次更快,因为:

  • Kryo 的StdInstantiatorStrategy 使用Objenesis 来实例化Hasher 实现(我不知道它有多快);
  • 并且不能使用推荐的 DefaultInstantiatorStrategy,因为 Hasher 实现没有无参数构造函数(有关详细信息,请参阅 Kryo 的 readme about InstantiatorStrategy)。

我建议使用 Java Microbenchmark Harness 对此进行基准测试(请注意链接页面末尾的各种 JMH 插件)。

【讨论】:

  • 感谢您的回答,我找到了一种无需深度复制的方法,正如您所说,这不是最快的解决方案。
  • @BaptisteMerliot 感谢您的接受,但如果您找到了更好的解决方案,您可能希望将其发布为答案并接受它,以便其他人可以找到此问题的最佳解决方案。
  • 解决方案是改变我的全局算法,而不仅仅是这部分,所以它就成了这个问题的题外话。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-01
  • 1970-01-01
  • 2011-07-25
  • 1970-01-01
相关资源
最近更新 更多