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

Does java cache array length calculation in loops

假设我有一个要迭代的数组:

int[] someArray = {1,2,3,4}

for (int i = 0; i < someArray.length; i++) {

    // do stuff
}

每次迭代都会计算这个长度的数组,还是会优化为只计算一次?

我是否应该通过提前计算长度来迭代数组并将其传递给循环?

for (int i = 0, length = someArray.length; i < length ; i++) {

    // do stuff
}

来自 JLS 7

10.7 数组成员

一个数组类型的成员都是以下几种: • public final 字段 length,其中包含组件的数量 阵列。长度可以是正数或零。

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

因为 lengthArray 的成员,所以当你创建一个数组时它已经被设置,在每次迭代中你只访问那个 属性 没有别的。

所以要么你像

一样访问它
    int myArrayLength=arr.length;
for(int i=0;i<myArrayLength;i++)

或喜欢:

   for(int i=0;i<arr.length;i++)

不会有可衡量的性能变化。

一如既往的性能:尽可能编写最简单的代码,并对其进行测试以查看其性能是否足够好。

如果您只需要元素(而不是索引),我建议您使用增强型 for 循环:

for (int value : array) {
    ...
}

根据 JLS 14.14.2 这基本上等同于您的第一段代码,但该代码仅讨论您真正感兴趣的内容。

但是,如果您 需要索引,并且假设您不更改 array 任何地方,我相信 JIT 编译器会优化本机代码以仅获取一次的长度。获取长度是一个 O(1) 操作,因为它基本上只是数组中的一个字段,但显然它确实涉及内存,因此 eventual 代码最好只执行此操作一次...但这并不意味着 您的 代码必须执行此操作。请注意,我不希望 Java 编译器 (javac) 执行此优化 - 我希望 JIT 执行此优化。

事实上,我相信一个好的 JIT 实际上会看到这样的代码:

for (int i = 0; i < array.length; i++) {
    int value = array[i];
    ...
}

并且能够优化数组边界检查——它可以识别如果它一直访问同一个数组对象,则不可能因数组边界错误而失败,因此它可以避免检查。它 可能 能够对预先获取长度的更多 "clever" 代码做同样的事情,但是 JIT 优化通常故意针对非常常见的代码模式(为了获得最大的"bang for buck") 并且上述遍历数组的方式非常常见。