2010-12-30 7 views
7
String[] strs = new String[] { "1", "2", ... , "6" }; 

for (String s : strs) { 
    System.out.println(s); 
} 

To jest pytanie dotyczące wewnętrznych elementów java.W jaki sposób Java wie jak modyfikować tablicę?

W powyższym przykładzie kodu, w jaki sposób pętla foreach określa, jak długo jest ta tablica? Czy tablice są obiektami wewnętrznie, czy też używają rzeczy takich jak sizeof, które są niedostępne dla programistów z przodu?

Mam przeczucie, że brakuje mi czegoś głupiego, ale wydaje mi się, że może być też fajnie. :-)

+0

możliwy duplikat [Jak działa Java dla każdej pętli?] (Http://stackoverflow.com/questions/85190/how-does-the-java-for-each-loop-work) –

+1

+1 ciekawy pytanie, a nie duplikat. –

+0

Niezupełnie. Wiem, że to jest iterable, ale w jaki sposób iterator wie, kiedy przerwać iterację? – SapphireSun

Odpowiedz

11

Skompilowałem następujący kod:

public class ArrayIterator 
{ 
    public static void main(String[] argv) 
    { 
     String[] strs = new String[] { "1", "2", "3", "4", "5" }; 
     enhancedPrint(strs); 
     normalPrint(strs); 
    } 

    public static void enhancedPrint(String[] strs) 
    { 
     for (String s : strs) 
     { 
      System.out.println(s); 
     } 
    } 

    public static void normalPrint(String[] strs) 
    { 
     String[] localArray = strs; 
     int len = localArray.length; 
     for (int i = 0; i < len; i++) 
     { 
      String s = localArray[i]; 
      System.out.println(s); 
     } 
    } 
} 

to jest zdemontowany (javap -c ArrayIterator) kodu bajtowego dla funkcji iteracji:

Udoskonalony druk:

public static void enhancedPrint(java.lang.String[]); 
    Code: 
    0: aload_0 
    1: astore_1 
    2: aload_1 
    3: arraylength 
    4: istore_2 
    5: iconst_0 
    6: istore_3 
    7: iload_3 
    8: iload_2 
    9: if_icmpge 31 
    12: aload_1 
    13: iload_3 
    14: aaload 
    15: astore 4 
    17: getstatic #10; //Field java/lang/System.out:Ljava/io/PrintStream; 
    20: aload 4 
    22: invokevirtual #11; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 
    25: iinc 3, 1 
    28: goto 7 
    31: return 

Normalny pętli for:

public static void normalPrint(java.lang.String[]); 
    Code: 
    0: aload_0 
    1: astore_1 
    2: aload_1 
    3: arraylength 
    4: istore_2 
    5: iconst_0 
    6: istore_3 
    7: iload_3 
    8: iload_2 
    9: if_icmpge 31 
    12: aload_1 
    13: iload_3 
    14: aaload 
    15: astore 4 
    17: getstatic #10; //Field java/lang/System.out:Ljava/io/PrintStream; 
    20: aload 4 
    22: invokevirtual #11; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 
    25: iinc 3, 1 
    28: goto 7 
    31: return 

Jak widać, w obu przypadkach, kompilator się ładuje długości tablic (strs.length) i zapętlenie przeciwko niemu. Widzimy, że ulepszona pętla for-each, w przypadku tablicy to cukier syntaktyczny do pętli w stosunku do długości tablicy (a nie w przypadku obiektu, w którym używa on Iteratora).


I edycja „normalne” dla pętli tak, że jest znacznie mniej idiomatyczne, ale że jest to ten sam kod bajtowy jak zwiększona do pętli. Dla wszystkich celów i celów, normalna wersja pętli for jest tym, co kompilator generuje, gdy kompiluje ulepszony dla każdej pętli.

+0

Whoa! Wielkie dzięki! – SapphireSun

3

Tak, jest coś podobnego do operatora C++ sizeof - to zmienna length instancja Pole length (co daje liczbę elementów w tablicy, nie rozmiar w bajtach). jest zawsze publicznym elementem tablicy, więc jest dostępny dla programistów Java.

I tak, tablice są objects, a nie tylko wewnętrznie.

(Szerzej, składnia for pętla działa zgodnie z opisem w question że org.life.java związanego, ale to nie jest całkiem co pytali.)