2011-03-20 152 views
2

这些语句在内存占用和Java效率方面是否完全相同?

首先Java For循环差异

Object[] array = new Object[100]; 
int i = 0; 
for (; i < array.length; i++){ 
    Object o = array[i]; 
    //do something 
} 

Object[] array = new Object[100]; 
for (int i = 0; i < array.length; i++){ 
    Object o = array[i]; 
    //do something 
} 

第三

Object[] array = new Object[100]; 
for (Object o : array){ 
    //do something 
} 

回答

6

就内存占用和效率而言,是的。但是,有差异。在第一个,i存在(有一个范围)超出循环;而第二个则不是。在第三种情况下,没有(直接)访问索引或更改当前对象位置的数组内容。

+0

非常感谢。所以在第二个声明中,我将只有一个内存分配给迭代器?或者为每次迭代分配不同的分配? 而在第三个... Java分配一个隐藏的迭代器?数组长度的隐藏整数? – Oneiros 2011-03-20 16:28:12

+2

这是正确的。如果您喜欢冒险,可以使用javap查看每种循环的生成的字节码。他们应该非常接近相同。 – 2011-03-20 16:33:09

+0

哦,我不知道javap ...再次感谢你! :) – Oneiros 2011-03-20 16:37:48

1

第一个是不常见的特发米;我不会那样写。

没有记忆或效率差异。第三个是在后来的JVM中添加的语法糖(我相信它是JDK 6)。

您的代码将成为内存和效率的瓶颈,而不是您的循环结构。

+2

第一个习惯用法是非常有用的情况下,你想在某些条件下摆脱循环,以后需要知道是否有休息,如果是这样,触发它的对象的索引。 – 2011-03-20 16:37:52

0

Java 5引入了第三个版本,旨在简化您的泛型工作。它被增强了,因为在循环之前不需要确定数组中有多少个元素。也没有必要指定如何增加当前位置,提供一个更清晰的实现,而不必创建计数器变量或迭代器。

+0

我同意增强的for-loop语法更清晰,前提是您不需要循环体中的当前索引。 (一方面,你不需要担心身体是否与索引变量混在一起。)但是,在我看来,它可以更容易地掩盖意外的自动装箱开销(尽管不是在这种情况下)。 – 2011-03-20 16:45:04

0

不,它不完全一样。而且这很容易验证,恕我直言,甚至不令人惊讶。

只需编译如下两个功能:

public static void test1(Object[] arr) { 
    for (int i = 0; i < arr.length; i++) { 
     System.out.println(arr[i]); 
    } 
} 

public void test2(Object[] arr) { 
    for(Object o : arr) { 
     System.out.println(o); 
    } 
} 

,并期待在输出:

public static void test1(java.lang.Object[]); 
    Code: 
    0: iconst_0 
    1: istore_1 
    2: iload_1 
    3: aload_0 
    4: arraylength 
    5: if_icmpge  23 
    8: getstatic  #4; //Field java/lang/System.out:Ljava/io/PrintStream; 
    11: aload_0 
    12: iload_1 
    13: aaload 
    14: invokevirtual #5; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V 
    17: iinc 1, 1 
    20: goto 2 
    23: return 

public void test2(java.lang.Object[]); 
    Code: 
    0: aload_1 
    1: astore_2 
    2: aload_2 
    3: arraylength 
    4: istore_3 
    5: iconst_0 
    6: istore 4 
    8: iload 4 
    10: iload_3 
    11: if_icmpge  34 
    14: aload_2 
    15: iload 4 
    17: aaload 
    18: astore 5 
    20: getstatic  #4; //Field java/lang/System.out:Ljava/io/PrintStream; 
    23: aload 5 
    25: invokevirtual #5; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V 
    28: iinc 4, 1 
    31: goto 8 
    34: return 
} 

我只是包括println()一样,让我们​​看到一些与变量并提出完成确保javac不会优化它。显然在更大的图片中,差异并不重要,它们几乎不可测量,但仍然不是相同的代码;)

尽管我不确定第二个函数究竟发生了什么,所以如果有人想要花点时间和剖析代码继续;-)

+0

你的第一个例子并不完全追踪OP的第一个例子。你需要用'Object o = arr [i]替换'System.out.println(arr [i]);'; System.out.println(o);'做一个公平的比较。所以只有'test2'中的每个数组元素都被存储在'o'(局部变量#5)中。第二个也做了几个不同的事情:缓存数组的长度(在局部变量#3中),它将'arr'复制到另一个局部变量(#2)。这些差异可能是由于编译器应用了不同的字节码模板。 – 2011-03-20 21:33:33