2012-04-15 29 views
33

Mam tablicę miejsc, a tablica ma dwa ciągi (wybrane i puste). Po kliknięciu myszki chcę przejść przez tablicę i znaleźć wybrane miejsce. Po naciśnięciu przycisku jest wyświetlany następujący komunikat:Ostatnia zmienna lokalna nie może być przypisana

Ostatniej zmiennej lokalnej seatno nie można przypisać, ponieważ jest ona zdefiniowana w typie obejmującym.

JButton btnContinue = new JButton("Next"); 
    btnContinue.addMouseListener(new MouseAdapter() { 
     public void mouseClicked(MouseEvent arg0) { 

      for(int x=0;x<17;x++){ 
       if(anArray[x]=="selected"){ 

        seatno = anArray[x]; 
       } 
      } 

      data page=new data(newfrom,newto,newtime,date2,seatno); 
      page.setVisible(true); 
      setVisible(false); 
     } 
    }); 
    btnContinue.setBounds(358, 227, 62, 23); 
    contentPane.add(btnContinue); 
+0

Twoja zmienna 'seatno' zawiera końcowe słowo kluczowe. –

Odpowiedz

89

Chodzi o to, że metoda lokalne zmienne od rodzaju otaczającej rzeczywistości są kopiowane do wystąpień anonimowych klas (to dlatego, problemów związanych z ramką aktywacji, ale nie będę wchodził w szczegóły, ponieważ nie jest to istotne dla pytania), dlatego muszą być ostateczne, ponieważ zmienna w instancji typu zagnieżdżonego nie jest już taka sama.

Więc tutaj jest pierwszym przykładem:

void foo() { 
    int a = 3; 
    new Runnable() { 
     @Override 
     public void run() { 
      a += 3; 
     } 
    }; 
} 

nie skompilować, ponieważ nie można odwoływać się do zmiennej non-końcowy w sposób anonimowy klasy. Po dodaniu ostatecznego modyfikatora do deklaracji a, wartość a zostanie skopiowana do utworzonej instancji klasy anonimowej, którą zdefiniowałeś. Jednak nie będzie można zmienić wartości a, ponieważ zmiany nie będą widoczne dla metody, w której zadeklarowano a.

Jednak anonimowe klasy nie są statyczne, to znaczy, że mają odwołanie do instancji zamykającego (chyba metody, gdzie są deklarowanej jest statyczna), które można wykorzystać do modyfikacji zmiennych instancji załączając:

int a = 3; 

void foo() { 
    new Runnable() { 
     @Override 
     public void run() { 
      a += 3; 
     } 
    }; 
} 

Ten przykład kompiluje i będzie zwiększał o a o 3 za każdym razem, gdy wywoływana jest metoda run() instancji klasy anonimowej. (W tym przykładzie nigdy nie jest wywoływana, ale jest to tylko przykład).

Podsumowując, należy przekonwertować zmienną seatno z zmiennej lokalnej metody na zmienną instancji typu otaczającego.Lub, jeśli tak jest, musisz usunąć ostateczny modyfikator, ponieważ zmienne końcowe można przypisać tylko raz.

Aktualizacja: W Javie 8, pojęcie skutecznie końcowych zmiennych jest wprowadzony (patrz Java Language Specification). Jednak w pierwszym przykładzie tego wpisu zmienna a jest przypisywana wiele razy, co uniemożliwia jej skuteczne zakończenie. Oznacza to, że ten przykład nadal nie jest kompilowany z językiem Java 8. (Błąd kompilacji to "Zmienna lokalna zdefiniowana w zasięgu obejmującym musi być ostateczna lub efektywna")

0

Nie znając deklarację seatno, sugeruję, aby wprowadzić nową zmienną w metodzie mouseClicked() że jest nie ostateczna i robi to samo zadanie jak seatno aktualnie robi, jak zmienna tylko wydaje do użycia wewnątrz tej metody.

Przy okazji: Zamień na nazwy klas (data powinno być Data). Będzie wyglądał znacznie jaśniej.

3

Ostatnia zmienna nie może zmienić jej wartości (jest podobna do stałej z C/C++).

Prawdopodobnie chcesz uczynić z niego pole w klasie (bez ostatecznego słowa kluczowego oczywiście), a nie zmienną lokalną wewnątrz funkcji.

0

Upewnij się, że zmienna nie ma modyfikatora final.

//final, can be set only when the object is created. 
private final String seatno; 

//no final modifier, the value can be set every time you "want" 
private String seatno; 

także do porównywania ciągów znaków należy użyć equals:

if(anArray[x].equals("selected")) 
4

Zamiast definiować zmienną członka klasy, można również użyć zmienna int, aby osiągnąć to samo.

void foo() { 
    final MutableInt a = new MutableInt(3); 
    new Runnable() { 
     @Override 
     public void run() { 
      a.add(3); 
     } 
    }; 
} 

Ponieważ MutableInt nie jest typem pierwotnym (stąd przekazywany przez odniesienie) i można go ponownie przypisać, działa.

+3

Uwaga: MutableInt wymaga biblioteki Apache Commons Lang. – Sundae

+0

Fajnie, dziękuję. MutableInt jest bardziej konwergentny niż AtomicInteger, ponieważ mniej codesmell (mniej kodu potrzeba) – Hartmut

1

Niedawno stanąłem przed podobnym problemem. W moim przypadku łatwiej było stworzyć końcową tablicę (lub kolekcję) i dodać zmienną, którą chciałem zmienić wewnątrz anonimowej klasy, do tej tablicy, jak poniżej.

int a = 3; 
    final int[] array = new int[1]; 
    array[0] = a; 
    new Runnable() { 
     @Override 
     public void run() { 
      array[0] += 3; 
     } 
    }; 
Powiązane problemy