2010-06-26 9 views
11

Me he encontrado con muchas situaciones en las que necesitaba pasarle valor a otro hilo y fundé que podía hacerlo de esta manera, pero me he estado preguntando ¿cómo está funcionando?¿Qué ocurre exactamente cuando tienes valores finales y clases internas en un método?

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

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

    thread.start(); 
} 

Editar: acaba de darse cuenta mi pregunta no estaba apuntando exactamente hacia lo que quería saber. Es más "cómo" funciona en lugar de "por qué".

Respuesta

7

Puede observar lo que sucede debajo simplemente descompilando la clase interna. Aquí está un ejemplo corto:

Después de compilar esta pieza de código:

public class Test { 

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

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

    thread.start(); 
} 
} 

obtendrá Test.class para Test.javaTest$1.class y para la clase interna en Test.java. Después de la descompilación Test$1.class verá esto:

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

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

Como se puede ver en lugar de handle variables existe this.val$handle. Esto significa que handle se copia como un campo val$handle a la clase interna. Y esto funcionará correctamente solo si el handle nunca cambiará, lo que en Java significa que debe ser final.

También puede observar que la clase interna tiene un campo this$0 que es una referencia a la clase externa. Esto a su vez muestra cómo las clases internas no estáticas pueden comunicarse con las clases externas.

8

Ningún método puede acceder a variables locales de otros métodos. Esto incluye métodos de clases anónimas como el de su ejemplo. Es decir, el método run en la clase Thread anónima no puede acceder a la variable local method().

Escribir final delante de la variable local es una forma para que usted, como programador, le haga saber al compilador que la variable realmente puede tratarse como un valor. Dado que esta variable (¡valor de lectura!) No cambiará, está "OK" para acceder a ella en otros métodos.

2

Esta clase interna se traduce a un código similar a:

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(); 

Desde la clase interna en realidad se pasa una copia de la última variable que puede no hacer ningún cambio que sea visible en la clase externa. No permitir ni siquiera intentar realizar cambios en este parámetro, solo está permitido acceder a las variables finales en las clases internas.

Cuestiones relacionadas