2011-03-20 95 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