2010-10-10 23 views
16

Sto provando a creare un array di JLabels, tutti dovrebbero diventare invisibili quando si fa clic. Il problema si presenta quando si tenta di impostare il listener del mouse attraverso una classe interna che deve accedere alla variabile di iterazione del ciclo utilizzato per dichiarare le etichette. Codice è auto-esplicativo:accesso alla variabile all'interno della classe interna in java

for(int i=1; i<label.length; i++) { 
     label[i] = new JLabel("label " + i); 
     label[i].addMouseListener(new MouseAdapter() { 
      public void mouseClicked(MouseEvent me) { 
      label[i].setVisible(false); // compilation error here 
      } 
     }); 
     cpane.add(label[i]); 
    } 

ho pensato che avrei potuto superare questo con l'uso di this o forse super invece che il richiamo del label[i] all'interno del metodo interno, ma non sono stato in grado di capirlo.

L'errore di compilazione è: la variabile locale i è accessibile dall'interno della classe interna; deve essere dichiarato definitivo

Sono sicuro che la risposta deve essere qualcosa di veramente sciocco a cui non ho pensato o forse sto facendo un piccolo errore.

Tutto l'aiuto sarebbe apprezzato

+0

L'errore è: 'variabile locale i si accede dall'interno di classe interna; deve essere dichiarato finale ' – omtinez

+0

@omtinez: allora forse dovresti dichiarare la variabile come' finale', no? (dai un'occhiata a [questo Q & A] (http://stackoverflow.com/questions/3045130/constructors-in-inner-classes-implementing-interfaces), anche) –

+1

@Matt Ball, non è una buona idea avere la variabile iteratore 'final'. –

risposta

27

La variabile locale deve essere final accessibile dalla classe interna (e anonima).

È possibile modificare il codice per qualcosa di simile:

for (int i = 1; i < label.length; i++) { 
    final JLabel currentLabel =new JLabel("label " + i); 
    currentLabel.addMouseListener(new MouseAdapter() { 
     public void mouseClicked(MouseEvent me) { 
      currentLabel.setVisible(false); // No more compilation error here 
     } 
    }); 
    label[i] = currentLabel; 
} 

Dal JLS:

Qualsiasi variabile locale, parametro formale, o il parametro eccezioni utilizzato ma non dichiarata in una classe interna deve essere dichiarato final.

Qualsiasi variabile locale utilizzata ma non dichiarata in una classe interna deve essere assegnata definitivamente allo (§16) prima del corpo della classe interna.


Risorse:

+0

sarebbe utile essere in grado di utilizzare la variabile iteratore per altri metodi che ho considerato irrilevante per la domanda pure – omtinez

+0

@Colin Hebert Il tuo link "risorse" sembra collegare altro documento rispetto alla sezione 8.1.3 – trante

+0

@trante, grazie è stato riferendosi a un precedente JLS, ospitato dal sole. Ora è aggiornato. –

0

Ciò accade perché label non è specificato come final.

Dichiara l'array di etichette come:

final JLabel[] label;

invece di:

JLabel[] label;

tuo MouseAdapter non è una classe interna; è una classe anonima. Le classi anonime possono fare riferimento solo alle variabili final del loro codice allegato.

+0

anonimo? il compilatore mi stava dicendo che era interno ... – omtinez

+1

In realtà, è una * classe interiore anonima *, significato anonimo che non ha un nome esplicito e il significato interiore è contenuto in un'altra classe. – Jorn

0

Le classi interne anonime possono accedere solo alle variabili del metodo di inclusione che sono final.

4

Se hai un problema di accesso i, fare un'altra variabile al di fuori della portata del vostro interno di classe (per esempioprima label[i].addMouseListener(...)):

for(int i=1; i<label.length; i++) { 
    label[i] = new JLabel("label " + i); 

    final int localI = i; 
    label[i].addMouseListener(new MouseAdapter() { 
     public void mouseClicked(MouseEvent me) { 
     label[localI].setVisible(false); 
     } 
    }); 
    cpane.add(label[i]); 
} 
+1

forse non il più elegante soluzione, ma penso che questo dovrebbe fare il lavoro – omtinez

+0

Dovrebbe funzionare, ma la soluzione Colins è molto più bella. – Jorn

2

è anche possibile utilizzare getSource nel programma. Dopo questo è possibile accedere al componente con l'aiuto di typecasting. ridurrà linee extra di codice, il codice sarà simile a questa

for (int i = 1; i < label.length; i++) { 
    currentLabel.addMouseListener(new MouseAdapter(e) { 
     public void mouseClicked(MouseEvent me) { 
     JLabel label = (JLabel) me.getSource(); 
     } 
    }); 
} 
Problemi correlati