2013-03-16 88 views
1

在为番石榴的ImmutableMap它说的javadoc:性能警告

性能说明:不同的HashMap,ImmutableMap不为有慢的Object.Equals 元素类型优化(java.lang.Object中)或者 Object.hashCode()实现。您可以通过 让您的元素类型缓存自己的散列代码,并使用缓存值的 来短路等效较慢的算法,从而获得更好的性能。

所以我的第一个问题是如何知道我的元素是否有缓慢的.equals或.hashCode实现?在我的具体实例中,我使用了一个Java Enum作为我的键,因此它有一个有效的.equals和.hashCode默认实现,对吗? (我假设这些值的实现是无关紧要的,只要你不使用值的值访问映射)。

我的第二个问题是“让你的元素类型缓存自己的散列码”甚至意味着!谷歌搜索我似乎无法找到你如何做到这一点的例子。我假设也许这意味着你最终在hashcodes中的hashcode?所以我进入哈希码桶,然后.equals方法使用第二组哈希码内?

回答

4

我使用一个Java枚举作为我的钥匙,让有.equals和高效的默认实现。 hashCode,对吗?

不等于或哈希码被覆盖,所以它几乎不会更快(即等于返回this == other)。

我的第二个问题是“让你的元素类型缓存自己的散列码”甚至意味着什么!

你可能有类似下面的代码,避免多次计算 - 如果你这样做,你需要确保:

  • 的哈希码是不变的(即不能在整个改变一个实例的生命)
  • 您的hashcode方法是线程安全的(可以通过使用局部变量来完成,例如,或者更简单地通过使得hash易变)。
class MyClass { 
    private int hash; 

    public int hashcode() { 
     int hash = this.hash; 
     if (hash == 0) { 
      hash = calculateIt(); 
      this.hash = hash; 
     } 
     return hash; 
    } 
} 
+2

如果对象是不可变的,并且经常调用hashcode()/ equals(),那么甚至可以在对象构造期间计算哈希码,而不必担心线程安全性。 – 2013-03-16 22:50:13

+0

@FrankPavageau绝对 - 确实更容易,更安全。 – assylias 2013-03-16 23:14:34

2

如果你的钥匙是Enum那么这对你来说不是问题。

他们与缓存的散列码谈论会是这样的:

private volatile int hashCode = -1; 

@Override 
public int hashCode() { 
    if (hashCode == -1) { 
    hashCode = longCalculation(); 
    } 
    return hashCode; 
} 
+1

当然,你必须要小心,-1不是一个有效的哈希值。 'java.lang.String'有这个问题:有些字符串每次都会重新计算它们的哈希值。 – Antimony 2013-03-16 21:21:04

+0

你的代码不是线程安全的 – assylias 2013-03-16 21:22:38

+1

@assylias - 你是对的 - 在某种程度上。实际上,它**是安全的,但如果多个线程同时请求'hashCode',它可以多次调用'longCalculation'。如果这是一个关键问题,那么我肯定会在多线程环境中投入更多精力。但是,它的确清楚地表明了我的观点。 – OldCurmudgeon 2013-03-16 21:26:39