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