2010-06-26 14 views
11

Je suis tombé sur de nombreuses situations où j'avais besoin de passer de la valeur à un autre thread et j'ai trouvé que je pouvais le faire de cette façon, mais je me demandais comment ça fonctionnait?Que se passe-t-il exactement lorsque vous avez des valeurs finales et des classes internes dans une méthode?

public void method() { 
    final EventHandler handle = someReference; 

    Thread thread = new Thread() { 
     public void run() { 
      handle.onEvent(); 
     } 
    }; 

    thread.start(); 
} 

Edit: Il faut juste réaliser ma question ne pointe pas exactement vers ce que je voulais savoir. C'est plus "comment" ça marche plutôt que "pourquoi".

Répondre

7

Vous pouvez remarquer ce qui se passe en dessous simplement en décompilant la classe interne. Voici un court exemple:

Après avoir compilé ce morceau de code:

public class Test { 

public void method() { 
    final Object handle = new Object(); 

    Thread thread = new Thread() { 
     public void run() { 
      handle.toString(); 
     } 
    }; 

    thread.start(); 
} 
} 

vous obtiendrez Test.class pour Test.java et Test$1.class pour la classe interne dans Test.java. Après la décompilation Test$1.class vous verrez ceci:

class Test$1 extends Thread 
{ 
    final Test this$0; 
    private final Object val$handle; 

    public void run() 
    { 
    this.val$handle.toString(); 
    } 
} 

Comme vous pouvez le voir à la place de la variable handle il y a this.val$handle. Cela signifie que handle est copié en tant que champ val$handle dans la classe interne. Et cela ne fonctionnera correctement que si le handle ne changera jamais - ce qui en Java signifie qu'il doit être final.

Vous pouvez également remarquer que la classe interne a un champ this$0 qui fait référence à la classe externe. Cela montre à son tour comment les classes internes non-statiques sont capables de communiquer avec les classes externes.

8

Aucune méthode ne peut accéder aux variables locales d'autres méthodes. Cela inclut les méthodes de classes anonymes comme celle de votre exemple. Autrement dit, la méthode run de la classe Thread anonyme ne peut pas accéder à la variable locale method().

L'écriture final en face de la variable locale est un moyen pour vous en tant que programmeur de faire savoir au compilateur que la variable peut réellement être traitée comme une valeur. Puisque cette variable (read value!) Ne changera pas, il est "ok" d'y accéder dans d'autres méthodes.

2

Cette classe interne se traduit en code similaire à:

class InnerClass extends Thread { 
    private EventHandler handle; 

    public InnerClass(EventHandler handle) { 
     this.handle = handle; 
    } 

    public void run() { 
     handle.onEvent(); 
    } 
} 

... 

EventHandler handle = someReference; 
Thread thread = new InnerClass(handle); 
thread.start(); 

Étant donné que la classe interne se fait passer une copie de la variable finale, il peut ne fait aucun changement qui serait visible dans la classe externe. Pour interdire même d'essayer d'apporter des modifications à ce paramètre, il est uniquement autorisé à accéder aux variables finales dans les classes internes.