W3docs

Clases locales en Java

Declara clases dentro de métodos en Java con clases internas locales, con acceso a variables locales efectivamente finales.

Una clase local es una clase declarada dentro del cuerpo de un método (o un constructor, o un bloque inicializador). Su alcance está limitado al bloque en el que se declara — nada fuera de ese bloque puede mencionarla por su nombre. Por lo demás, se comporta de manera similar a una clase interna, con acceso a los miembros de la instancia que la contiene y a las variables locales efectivamente finales del método.

Las clases locales son poco comunes en el Java moderno. Las expresiones lambda han reemplazado sus principales casos de uso para callbacks de un solo método, y las clases anónimas suelen ser más cortas para implementaciones de un solo uso. Sin embargo, una clase local es ocasionalmente la opción más limpia cuando necesitas un tipo con nombre que participe en la lógica del método que lo contiene y no sea útil en ningún otro lugar.

Si aún no conoces los demás miembros de la familia de clases anidadas, los capítulos sobre clases anidadas y clases internas establecen los términos usados a continuación.

Cómo declarar una

Una declaración de clase dentro del cuerpo de un método:

public void process(List<String> lines) {
  class Counter {
    int n = 0;
    void inc() { n++; }
  }

  Counter c = new Counter();
  for (String s : lines) if (!s.isBlank()) c.inc();

  System.out.println("non-blank lines: " + c.n);
}

Fuera de process, nadie puede ver Counter — su nombre no existe más allá de la llave de cierre del método. Dentro, la usas como cualquier otra clase.

¿Por qué elegirla sobre una clase anónima?

Una clase local tiene un nombre real, lo que te proporciona algunas cosas que una clase anónima no puede tener:

  • Un constructor. Puedes darle parámetros, escribir validación y tener múltiples constructores.
  • Múltiples instancias. Como la clase tiene un nombre, puedes escribir new Counter() más de una vez. Una definición de clase anónima solo crea una instancia por expresión.
  • Autoreferencia. Counter puede tomarse a sí misma como parámetro, tener un campo Counter next, recursar — todo lo que los tipos con nombre pueden hacer.
  • Legibilidad. Un nombre como Counter documenta para qué sirve el ayudante. Los bloques anónimos new Object() { ... } son más difíciles de leer rápidamente.

Acceso al estado que la contiene

Las clases locales pueden:

  • Leer y escribir campos de la instancia que las contiene (si el método que las contiene es no estático).
  • Llamar a métodos de instancia de la clase que las contiene.
  • Leer — pero no reasignar — las variables locales y parámetros finales o efectivamente finales del método que las contiene.
void run(int multiplier) {
  class Scaler {
    int scale(int x) { return x * multiplier; }   // captures the parameter
  }
  System.out.println(new Scaler().scale(7));
}

multiplier se captura en la clase sintética como un campo. El requisito de "efectivamente final" es la razón — si multiplier pudiera reasignarse dentro de run después de que Scaler hubiera capturado su valor anterior, ambos discreparían silenciosamente.

En un método estático

En un método static, la clase local es implícitamente estática — no tiene instancia que la contenga a la que referirse:

public static int demo() {
  class Helper {
    int square(int n) { return n * n; }
  }
  return new Helper().square(7);
}

No hay Outer.this aquí, porque el método que la contiene es estático. Helper aún puede capturar variables locales efectivamente finales de demo, pero no campos de instancia de un objeto que no existe.

Cuándo usarla realmente

Casos concretos en los que una clase local supera genuinamente a las alternativas:

  • El ayudante tiene más de un método, y prefieres ver los métodos agrupados con un nombre claro en lugar de dispersos en el código repetitivo de una clase anónima.
  • El ayudante necesita un constructor para validar su configuración.
  • El ayudante recursa o mantiene referencias a otras instancias de su propio tipo.

Si una lambda o una clase anónima corta funcionarían, prefiere eso. Las clases locales son una herramienta de nicho.

Modificadores

Una clase local acepta solo un conjunto reducido de modificadores:

  • final — marca la clase como no extensible. Ya no tiene nombre para que el código externo la extienda, por lo que esto es principalmente una declaración de intención.
  • abstract — legal pero poco común: necesitarías una segunda clase local en el mismo bloque para extenderla.
  • Los modificadores de acceso (public, protected, private) no están permitidos. Una clase local vive completamente dentro de un bloque, por lo que no hay alcance fuera de ese bloque desde el que la visibilidad pudiera siquiera controlarse.

Tampoco puede declararse static directamente. Si captura una instancia que la contiene depende de si el método circundante es estático, como se mostró anteriormente — no de una palabra clave.

Un ejemplo completo

java— editable, runs on the server

Qué viene a continuación

Eso concluye el recorrido por las clases anidadas — y la mayor parte de la maquinaria POO clásica de Java. La siguiente sección de la Parte 6 avanza hacia los tipos de clases especiales: tipos que Java proporciona para formas específicas de datos, comenzando con enum para conjuntos fijos de constantes. Continúa hacia enums en Java.

Práctica

Práctica
¿Por qué podrías elegir una clase local sobre una clase anónima para el mismo trabajo?
¿Por qué podrías elegir una clase local sobre una clase anónima para el mismo trabajo?
Was this page helpful?