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
本身中包含的所有对象。 看一下HashSet
的equals()
和hashCode()
的实现,并将它与String
进行比较。
至于你的例子:由于hashCode()
只有一次影响小于equals()
。 在你的第一个块中,你为HashSet
计算一次,然后get()
再次为Integer
做一次(实际上并不那么复杂)。 这在hashCode()
部分没有太大区别。 第一个块要快得多,因为对于Integer
而不是HashSet
执行equals()
,这要快得多。
我不知道你要对这段代码做什么,但是对于你的问题,当HashMap
的键是一个Collection
(如你的HashMap
), hashCode
计算需要迭代Collection
包含的所有元素,因此计算取决于常量数量属性的hashCode
需要更多时间。