HashMap通过简单而复杂的密钥获得性能

我想要一个其get操作尽可能快的地图。 键是字符串集(数据库中有2个表名相关),值是整数(数字是数据库中行的id,表之间有实际关系),

例子:

table 1 - employee table 2 - company relationship - employee.comp_id = company.id 

我无意在地图中读取密钥。 我只想要给定2个表名的关系id。 所以我写了一个小程序来测试HashMap中的get操作。

 public static void main(String args[]) throws NoSuchMethodException, SecurityException { int limit = 1000; HashMap m1 = new HashMap(1000 * 1000); HashMap<Set, Integer> m2 = new HashMap(1000 * 1000); String k1, k2; Set k3; Integer k4; for (int x = 0; x < limit; x++) { for (int y = 0; y < limit; y++) { k1 = String.valueOf(x); k2 = String.valueOf(y); k3 = new HashSet(Arrays.asList(k1, k2)); k4 = k3.hashCode(); m2.put(k3, k4); m1.put(k4, k4); } } long t1, t2; System.out.println("init"); t1 = System.nanoTime(); // block 1 ///////////////////////////////////////////// for (int x = 0; x < limit; x++) { for (int y = 0; y < limit; y++) { m1.get(new HashSet(Arrays.asList(String.valueOf(x), String.valueOf(y))).hashCode()); } } // ///////////////////////////////////////////////////// t2 = System.nanoTime(); System.out.println(t2 - t1); t1 = t2; // block 2 ///////////////////////////////////////////// for (int x = 0; x < limit; x++) { for (int y = 0; y < limit; y++) { m2.get(new HashSet(Arrays.asList(String.valueOf(x), String.valueOf(y)))); } } // ///////////////////////////////////////////////////// t2 = System.nanoTime(); System.out.println(t2 - t1); } 

在我的机器上,块2​​比块1花费大约9倍的时间来完成执行。

性能是否取决于用作密钥的Object的复杂性。 无论哪种情况,我都知道哈希码是通过HasMap.get()方法的实现来计算的。

实际上对于块1中的代码,哈希码是通过我的代码以及HashMap的实现来计算的,但是性能仍然优于块2,其中Set的哈希码仅通过HashMap的实现来计算。

请注意,正在两个块中创建Set

get()的性能取决于两件事:

  • 参数键对象hashCode()方法的性能
  • 现有密钥对象的性能为equals()方法

看一下HashMap.get()的文档 。 地图包含键值对。 要为键找到正确的值,请使用键的equals()方法。 在HashMap ,通过使用它的哈希来减少要比较的键的数量。 因此, hashCode()在您作为参数传递的密钥对象上只执行一次。

然后, HashMap的实现有几个可以比较的关键对象(理想情况下只有一个)。 这意味着它必须执行equals() 1到n次。

如果您有一个Set作为键类型,则两者都更复杂,因为它们遍历Set本身中包含的所有对象。 看一下HashSetequals()hashCode()的实现,并将它与String进行比较。

至于你的例子:由于hashCode()只有一次影响小于equals() 。 在你的第一个块中,你为HashSet计算一次,然后get()再次为Integer做一次(实际上并不那么复杂)。 这在hashCode()部分没有太大区别。 第一个块要快得多,因为对于Integer而不是HashSet执行equals() ,这要快得多。

我不知道你要对这段代码做什么,但是对于你的问题,当HashMap的键是一个Collection (如你的HashMap, Integer> ), hashCode计算需要迭代Collection包含的所有元素,因此计算取决于常量数量属性的hashCode需要更多时间。