让我们说我有一个我想迭代的数组:
int[] someArray = {1,2,3,4}
for (int i = 0; i < someArray.length; i++) {
// do stuff
}
这个长度的aray会在每次迭代中被重新计算,还是会被优化以仅计算一次?
我应该通过提前计算长度来迭代数组并将其传递给循环吗?
for (int i = 0, length = someArray.length; i < length ; i++) {
// do stuff
}
答案 0 :(得分:5)
来自JLS 7
10.7阵列成员
数组类型的成员是以下所有成员:
•public final
字段length
,其中包含组件数
数组。长度可以是正数或零。
回到你的问题,java没有重新计算array.length
上数组中元素的数量。它返回在数组创建期间计算的public final int length
的值。
答案 1 :(得分:3)
由于length
是Array
的成员,因此在创建数组时已经设置了它。在每次迭代时,您只能访问该属性。
所以要么像
那样访问它 int myArrayLength=arr.length;
for(int i=0;i<myArrayLength;i++)
或者喜欢:
for(int i=0;i<arr.length;i++)
没有可衡量的性能变化。
答案 2 :(得分:3)
与性能一样:尽可能编写最简单的代码,并对其进行测试以确定其性能是否足够好。
如果你只需要元素(而不是索引),我建议你使用增强型for循环:
for (int value : array) {
...
}
根据JLS 14.14.2,它基本上等同于您的第一段代码,但代码只讨论您真正感兴趣的内容。
但是如果你做需要索引,并假设你不在任何地方改变array
,我相信JIT编译器会优化本机代码只获取一次长度。获得长度是一个O(1)操作,因为它基本上只是数组中的一个字段,但显然它确实涉及命中内存,所以它对最终更好代码只执行一次...但这并不意味着您的代码必须这样做。请注意,我不希望Java编译器(javac
)执行此优化 - 我期望JIT能够。
事实上,我相信一个好的JIT实际上会看到如下代码:
for (int i = 0; i < array.length; i++) {
int value = array[i];
...
}
并且能够优化掉数组边界检查 - 它可以识别出如果它一直访问同一个数组对象,那可能会因数组边界错误而失败,所以它可以避免检查。 可以能够为更多&#34;聪明的&#34;做同样的事情。预先获取长度的代码,但JIT优化通常故意针对非常常见的代码模式(为了获得最大的&#34; bang for buck&#34;)并且上面迭代数组的方式是非常< / em>普通。