1: HashMap<String, String> test = new HashMap<>();
2: Map<String, String> test = new HashMap<>();
只进行put、get操作
请问1的性能会优于2吗?为什么?
伊谢尔伦2017-04-17 14:47:38
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]
In the test here, http://bobah.net/book/export/html/55
invokeinterface may be 38% slower
http://stackoverflow.com/questions/1504633/what-is-the-point-of-invokeinterface
Explanation here
阿神2017-04-17 14:47:38
For this question, the general answer is "about the same, there is no difference";
The more extreme answer is "the performance of 2 is slightly better than 1";
Code below:
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");
The corresponding instructions after being compiled into bytecode are:
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
It can be seen that the put/get operation of the map in case 1 is completed with the invokevirtual
instruction;
And the put/get operation of the map in case 2 is completed with the invokeinterface
instruction;
In terms of implementation, the performance of invokevirtual
is slightly better than invokeinterface
, so if we have to say who has better performance, it would be 2;
Finally, as a reminder, in the process of java programming, any jvm instruction should be regarded as having almost the same constant-level time overhead, even if it is invokedynamic
. Only in this way can we bring unity to our upper-level algorithms and logic optimization , non-interference perspective;
It is irrational to change the way Java code is written in order to pick out jvm instructions in a sharp way, and its conclusion is also unstable - it may change with the upgrading of jvm, and for this purpose The code changes brought about by this kind of "performance improvement" lead to reduced readability and maintainability, which is not worth the gain