代码之家  ›  专栏  ›  技术社区  ›  LuminousNutria

在迭代过程中,两次调用数组的length属性还是生成新变量更快?[副本]

  •  0
  • LuminousNutria  · 技术社区  · 6 年前

    在应用程序中将for循环更新为for each循环时,我遇到了很多这样的“模式”:

    for (int i = 0, n = a.length; i < n; i++) {
        ...
    }
    

    而不是

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

    大小()

    array.length 比常规变量更贵?

    0 回复  |  直到 15 年前
        1
  •  74
  •   Stephen C    6 年前

    array.length O(1) 或恒定时间操作。

    自从 .length 是一个 public final array ,它的访问速度并不比局部变量慢。(这与调用 size() )

    不管怎么说都是。

    您可以通过查看OpenJDK中JIT编译器的源代码,或者让JVM转储JIT编译的本机代码并检查代码来确认这一点。

    1. 如果您正在调试封闭方法,或者
    2. 如果循环体有足够的局部变量来强制寄存器溢出。
        2
  •  19
  •   Grant Wagner    15 年前

    我午饭时有点时间:

    public static void main(String[] args) {
        final int[] a = new int[250000000];
        long t;
    
        for (int j = 0; j < 10; j++) {
            t = System.currentTimeMillis();
            for (int i = 0, n = a.length; i < n; i++) { int x = a[i]; }
            System.out.println("n = a.length: " + (System.currentTimeMillis() - t));
    
            t = System.currentTimeMillis();
            for (int i = 0; i < a.length; i++) { int x = a[i]; }
            System.out.println("i < a.length: " + (System.currentTimeMillis() - t));
        }
    }
    

    结果是:

    n = a.length: 672
    i < a.length: 516
    n = a.length: 640
    i < a.length: 516
    n = a.length: 656
    i < a.length: 516
    n = a.length: 656
    i < a.length: 516
    n = a.length: 640
    i < a.length: 532
    n = a.length: 640
    i < a.length: 531
    n = a.length: 641
    i < a.length: 516
    n = a.length: 656
    i < a.length: 531
    n = a.length: 656
    i < a.length: 516
    n = a.length: 656
    i < a.length: 516
    

    1. 如果你逆转测试,那么 n = a.length 显示为比 i < a.length 大约一半,可能是由于垃圾收集(?)。
    2. 250000000 因为我有 OutOfMemoryError 270000000 .

        3
  •  11
  •   IRBMe    15 年前

    我怀疑是否有任何显著的区别,即使有,我敢打赌它可能在编译过程中被优化掉了。当你尝试微优化这样的东西时,你是在浪费时间。首先使代码可读并正确,然后如果您有性能问题,请使用 ,然后担心在适当的情况下选择更好的数据结构/算法, 然后 担心如何优化探查器突出显示的部分。

        4
  •  7
  •   Bill the Lizard    15 年前

        5
  •  4
  •   instcode    15 年前

    既然如此,为什么不做一个逆循环:

    for (int i = a.length - 1; i >= 0; --i) {
        ...
    }
    

    • 回路反转
        6
  •  3
  •   Michael Myers KitsuneYMG    15 年前

    将其存储在变量中可能会稍微快一点。但如果一个剖析者指出这是一个问题,我会非常惊讶。

    在字节码级别,通过 arraylength iload 字节码,但应该没有足够的差异来注意。

        7
  •  2
  •   Carl Manaster    15 年前

    这个答案是从C的角度来看的,但我认为Java也是如此。

    在C#,成语

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

    被识别为在数组上迭代,因此在循环中访问数组时避免边界检查,而不是每次访问数组时。

    这可能会或可能不会被代码识别,例如:

    for (int i = 0, n = a.length; i < n; i++) {    ...}
    

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

    这种优化在多大程度上是由编译器执行的,而抖动我不知道,特别是如果它是由抖动执行的,我希望所有3个都能生成相同的本机代码。

        8
  •  1
  •   Chris Vest    15 年前

    数组长度是一个常量,JIT编译器应该在这两个实例中都能看穿它。我希望得到的机器代码在这两种情况下是相同的。至少对于服务器编译器是这样。