2012-04-15 19 views
33

Ho una serie di posti e l'array ha due stringhe (selezionate e vuote). Al clic del mouse, voglio attraversare la matrice e trovare il posto selezionato. Quando preme il pulsante dice:Non è possibile assegnare la variabile locale finale

L'ultima variabile locale seatno non può essere assegnata, poiché è definita in un tipo di chiusura.

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

la variabile 'seatno' contiene la parola chiave finale. –

risposta

89

Il punto è che le variabili di metodo-locale dal tipo di inclusione sono in realtà copiati alle istanze di classi anonime (questo è perché dei problemi relativi al frame di attivazione, ma non approfondirò i dettagli in quanto questo non è realmente pertinente alla domanda), motivo per cui devono essere definitivi, perché la variabile nell'istanza di tipo nidificata non è più la stessa.

Così, qui è il primo esempio:

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

Questo non si compila, perché non si può fare riferimento a una variabile non finale in un metodo di classe anonima. Quando aggiungi un modificatore finale alla dichiarazione di a, il valore di a verrebbe copiato nell'istanza creata della classe anonima che hai definito. Tuttavia, non ti sarà consentito modificare il valore di a, perché le modifiche non sarebbero visibili al metodo in cui è stato dichiarato a.

Tuttavia, le classi anonime non sono statici, cioè, hanno un riferimento all'istanza che racchiude (a meno che il metodo in cui sono dichiarate è statico), che è possibile utilizzare per modificare le variabili di istanza allegando:

int a = 3; 

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

Questo esempio viene compilato e aumenterà di a di 3 ogni volta che viene chiamato il metodo run() dell'istanza di classe anonima. (In questo esempio non viene mai chiamato, ma è solo un esempio.)

Quindi, per riassumere, è necessario convertire la variabile seatno da una variabile di metodo locale a una variabile di istanza del tipo di inclusione.Oppure, se lo è ancora, è necessario rimuovere il modificatore finale poiché le variabili finali possono essere assegnate una sola volta.

Aggiornamento: In Java 8, viene introdotto il concetto di efficacemente finali variabili (vedi Java Language Specification). Tuttavia, nel primo esempio di questo post, la variabile a viene assegnata più volte, il che impedisce che sia effettivamente definitiva. Ciò significa che questo esempio non viene ancora compilato con Java 8. (L'errore di compilazione è "La variabile locale definita in un ambito allegato deve essere definitiva o effettivamente definitiva")

0

Senza conoscere la dichiarazione di seatno, io suggerirei di introdurre una nuova variabile nel metodo mouseClicked() che è non finale e fa lo stesso lavoro di seatno fa attualmente, come variabile sembra solo da usare all'interno di quel metodo.

A proposito: in maiuscolo i nomi delle classi (data devono essere Data). Sembrerà molto più chiaro.

3

Una variabile finale non può modificare il suo valore (è simile a const da C/C++).

Probabilmente si desidera renderlo un campo in una classe (senza ovviamente la parola chiave finale), non una variabile locale all'interno di una funzione.

0

Assicurarsi che la variabile non abbia il modificatore 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; 

Inoltre, per confrontare le stringhe si dovrebbe usare equals:

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

Invece di definire una variabile membro della classe è possibile utilizzare anche un mutabile int per raggiungere lo stesso.

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

Poiché non è MutableInt tipo primitivo (quindi passato per riferimento) e possono essere riassegnati funziona.

+3

Nota: MutableInt richiede Apache Commons Lang. – Sundae

+0

Bello, grazie. MutableInt è più convento di AtomicInteger, perché less codesmell (meno codice necessario) – Hartmut

1

recente ho affrontato problema simile. Nel mio caso è stato più facile creare la matrice finale (o collezione) e aggiungere la variabile, che volevo cambiare all'interno della classe anonima, a questo array, come di seguito.

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