是否为每次迭代创建了for循环中的引用变量声明?

时间:2017-10-26 12:41:24

标签: java java-memory-model

前两个例子:

1)
MyClass myClass;
for (int i=0; i<arrayList.size(); i++) {
    myClass = arrayList.get(i);
    ...
}


2)
for (int i=0; i<arrayList.size(); i++) {
    MyClass myClass = arrayList.get(i);
    ...
}

在第一个示例中,引用变量myClass仅创建一次。但是在第二个例子中,它是仅创建一次,还是每次迭代创建一次?我的想法也许是编译器优化了这个,我不知道。

我试图通过编写一个例子来回答这个问题,但无法弄明白。如何通过代码证明?

注意:我意识到示例2是更好的样式,因为myClass在for循环之外是不可知的,并且它的范围保持最小。我也在这里搜索过但是没有找到这个确切问题的明确答案(通常它是&#34;这是首选的问题?&#34;。)我还假设如果myClass参考每次迭代都会创建它并不是一个很大的性能问题。

编辑:再次,我不是问哪种编码风格更好。此外,我想知道它是否可以通过代码推断/证明。我尝试生成并比较字节码,但我不熟悉字节码,生成的内容不完全匹配。

1 个答案:

答案 0 :(得分:6)

声明变量时,不要“创建”任何内容。变量只是一个方便的名称,可以帮助您记住放置结果的位置,并允许您控制结果的使用位置,并将某些类型信息与该结果相关联;但是一旦你编译了代码,它们就不再存在了。

比较字节码(*):

void outside(int i, List<?> list) {
  Object obj;
  for (i = 0; i < list.size(); i++) {
    obj = list.get(i);
  }
}

void inside(int i, List<?> list) {
  for (i = 0; i < list.size(); i++) {
    Object obj = list.get(i);
  }
}

反编译为:

  void outside(int, java.util.List<?>);
    Code:
       0: iconst_0
       1: istore_1
       2: iload_1
       3: aload_2
       4: invokeinterface #2,  1            // InterfaceMethod java/util/List.size:()I
       9: if_icmpge     26
      12: aload_2
      13: iload_1
      14: invokeinterface #3,  2            // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
      19: astore_3
      20: iinc          1, 1
      23: goto          2
      26: return

  void inside(int, java.util.List<?>);
    Code:
       0: iconst_0
       1: istore_1
       2: iload_1
       3: aload_2
       4: invokeinterface #2,  1            // InterfaceMethod java/util/List.size:()I
       9: if_icmpge     26
      12: aload_2
      13: iload_1
      14: invokeinterface #3,  2            // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
      19: astore_3
      20: iinc          1, 1
      23: goto          2
      26: return

两者完全相同。使用最具可读性的那个。

(*)我已将循环变量i声明为参数,以避免在Object之前或之后声明的i导致的生成字节码的任何差异。这与字节码的唯一区别在于aload_N / iload_N / astore_N / istore_N指令 - N不同,因为变量存储在不同的“老虎机”。这不是一个显着的差异。