简体   繁体   English

Java:在for循环中调用arr.length的次数是多少?

[英]Java: How many times is arr.length called in a for-loop?

If arr is an array of size 10, in the following code block, how many times is arr.length accessed? 如果arr是一个大小为10的数组,在下面的代码块中,访问arr.length次数是arr.length

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

Once? 一旦? Or every time it loops? 或者每次循环?

Thanks everyone! 感谢大家! Here's what I ended up doing: 这是我最终做的事情:

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

Eleven times.... 十一次......

10 times, the statement i < arr.length evaluates to true . 10次​​,声明i < arr.length评估为true
1 time it evalutes to false and the loop ends. 1次它评估为false并且循环结束。

Since you are permitted to change arr within the loop, it's usually evaluated every time the loop termination condition is evaluated. 由于允许在循环内更改arr ,因此通常在每次评估循环终止条件时对其进行求值。

An optimising compiler (or JIT) may recognise that you don't change arr within the loop, and then only evaluate arr.length once. 优化编译器(或JIT)可能会识别出您不在循环中更改arr ,然后仅评估arr.length一次。

Without compiler optimizations, 11 times (one per iteration + one after the last iteration). 没有编译器优化,11次(每次迭代一次+最后一次迭代后一次)。 But the compiler will optimize the thing so there's going to be only one access. 但是编译器会优化这个东西,所以只有一个访问权限。 But what I said assumes your for loop has a body: 但我所说的假设你的for循环有一个体:

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

In your case the loop has no body: 在你的情况下,循环没有正文:

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

so it's a no-op and the compiler is going to remove it. 所以这是一个无操作,编译器将删除它。 So in that specific case you'll access the field zero times. 因此,在特定情况下,您将访问该字段零次。

But don't rely on compiler optimizations because you don't really know what it does. 但是不要依赖编译器优化,因为你真的不知道它的作用。

zero is a possible answer in a decent modern vm. 是一个体面的现代vm的可能答案。

in your specific loop, since it doesn't do anything, most likely vm will completely bypass it. 在你的特定循环中,因为它没有做任何事情, 很可能 vm会完全绕过它。

in the following example 在以下示例中

size = ...
arr = new byte[size];
for (int i = 0; i < arr.length; ++i)
    non-trivial-statements;

vm could deduce that arr.length==size, which is already in a register, therefore size is used directly. vm可以推导出已经在寄存器中的arr.length == size,因此直接使用size

more interestingly, it knows that i<arr.length already , therefore arr[i] doesn't need runtime bound check, making array access as cheap as C array. 更有趣的是,它知道 i<arr.length已经i<arr.length ,因此arr[i]不需要运行时绑定检查,使得数组访问与C数组一样便宜。

However, Java the language doesn't dictate these things. 但是,Java语言并没有规定这些东西。 a vm can access it zero times, or a million times, it's all correct as long as the observable effects are the same. 一个vm可以访问它零次或一百万次,只要可观察的效果是相同的,它们都是正确的。

the point is, you shouldn't worry about it. 关键是,你不应该担心它。 programs written in the common fashion are most likely subject to heavy optimization. 以共同方式编写的程序很可能需要进行大量优化。 following the crowd pays off in this case. 跟随人群在这种情况下得到回报。

Every time it loops by definition. 每次按定义循环。 It might be optimized to 1 if you are lucky. 如果你幸运的话可能会优化为1。

for (int i=0, n=arr.length; i<n; i++); for (int i=0, n=arr.length; i<n; i++); is a simple idiom that neither 这是一个简单的习惯用语

  • a) relies on the compiler nor a)依赖编译器也不依赖
  • b) requires a non-loop scoped variable to hold the length, and b)需要一个非循环范围的变量来保持长度,和
  • c) evaluates arr.length just once c)只评估一次arr.length

You could also do some experiments like 你也可以做一些实验

public class Count{

    private static int count; 

    private static int getLength(Object[] arr) {
        count += 1;
        return arr.length;
    }

    public static void main(String[] args){
        count = 0;
        Object[] arr = new Object[10];
        for (int i = 0; i < getLength(arr); ++i) {
            // do something
        }
        System.out.printf("called %d times%n", count);
    }
}    

for more details also print the value of i and the returned value of getLength (or use a debugger). 有关更多详细信息,还会打印i的值和getLength的返回值(或使用调试器)。

For fast online testing have a look at Youjavait or ideone . 对于快速在线测试,请查看Youjavaitideone

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM