Uso de definiciones de clase dentro de un método en Java

Ejemplo:

public class TestClass { public static void main(String[] args) { TestClass t = new TestClass(); } private static void testMethod() { abstract class TestMethod { int a; int b; int c; abstract void implementMe(); } class DummyClass extends TestMethod { void implementMe() {} } DummyClass dummy = new DummyClass(); } } 

Descubrí que el fragmento de código anterior es perfectamente legal en Java. Tengo las siguientes preguntas.

  1. ¿De qué sirve tener una definición de clase dentro de un método?
  2. Se generará un archivo de clase para DummyClass
  3. Es difícil para mí imaginar este concepto de una manera orientada a objetos. Tener una definición de clase dentro de un comportamiento. Probablemente alguien me puede decir ejemplos equivalentes del mundo real.
  4. Clases abstractas dentro de un método me suena un poco loco. Pero no hay interfaces permitidas. ¿Hay alguna razón detrás de esto?

Esto se llama una clase local.

2 es el más fácil: sí, se generará un archivo de clase.

1 y 3 son una especie de la misma pregunta. Utilizaría una clase local en la que nunca necesita crear una instancia o conocer los detalles de la implementación en ningún lugar, excepto en un método.

Un uso típico sería crear una implementación desechable de alguna interfaz. Por ejemplo, a menudo verá algo como esto:

  //within some method taskExecutor.execute( new Runnable() { public void run() { classWithMethodToFire.doSomething( parameter ); } }); 

Si necesita crear muchos de estos y hacer algo con ellos, puede cambiar esto a

  //within some method class myFirstRunnableClass implements Runnable { public void run() { classWithMethodToFire.doSomething( parameter ); } } class mySecondRunnableClass implements Runnable { public void run() { classWithMethodToFire.doSomethingElse( parameter ); } } taskExecutor.execute(new myFirstRunnableClass()); taskExecutor.execute(new mySecondRunnableClass()); 

En cuanto a las interfaces: no estoy seguro de si hay un problema técnico que haga que las interfaces definidas localmente sean un problema para el comstackdor, pero incluso si no las hay, no agregarían ningún valor. Si una clase local que implementa una interfaz local fuera utilizada fuera del método, la interfaz no tendría sentido. Y si una clase local solo fuera utilizada dentro del método, tanto la interfaz como la clase se implementarían dentro de ese método, por lo que la definición de la interfaz sería redundante.

Esas son llamadas clases locales . Puede encontrar una explicación detallada y un ejemplo aquí . El ejemplo arroja una implementación específica que no necesitamos conocer fuera del método.

  1. La clase no se puede ver (es decir, instanciada, sus métodos accedidos sin Reflexión) desde fuera del método. Además, puede acceder a las variables locales definidas en testMethod (), pero antes de la definición de la clase.

  2. De hecho, pensé: “No se escribirá ese archivo”. hasta que lo intenté: ¡Oh sí, se creó ese archivo! Se llamará algo así como A $ 1B.class, donde A es la clase externa y B es la clase local.

  3. Especialmente para las funciones de callback (controladores de eventos en GUI, como onClick () cuando se hace clic en un botón, etc.), es bastante habitual utilizar “clases anónimas”, en primer lugar porque puede terminar con muchas de ellas. Pero a veces las clases anónimas no son lo suficientemente buenas, especialmente, no se puede definir un constructor en ellas. En estos casos, estas clases locales de métodos pueden ser una buena alternativa.

El verdadero propósito de esto es permitirnos crear clases en línea en llamadas a función para consolar a aquellos de nosotros que nos gusta pretender que estamos escribiendo en un lenguaje funcional;)

El único caso en el que le gustaría tener una clase interna de función completa frente a una clase anónima (también conocido como cierre de Java) es cuando se cumplen las siguientes condiciones

  1. debe proporcionar una interfaz o implementación de clase abstracta
  2. desea utilizar algunos parámetros finales definidos en la función de llamada
  3. necesita registrar algún estado de ejecución de la llamada de interfaz.

Por ejemplo, alguien quiere un Runnable y desea registrar cuándo la ejecución ha comenzado y terminado.

Con la clase anónima no es posible hacerlo, con la clase interna puedes hacer esto.

Aquí hay un ejemplo que demuestra mi punto

 private static void testMethod ( final Object param1, final Object param2 ) { class RunnableWithStartAndEnd extends Runnable{ Date start; Date end; public void run () { start = new Date( ); try { evalParam1( param1 ); evalParam2( param2 ); ... } finally { end = new Date( ); } } } final RunnableWithStartAndEnd runnable = new RunnableWithStartAndEnd( ); final Thread thread = new Thread( runnable ); thread.start( ); thread.join( ); System.out.println( runnable.start ); System.out.println( runnable.end ); } 

Sin embargo, antes de utilizar este patrón, evalúe si las clases simples de nivel superior, clase interna o clase interna estática son mejores alternativas.

La razón principal para definir las clases internas (dentro de un método o una clase) es tratar con la accesibilidad de los miembros y las variables de la clase y el método que los incluye. Una clase interna puede buscar miembros de datos privados y operar en ellos. Si dentro de un método también puede tratar con la variable local final.

Tener clases internas ayuda a asegurar que esta clase no sea accesible al mundo exterior. Esto es válido especialmente para casos de progtwigción de IU en GWT o GXT, etc. donde JS genera código escrito en Java y el comportamiento de cada botón o evento debe definirse creando clases anónimas