哪个函数更快(p是MyObject的atomic public int属性):
public static boolean check(MyObject o1, List<MyObject> list) {
int p = o1.p;
for (int i = 0; i < 1000000; i++) {
MyObject o = list.get(i);
if (o.p < p) return false;
}
return true;
}
要么
public static boolean check(MyObject o1, List<MyObject> list) {
for (int i = 0; i < 1000000; i++) {
MyObject o = list.get(i);
if (o.p < o1.p) return false;
}
return true;
}
因此,通过使用局部变量p我们可以缓存对象属性调用,还是由编译器优化内联完成?
最佳答案
简短答案:这取决于
稍长一点的答案:这取决于编译器,VM和VM的设置。
背景:在服务器模式下使用HotSpot VM(最常见的风味)将使两个变体相同,因为VM确实在服务器模式下循环不变式提升。在客户端模式下,如果VM认为值得优化,则可以执行,不执行或什至以后执行。
Loop invariant hoisting是循环优化的一种,已在大多数现代编译器(或Java,VM)中实现。至于javac生成的代码:如果VM不做进一步优化,您的第一个代码段将表现得更快。
public static boolean check(Test$MyObject, java.util.List);
Code:
0: aload_0
1: getfield #7; //Field Test$MyObject.p:I
4: istore_2
5: iconst_0
6: istore_3
7: iload_3
8: ldc #4; //int 1000000
10: if_icmpge 42
13: aload_1
14: iload_3
15: invokeinterface #11, 2; //InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
20: checkcast #5; //class Test$MyObject
23: astore 4
25: aload 4
27: getfield #7; //Field Test$MyObject.p:I
30: iload_2
31: if_icmpge 36
34: iconst_0
35: ireturn
36: iinc 3, 1
39: goto 7
42: iconst_1
43: ireturn
-
public static boolean check(Test$MyObject, java.util.List);
Code:
0: iconst_0
1: istore_2
2: iload_2
3: ldc #4; //int 1000000
5: if_icmpge 38
8: aload_1
9: iload_2
10: invokeinterface #11, 2; //InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
15: checkcast #5; //class Test$MyObject
18: astore_3
19: aload_3
20: getfield #7; //Field Test$MyObject.p:I
23: aload_0
24: getfield #7; //Field Test$MyObject.p:I
27: if_icmpge 32
30: iconst_0
31: ireturn
32: iinc 2, 1
35: goto 2
38: iconst_1
39: ireturn
如您所见,第二个示例中第20行的getfield操作位于第一个示例中的第1行中,并且在循环之外(变量1中的第7至39行以及变量2中的第2至35行),因此仅执行而不是1000000次。