CodeGym /Cursos /JAVA 25 SELF /Clases locales: declaración dentro de métodos

Clases locales: declaración dentro de métodos

JAVA 25 SELF
Nivel 16, Lección 3
Disponible

1. Clase local

Una clase local es una clase declarada dentro de un método (o incluso dentro de un bloque de código, por ejemplo, en un bucle o en un bloque if). Es visible y accesible solo dentro de ese método y, fuera de él, es como si no existiera. A diferencia de las clases anónimas, una clase local tiene nombre (aunque sea sencillo), y puede contener varios métodos e incluso campos.

Si hacemos una analogía: imagina que estás cocinando un plato complejo siguiendo una receta. En uno de los pasos necesitas preparar una salsa especial que solo se usa en esta receta y en ninguna otra. En lugar de publicar un libro de recetas aparte solo para esa salsa, describes su preparación directamente dentro de la receta principal. Una clase local funciona igual: es «una receta dentro de otra receta», necesaria solo en un método concreto.

Ejemplo de declaración de una clase local

public class Outer {
    void someMethod() {
        class Local {
            void print() {
                System.out.println("Hello from Local!");
            }
        }
        Local local = new Local();
        local.print();
    }
}

Aquí la clase Local se declara dentro del método someMethod de la clase Outer. Existe solo en este método y no es visible desde fuera.

Sintaxis de las clases locales

La declaración de una clase local se parece a la de una clase normal, solo que ocurre dentro de un método:

void myMethod() {
    class MyLocalClass {
        void doSomething() {
            System.out.println("¡La clase local funciona!");
        }
    }

    MyLocalClass obj = new MyLocalClass();
    obj.doSomething();
}

Particularidades de la sintaxis:

  • Una clase local puede declararse dentro de cualquier método, constructor o incluso bloque de inicialización.
  • El nombre de la clase local es obligatorio (a diferencia de las clases anónimas).
  • Una clase local no puede declararse con modificadores de acceso (public, private, protected) ni con el modificador static.
  • Una clase local puede implementar interfaces o heredar de otras clases.

Comparación de tipos de clases:

public class Example {
// 1. Clase regular (en un archivo separado)
// class RegularClass { ... }

    // 2. Clase interna (dentro de una clase)
    class InnerClass { }
    
    // 3. Clase anidada estática (dentro de una clase)
    static class NestedClass { }
    
    void method() {
        // 4. Clase local (en un método)
        class LocalClass { }
        
        // 5. Clase anónima (en un método, sin nombre)
        Object obj = new Object() { };
    }
}

Clase local = una clase con nombre solo para este método.

2. Particularidades de las clases locales

Acceso a las variables del método

Una clase local puede acceder a:

  • Los campos de la clase externa (incluso si son private).
  • Solo a variables final o effectively final del método circundante.

¿Qué es «effectively final»?
Es una variable cuyo valor no cambia después de su inicialización. Por ejemplo:

void foo() {
    int x = 5; // effectively final
    class L { void print() { System.out.println(x); } }
}

Si más tarde escribieras x = 10;, el compilador se quejaría.

¿Por qué es así?

Se debe a cómo Java implementa las clases locales «bajo el capó»: las variables del método se copian de hecho dentro de la clase local, en lugar de almacenarse por referencia. Si la variable pudiera cambiar, la clase local podría trabajar con una copia obsoleta — y eso es camino seguro hacia errores y dolores de cabeza.

Ejemplo con acceso a variables

public class Outer {
    private String secret = "¡secreto!";

    void revealSecret() {
        String greeting = "Hola,"; // effectively final

        class Revealer {
            void printSecret() {
                System.out.println(greeting + " " + secret);
            }
        }

        Revealer revealer = new Revealer();
        revealer.printSecret();
    }
}

3. Uso de las clases locales: ¿para qué y cuándo?

Las clases locales no son una herramienta para todos los días, pero a veces hacen el código más limpio y compacto. He aquí cuándo conviene usarlas:

  • Lógica auxiliar específica de un único método.
    Por ejemplo, si en un método necesitas implementar una ordenación compleja, un filtrado o una estructura de datos temporal.
  • Encapsulación para no «ensuciar» la clase con tipos innecesarios.
    Si una clase solo se necesita en un lugar, ¿para qué hacerla visible en toda la clase o el paquete?
  • Implementación de patrones de diseño donde los objetos auxiliares solo se necesitan localmente.

Ejemplo: ordenación mediante una clase local

Supongamos que tienes una lista de nombres y quieres ordenarlos por longitud. Puedes crear una clase local comparadora:

import java.util.*;

public class NameSorter {
    public void sortNames(List<String> names) {
        class LengthComparator implements Comparator<String> {
            @Override
            public int compare(String a, String b) {
                return Integer.compare(a.length(), b.length());
            }
        }
        Collections.sort(names, new LengthComparator());
    }
}

Ejemplo: estructura temporal

A veces hace falta crear una estructura auxiliar para procesar datos en un único método:

