2010-10-10 32 views
16

Je suis en train de créer un tableau de JLabels, tous devraient être invisibles quand on clique dessus. Le problème survient lorsque vous essayez de configurer le programme d'écoute de la souris via une classe interne qui a besoin d'accéder à la variable d'itération de la boucle utilisée pour déclarer les étiquettes. Code est explicite:l'accès à la variable dans la classe interne dans 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]); 
    } 

Je pensais que je pouvais résoudre ce par l'utilisation de this ou peut-être super au lieu de l'appel de label[i] dans la méthode intérieure mais je ne l'ai pas été en mesure de comprendre.

L'erreur de compilation est la suivante: la variable locale i est accessible à partir de la classe interne; doit être déclaré final`

Je suis sûr que la réponse doit être quelque chose de vraiment stupide que je n'ai pas pensé ou peut-être que je fais une petite erreur.

Toute aide serait appréciée

+0

L'erreur est: 'variable locale i est accessible à partir de la classe intérieure; doit être déclaré final – omtinez

+0

@omtinez: alors peut-être que vous devriez déclarer la variable comme 'final', non? (jetez un oeil à [ce Q & A] (http://stackoverflow.com/questions/3045130/constructeurs-in-inner-classes-implementing-interfaces), aussi) –

+1

@Matt Ball, Ce n'est pas une bonne idée de avoir la variable d'itérateur 'final'. –

Répondre

27

Votre variable locale doit être final accessible à partir de la classe interne (et anonyme).

Vous pouvez changer votre code pour quelque chose comme ceci:

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; 
} 

De l'JLS:

Toute variable locale, paramètre formel ou paramètre d'exception utilisé, mais non déclarée dans une classe interne doit être déclaré final.

Toute variable locale utilisée mais non déclarée dans une classe interne doit être affectée définitivement (§16) avant le corps de la classe interne.


Ressources:

+0

il serait utile de pouvoir utiliser la variable itérateur pour d'autres méthodes que je considérais non pertinentes à la question ainsi – omtinez

+0

@Colin Hebert Votre lien "ressources" semble relier un autre document que la section 8.1.3 – trante

+0

@trante, merci c'était se référant à un précédent JLS, hébergé par le soleil. C'est maintenant à jour. –

0

Cela se produit parce que label n'est spécifié comme final.

Déclarer le tableau des étiquettes comme:

final JLabel[] label;

au lieu de:

JLabel[] label;

Votre MouseAdapter n'est pas une classe interne; c'est une classe anonyme. Les classes anonymes ne peuvent faire référence qu'aux variables final de leur code englobant.

+0

anonyme? le compilateur me disait qu'il était interne ... – omtinez

+1

En fait, c'est une classe interne * anonyme, ce qui signifie qu'elle n'a pas de nom explicite, et la signification interne est contenue dans une autre classe. – Jorn

0

Les classes internes anonymes peuvent uniquement accéder aux variables de la méthode englobante final.

4

Si vous rencontrez un problème d'accès i, faire une autre variable en dehors de la portée de votre classe interne (par exempleavant 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

peut-être pas le plus élégant solution, mais je pense que cela devrait faire le travail – omtinez

+0

Cela devrait fonctionner, mais la solution Colins est beaucoup plus agréable. – Jorn

2

vous pouvez également utiliser getSource dans votre programme. Après cela, vous pouvez accéder à votre composant avec l'aide de typecasting. il permettra de réduire les lignes de code supplémentaires, votre code ressemblera à ceci

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