如果我在Java循环内或循环外声明变量,会有所不同吗?[关闭]


13

可能重复:
您在哪里声明变量?方法的顶部或何时需要它们?

如果我在Java循环内或循环外声明变量,会有所不同吗?

这是

for(int i = 0; i < 1000; i++) {
   int temp = doSomething();
   someMethod(temp);
}

等于这个(关于内存使用)?

int temp = 0;
for(int i = 0; i < 1000; i++) {
   temp = doSomething();
   someMethod(temp);
}

如果临时变量例如是ArrayList,该怎么办?

for(int i = 0; i < 1000; i++) {
   ArrayList<Integer> array = new ArrayList<Integer>();
   fillArray(array);
   // do something with the array
}

编辑:随着javap -c我得到以下输出

循环外的变量:

  public static void main(java.lang.String[]);
    Code:
       0: iconst_0      
       1: istore_1      
       2: iconst_0      
       3: istore_2      
       4: iload_2       
       5: sipush        1000
       8: if_icmpge     25
      11: invokestatic  #2                  // Method doSomething:()I
      14: istore_1      
      15: iload_1       
      16: invokestatic  #3                  // Method someMethod:(I)V
      19: iinc          2, 1
      22: goto          4
      25: return  

循环内的变量:

  public static void main(java.lang.String[]);
    Code:
       0: iconst_0      
       1: istore_1      
       2: iload_1       
       3: sipush        1000
       6: if_icmpge     23
       9: invokestatic  #2                  // Method doSomething:()I
      12: istore_2      
      13: iload_2       
      14: invokestatic  #3                  // Method someMethod:(I)V
      17: iinc          1, 1
      20: goto          2
      23: return        

对于感兴趣的人,此代码:

public class Test3 {
    public static void main(String[] args) {
        for(int i = 0; i< 1000; i++) {
            someMethod(doSomething());
        }   
    }
    private static int doSomething() {
        return 1;
    }
    private static void someMethod(int temp) {
        temp++;
    }
}

产生这个:

  public static void main(java.lang.String[]);
    Code:
       0: iconst_0      
       1: istore_1      
       2: iload_1       
       3: sipush        1000
       6: if_icmpge     21
       9: invokestatic  #2                  // Method doSomething:()I
      12: invokestatic  #3                  // Method someMethod:(I)V
      15: iinc          1, 1
      18: goto          2
      21: return   

但是优化会在运行时进行。有没有办法查看优化的代码?(很抱歉编辑很久)


1
我很高兴您真正查看了反汇编,并希望它对您有所帮助。我曾希望有实际Java经验的人回答您有关优化代码的最后一个问题,但是也许您可以在Stackoverflow上发布该特定部分-这似乎是一个非常具体的问题。
Joris Timmermans 2012年

是的,我将尝试获取优化的代码。(问题有所改变,我在编辑中用优化的代码问了这个问题)
Puckl 2012年

重复链接断开。现在是使这个问题成为原创的时候了。
Zon

Answers:


4

这些问题大多数的常见答案应该是“您为什么不尝试并找出来?”。在Java中,您可能需要查看生成的字节码(我相信该工具称为javap),以查看这两种声明变量的方式之间字节码的区别。

这样做对您来说是一个更好的学习体验,因为下次您遇到优化问题时,您可以使用同一工具来验证编译器是否正在执行期望的工作-这将帮助您避免不必要地更改代码当优化器自己做得很好时,您可以选择样式,或者在您确实需要最后一点性能时找到实际的调整。



1

在单个变量的级别上,效率没有显着差异,但是,如果您有一个具有1000个循环和1000个变量的函数(不要介意隐含的不良风格),则可能存在系统差异,因为所有变量的寿命都是相同而不是重叠。这可能会影响栈大小以及垃圾收集器清除保持存活时间超过必要时间的变量的能力。

另外,给变量提供尽可能小的范围是一种更好的样式。它可以防止事故发生。


这是不正确的-在JVM级别上,不存在局部变量作用域受限的问题。
Michael Borgwardt

您的意思是说,如果我写了1000次(int i = ..),退出函数时堆栈上会有1000个不同的变量?
ddyer 2012年

根据 artima.com/insidejvm/ed2/jvm8.html的说明,“例如,如果两个局部变量的作用域有限且不重叠,例如Example3b中的i和j局部变量,则编译器可以自由使用相同的数组条目对于这两个变量。“这仅是有意义的,编译器可以通过这种方式自由地优化堆栈帧的大小。
ddyer 2012年

1
好点子; 但是,如果我们谈论的是编译器优化,则编译器几乎可以轻松地将局部变量条目重用于具有重叠词法范围但未以重叠方式使用的变量。
Michael Borgwardt
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.