84669 orang belajar
152542 orang belajar
20005 orang belajar
5487 orang belajar
7821 orang belajar
359900 orang belajar
3350 orang belajar
180660 orang belajar
48569 orang belajar
18603 orang belajar
40936 orang belajar
1549 orang belajar
1183 orang belajar
32909 orang belajar
1: HashMap<String, String> test = new HashMap<>();2: Map<String, String> test = new HashMap<>();
只进行put、get操作请问1的性能会优于2吗?为什么?
业精于勤,荒于嬉;行成于思,毁于随。
HashMap<String, String> map1 = new HashMap<>(); Map<String, String> map2 = new HashMap<>(); map1.put("a", "b"); map2.put("a", "b");
=>
16 aload_1 [map1] 17 ldc <String "a"> [160] 19 ldc <String "b"> [162] 21 invokevirtual java.util.HashMap.put(java.lang.Object, java.lang.Object) : java.lang.Object [164] 24 pop 25 aload_2 [map2] 26 ldc <String "a"> [160] 28 ldc <String "b"> [162] 30 invokeinterface java.util.Map.put(java.lang.Object, java.lang.Object) : java.lang.Object [168] [nargs: 3]
这里的测试中, http://bobah.net/book/export/html/55invokeinterface可能慢38%
http://stackoverflow.com/questions/1504633/what-is-the-point-of-invokeinterface这里有解释
对于这个问题,一般的答案是“差不多,没有区别”; 而钻牛角尖的答案是“2的性能比1稍好”;
下面的代码:
HashMap<String, String> m1 = new HashMap<>(); m1.put("test", "test"); m1.get("test"); Map<String, String> m2 = new HashMap<>(); m2.put("test", "test"); m2.get("test");
编译成字节码后对应的指令是:
0: new #16 // class java/util/HashMap 3: dup 4: invokespecial #18 // Method java/util/HashMap."<init>":()V 7: astore_1 8: aload_1 9: ldc #19 // String test 11: ldc #19 // String test 13: invokevirtual #21 // Method java/util/HashMap.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 16: pop 17: aload_1 18: ldc #19 // String test 20: invokevirtual #25 // Method java/util/HashMap.get:(Ljava/lang/Object;)Ljava/lang/Object; 23: pop 24: new #16 // class java/util/HashMap 27: dup 28: invokespecial #18 // Method java/util/HashMap."<init>":()V 31: astore_2 32: aload_2 33: ldc #19 // String test 35: ldc #19 // String test 37: invokeinterface #29, 3 // InterfaceMethod java/util/Map.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 42: pop 43: aload_2 44: ldc #19 // String test 46: invokeinterface #32, 2 // InterfaceMethod java/util/Map.get:(Ljava/lang/Object;)Ljava/lang/Object; 51: pop 52: return
可见情况1的map的put/get操作是用invokevirtual指令完成的; 而情况2的map的put/get操作是用invokeinterface指令完成的;
invokevirtual
invokeinterface
而论实现的话,invokevirtual的性能略优于invokeinterface, 因此硬要说谁性能好的话那就是2;
最后提醒一下,在java编程过程中,任何jvm指令我们都应该看作是差不多一样的常数级时间开销,哪怕它是invokedynamic,这才能为我们的上层算法、逻辑优化带来统一、无干扰的视角; 为了钻牛角尖地挑选jvm指令而改变java代码的写法是不理智的,且其结论也是不稳定的 —— 它可能会随着jvm升级换代而变化的, 而且为了这种“性能提升”而带来的代码改动导致可读性、可维护性降低也是得不偿失的
invokedynamic
根据可操作方法论,2的性能优于1
=>
这里的测试中, http://bobah.net/book/export/html/55
invokeinterface可能慢38%
http://stackoverflow.com/questions/1504633/what-is-the-point-of-invokeinterface
这里有解释
对于这个问题,一般的答案是“差不多,没有区别”;
而钻牛角尖的答案是“2的性能比1稍好”;
下面的代码:
编译成字节码后对应的指令是:
可见情况1的map的put/get操作是用
invokevirtual
指令完成的;而情况2的map的put/get操作是用
invokeinterface
指令完成的;而论实现的话,
invokevirtual
的性能略优于invokeinterface
, 因此硬要说谁性能好的话那就是2;最后提醒一下,在java编程过程中,任何jvm指令我们都应该看作是差不多一样的常数级时间开销,哪怕它是
invokedynamic
,这才能为我们的上层算法、逻辑优化带来统一、无干扰的视角;为了钻牛角尖地挑选jvm指令而改变java代码的写法是不理智的,且其结论也是不稳定的 —— 它可能会随着jvm升级换代而变化的, 而且为了这种“性能提升”而带来的代码改动导致可读性、可维护性降低也是得不偿失的
根据可操作方法论,2的性能优于1