void processScores(int[] scores) {
    class ScoreInfo {
        int score;
        boolean passed;

        ScoreInfo(int score) {
            this.score = score;
            this.passed = score >= 60;
        }
    }

    for (int s : scores) {
        ScoreInfo info = new ScoreInfo(s);
        System.out.println("Puntuación: " + info.score + ", aprobado: " + info.passed);
    }
}

4. Clases locales vs. clases anónimas

A veces surge la pregunta: ¿para qué hacen falta las clases locales si existen las anónimas? Vamos a verlo.

  • Clase local: es una clase con nombre que puedes usar varias veces en el método, añadirle campos, varios métodos y clases internas.
  • Clase anónima: es una implementación de un interfaz o un descendiente sin nombre y de un solo uso, normalmente con un método (o la sobrescritura de uno o dos métodos).

Cuándo usar cada una:

  • Si la lógica es simple y se necesita una sola vez, usa una clase anónima.
  • Si necesitas más métodos o campos, o la clase se usará en varios puntos del método, usa una clase local.

Ejemplo comparativo

Clase anónima:

Runnable r = new Runnable() {
    @Override
    public void run() {
        System.out.println("¡Rápido y anónimo!");
    }
};

Clase local:

void doWork() {
    class MyWorker implements Runnable {
        @Override
        public void run() {
            System.out.println("¡Soy una clase local!");
        }
    }
    MyWorker worker = new MyWorker();
    worker.run();
}

5. Restricciones y particularidades de las clases locales

  • Modificadores de acceso: Una clase local no puede declararse como public, private o protected. Tampoco se puede añadir static.
  • Miembros estáticos: Una clase local no puede contener miembros estáticos, excepto constantes (static final).
  • Ámbito de visibilidad: Una clase local solo es visible en el bloque donde se declara.
  • Uso de parámetros genéricos: Una clase local puede ser genérica si es necesario.
  • Anidamiento: Se pueden declarar clases locales dentro de otras clases locales (pero es mejor no abusar de ello, o el código se parecerá a una matrioska).

6. Clases locales en una aplicación real

Sigamos desarrollando nuestra aplicación educativa. Supongamos que tenemos la clase Quiz, que hace preguntas al usuario y comprueba las respuestas. Queremos crear dentro del método de comprobación una clase temporal que almacene la respuesta del usuario y el estado de la verificación.

Ejemplo: uso de una clase local en una aplicación

import java.util.Scanner;

public class Quiz {
    private String question = "¿Capital de Francia?";
    private String correctAnswer = "París";

    public void runQuiz() {
        Scanner scanner = new Scanner(System.in);

        System.out.println(question);
        String userAnswer = scanner.nextLine();

        // Clase local para almacenar el resultado
        class AnswerResult {
            String answer;
            boolean isCorrect;

            AnswerResult(String answer) {
                this.answer = answer;
                this.isCorrect = answer.equalsIgnoreCase(correctAnswer);
            }

            void printResult() {
                if (isCorrect) {
                    System.out.println("¡Correcto!");
                } else {
                    System.out.println("Incorrecto, la respuesta correcta es: " + correctAnswer);
                }
            }
        }

        AnswerResult result = new AnswerResult(userAnswer);
        result.printResult();
    }
}

Aquí la clase AnswerResult existe solo dentro del método runQuiz y no se necesita en ningún otro lugar. ¡Es un excelente ejemplo de clase local en la práctica!

7. Errores típicos al trabajar con clases locales

Error n.º 1: intentar acceder a una variable del método que no es final ni effectively final.
Si declaraste una variable en el método y luego cambias su valor después de usarla en la clase local, el compilador emitirá un error. Asegúrate siempre de que esas variables no cambian tras su inicialización.

Error n.º 2: querer añadir modificadores de acceso o static.
Una clase local no puede declararse con los modificadores public, private, protected ni con static. Si lo intentas — el compilador se opondrá.

Error n.º 3: intentar usar una clase local fuera del método.
Una clase local vive solo en el método (o bloque) donde se declara. No es accesible desde otros métodos ni desde fuera de la clase.

Error n.º 4: abusar de las clases locales para lógica compleja.
Si tu clase local se vuelve demasiado grande, contiene muchos métodos o campos, lo más probable es que debas extraerla a una clase independiente. Las clases locales son buenas para tareas auxiliares y compactas.

1
Tarea
JAVA 25 SELF, nivel 16, lección 3
Bloqueada
Tablón de anuncios interactivo: saludo temporal 👋
Tablón de anuncios interactivo: saludo temporal 👋
1
Tarea
JAVA 25 SELF, nivel 16, lección 3
Bloqueada
Guardián del secreto: revelación controlada 🔐
Guardián del secreto: revelación controlada 🔐
1
Tarea
JAVA 25 SELF, nivel 16, lección 3
Bloqueada
Calculadora especializada: visualización instantánea de la suma ➕
Calculadora especializada: visualización instantánea de la suma ➕
1
Tarea
JAVA 25 SELF, nivel 16, lección 3
Bloqueada
Analizador de datos de texto: informe breve por nombre 📊
Analizador de datos de texto: informe breve por nombre 📊
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION