2010-07-20 18 views
2

Voici le code:Comment un écouteur d'événement java défini comme une classe interne anonyme peut-il utiliser une variable provenant d'une classe englobante?

protected Dialog onCreateDialog(int id) { 
    Dialog dialog = null; 
    if (id == DIALOG_SEARCH) { 
     dialog = new Dialog(this); 
     dialog.setContentView(R.layout.search_dialog_layout); 
     dialog.setTitle("Search Dialog"); 
     Button button = (Button) dialog.findViewById(R.id.Button01); 
     final Button button2 = (Button) dialog.findViewById(R.id.Button02); 
     button2.setEnabled(false); 
     button.setOnClickListener(new OnClickListener() { 
      public void onClick(View arg0) { 
       button2.setEnabled(true); 
      } 
     }); 
    } 
    return dialog; 
} 

Comment la classe interne anonyme (le OnClickListener) ont accès à la variable button2? Sa méthode onClick est appelée à un moment aléatoire dans le futur lorsque l'on clique sur button. Dans quel contexte cette fonction s'exécute-t-elle? Comment sait-il button2? Je suis juste confus au sujet de la portée et du contexte ici.

Répondre

2

Souvent, le meilleur moyen de savoir comment le compilateur Java fait quelque chose est de compiler la classe puis de l'exécuter via Jad (JAva Decompiler). Dans ce cas, il semble que javac crée simplement une variable supplémentaire sur la classe interne anonyme nommée "val $ o" et l'initialise dans un initialiseur statique. En voyant cette transformation, il devient plus clair pourquoi Java exige que vous définissiez la variable finale avant de l'utiliser dans une classe interne anonyme. Sans l'exigence, les deux variables pourraient se retrouver avec des valeurs différentes à l'exécution. En outre, ce n'est vraiment pas différent du mécanisme que Java utilise pour autoriser tous les classes internes (anonymes ou nommées) à accéder à leur classe conteneur. Vous pouvez voir que la classe interne contient une référence à cette variable de la classe contenant, nommée "this $ 0".

Je compilé un exemple plus simple:

public class Outer { 

    public void outerMethod() { 
     final Object o = "fromOuter"; 
     new Object() { 
      public void innerMethod() { 
       System.out.println(o); 
      } 
     }.innerMethod(); 
    } 
} 

et a obtenu ceci l'autre extrémité:

public class Outer { 

    public Outer() 
    { 
    } 

    public void outerMethod() 
    { 
     final Object o = "fromOuter"; 
     (new Object() { 

      public void innerMethod() 
      { 
       System.out.println(o); 
      } 

      final Outer this$0; 
      private final Object val$o; 


      { 
       this$0 = Outer.this; 
       o = obj; 
       super(); 
      } 
     }).innerMethod(); 
    } 
} 
+1

Merci! Tous les répondeurs étaient d'accord, mais j'aime bien celui-ci parce que tu m'as montré comment je pourrais le comprendre par moi-même. Un suivi ... où ce comportement est-il officiellement décrit? –

1

Toute classe anonyme vous créez conservera une référence à la classe englobante qui leur permet d'accéder aux variables de la classe externe.