java是否在循环中缓存数组长度计算

时间:2015-06-10 06:12:56

标签: java arrays performance compiler-optimization

让我们说我有一个我想迭代的数组:

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
}

3 个答案:

答案 0 :(得分:5)

来自JLS 7

10.7阵列成员

数组类型的成员是以下所有成员: •public final字段length,其中包含组件数 数组。长度可以是正数或零。

回到你的问题,java没有重新计算array.length上数组中元素的数量。它返回在数组创建期间计算的public final int length的值。

答案 1 :(得分:3)

由于lengthArray的成员,因此在创建数组时已经设置了它。在每次迭代时,您只能访问该属性。

所以要么像

那样访问它
    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>普通。