2009-03-04 16 views
39

jest to dozwolone w Java:tworząc zmienne końcowe wewnątrz pętli

for(int i=0;i<5;i++){ 
    final int myFinalVariable = i; 
} 

Słowo kluczowe moje pytanie jest final. Czy można wykonać ostatnią zmienną, która zmienia się przy każdym uruchomieniu pętli? Zastanawiam się nad tym, ponieważ finał mówi, że nie możesz zmienić wartości zmiennej (wywołując tylko myFinalVariable = i), ale redefiniuję całą zmienną za pomocą final int.

Czy są to dwie zupełnie różne zmienne o tej samej nazwie - z zmienną z poprzedniego przebiegu pętli już jadącą w dół do garbage collectora?

Odpowiedz

73

Tak, jest dozwolone. Słowo kluczowe final oznacza, że ​​nie można zmienić wartości zmiennej w zakresie jej zakresu. Dla przykładu z pętlą możesz myśleć o zmiennej wychodzącej poza zakres na końcu pętli, a następnie powracającej do zakresu z nową wartością w górnej części pętli. Przypisanie do zmiennej w pętli nie będzie działać.

11

Masz rację, dla każdej iteracji w pętli tworzysz nową zmienną. Zmienne mają tę samą nazwę, ale jest to w porządku, ponieważ nie są one w tym samym zakresie. Kolejny przykład to nie pracy:

final int myFinalVariable = 0; 
for(int i=0;i<5;i++){ 
    myFinalVariable = i; 
} 
8

Zmienna jest tylko miejsce na stosie. Staraj się przechowywać zmienne z możliwie najmniejszym zakresem i staraj się, aby były ostateczne. Jednak zakres i finał są po prostu kwestią kodu źródłowego ... z punktu widzenia generowania kodu/VM naprawdę nie mają znaczenia.

W twoim konkretnym przykładzie, używając "int", nie jest tworzone żadne śmieci. Jednak jeśli byłyby tworzone obiekty, to w obu przypadkach ilość śmieci i kiedy odpadki byłyby kwalifikujące się do czyszczenia, byłyby identyczne.

Weźmy następujący kod:

public class X 
{ 
    public static void main(final String[] argv) 
    { 
     foo(); 
     bar(); 
    } 

    private static void foo() 
    { 
     for(int i=0;i<5;i++) 
     { 
      final int myFinalVariable = i; 
     } 
    } 

    private static void bar() 
    { 
     for(int i=0;i<5;i++) 
     { 
      int myFinalVariable = i; 
     } 
    } 
} 

Kompilator wywołuje identyczną kodu bajtowego dla każdej metody:

public class X extends java.lang.Object{ 
public X(); 
    Code: 
    0: aload_0 
    1: invokespecial #1; //Method java/lang/Object."<init>":()V 
    4: return 

public static void main(java.lang.String[]); 
    Code: 
    0: invokestatic #2; //Method foo:()V 
    3: invokestatic #3; //Method bar:()V 
    6: return 

private static void foo(); 
    Code: 
    0: iconst_0 
    1: istore_0 
    2: iload_0 
    3: iconst_5 
    4: if_icmpge  15 
    7: iload_0 
    8: istore_1 
    9: iinc 0, 1 
    12: goto 2 
    15: return 

private static void bar(); 
    Code: 
    0: iconst_0 
    1: istore_0 
    2: iload_0 
    3: iconst_5 
    4: if_icmpge  15 
    7: iload_0 
    8: istore_1 
    9: iinc 0, 1 
    12: goto 2 
    15: return 

} 

dodanie innego sposobu, który deklaruje zmienną poza pętlą daje nieco innego kodu bajtowego ze względu na kolejność deklarowania zmiennych). Zauważ, że tej wersji nie można ustawić jako ostatecznej. Ta ostatnia wersja nie jest najlepszym sposobem (ostateczna zmiennej wewnątrz pętli jest najlepszy, jeśli można to zrobić):

private static void car() 
{ 
    int myFinalVariable; 

    for(int i=0;i<5;i++) 
    { 
     myFinalVariable = i; 
    } 
} 

private static void car(); 
    Code: 
    0: iconst_0 
    1: istore_1 
    2: iload_1 
    3: iconst_5 
    4: if_icmpge  15 
    7: iload_1 
    8: istore_0 
    9: iinc 1, 1 
    12: goto 2 
    15: return 

} 
2

Jak odpowiedział Tak, rzeczywiście mogą oznaczyć zmiennych w pętli jako „ostateczny” . Oto efekt (Java 7, Eclipse Indigo, Mac OS X Lion).

for (int i = 0; i < 5; i++) { 

    // With 'final' you cannot assign a new value. 
    final int myFinalVariable = i; // Gets 0, 1, 2, 3, or 4 on each iteration. 
    myFinalVariable = 7; // Compiler error: The final local variable myFinalVariable cannot be assigned. 

    // Without 'final' you can assign a new value. 
    int myNotFinalVariable = i; // Gets 0, 1, 2, 3, or 4 on each iteration. 
    myNotFinalVariable = 7; // Compiler is OK with re-assignment of variable's value. 

} 
2

Zmienna zadeklarowana w pętli ma zasięg tylko do pojedynczego wykonania pętli.

Deklaracja zmiennej jako końcowej w pętli powoduje, że nie ma różnicy dla zmiennej po stronie pętli, ale jeśli zadeklarujemy zmienną poza pętlą z ostatecznym modyfikatorem, wówczas wartość przypisana do typu pierwotnego lub Obiekt przypisany do zmiennej referencyjnej nie może zostać zmieniony .

W poniższym przykładzie nie ma problemu z pierwszymi dwoma pętlami, obie pętle dają ten sam wynik, ale trzecia pętla daje błąd kompilacji.

public class Test {

public static void main(String[] args) { 
    for (int i = 0; i < 5; i++) { 
     final int j= i; 
     System.out.println(j); 
    } 
    for (int i = 0; i < 5; i++) { 
     int j= i; 
     System.out.println(j); 
    } 

    final int j; 
    for (int i = 0; i < 5; i++) { 
     j= i; 
     System.out.println(j); 
    } 
} 

}

Proszę, poprawcie mnie jeśli się mylę.

Powiązane problemy