如果我有像...一样的for循环。
for (int i = 0; i < myArray.length; i++) { ... }
...每次迭代都会评估myArray.length
吗?那就像... ...
int len = myArray.length;
for (int i = 0; i < len; i++) { ... }
......性能会有小幅提升吗?
答案 0 :(得分:4)
无论myArray.length
只是一个字段,因此无需评估
Java数组的长度为public final int
,所以它被初始化一次,当你引用它时,没有像方法调用那样的代码执行
公共最终字段长度,包含数组的组件数。长度可以是positive or zero.
答案 1 :(得分:3)
第一种形式可能会产生一些性能损失,因为评估它需要在iflt
之前,aload
,arraylength
和iload
;而第二个只有两个iload
s。
@ajp正确地提到myArray
可能更改;所以编译器会高度不太可能将第一种形式优化为第二种形式(除非,myArray
可能是final
)。
然而,JIT,当它开始时,可能足够聪明,如果myArray
没有改变,它将把第一个形式变成第二个。
以防万一,无论如何,使用第二种形式(这是我经常做的,但这只是出于习惯)。请注意,您始终可以javap
生成的类文件来查看生成的字节代码并进行比较。
顺便说一句,维基百科有一个very handy page listing all of a JVM's bytecodes。正如您所看到的,其中很多都专注于阵列!
答案 2 :(得分:2)
是的,每次都会评估终止表达式。所以你保持一次长度可能是一个小的性能提升是正确的。但更重要的是,它改变了逻辑,如果重新分配myArray
,这可能会有所不同。
for (int i = 0; i < myArray.length; i++) {
if (something-something-something) {
myArray = appendToMyArray(myArray, value); // sets myArray to a new, larger array
}
}
现在,首先将数组长度存储在变量中会产生很大的不同。
您通常不会看到带有数组的代码。但是对于arrayList
或其他集合,其大小可以在循环体中增加(或减少),无论您是一次还是每次计算大小,都会产生大差异。这个习惯用法出现在你保留“待办事项列表”的算法中。例如,这是一个部分算法,用于查找直接或间接与某人建立联系的所有人:
ArrayList<Person> listToCheck = new ArrayList<>(KevinBacon);
for (int i = 0; i < listToCheck.size(); i++) {
List<Person> connections = allConnections(listToCheck.get(i));
for (Person p : connections) {
if ([p has not already been checked]) {
listToCheck.add(p); // increases listToCheck.size()!!!
}
}
}
答案 3 :(得分:0)
不是真的。两种情况都是将两个内存地址的值与每次迭代进行比较,除非您在使用len
变量时进行不必要的分配。性能差异可能非常小,第一行更具可读性,因此我会使用第一种方式,因为它更具可读性。如果您想要更具可读性和效率,请使用for-each循环,如果您只是要通过数组进行线性迭代。 for-each循环看起来像这样:
int [] myArray = {1,2,3};
for(int i:myArray){
System.out.print(i);
}
将打印:
1
2
3
因为我被设置为数组的每个元素。 for each循环可用于许多对象,是一个很好的学习功能。 这是一本解释它的指南。