CodeGym /Cursos /JAVA 25 SELF /Clases anidadas estáticas (static nested)

Clases anidadas estáticas (static nested)

JAVA 25 SELF
Nivel 16 , Lección 1
Disponible

1. Clase anidada estática

Una clase anidada estática (static nested class) es una clase declarada dentro de otra clase con el modificador static. En esencia, es una clase normal que simplemente «vive» dentro de otra clase, pero no está vinculada al objeto de esta.

Si una clase interna es como un hermano pequeño que siempre va de la mano del mayor (del objeto de la clase externa), la anidada estática es como un primo que solo viene a las fiestas familiares y el resto del tiempo vive su propia vida.

Diferencias clave:

  • No tiene una referencia implícita al objeto de la clase externa — nada de OuterClass.this ni acceso a miembros no estáticos.
  • Puede contener miembros estáticos (a diferencia de una clase interna normal).
  • Se crea sin un objeto de la clase externa.

Sintaxis de declaración

Declarar una clase anidada estática es muy sencillo: usamos la palabra clave static dentro de la clase externa.

class Outer {
    static class Nested {
        void print() {
            System.out.println("Hello from Nested!");
        }
    }
}

¡Y eso es todo! Nada de construcciones sintácticas rebuscadas — simplemente static class.

Visualización:

Outer (clase externa)
│
├── Nested (static nested class)
│      └── print()

2. Creación de una instancia de una clase anidada estática

Lo mejor: ¡no necesitas un objeto de la clase externa!

Outer.Nested nested = new Outer.Nested();
nested.print(); // Hello from Nested!

Fíjate: usamos el nombre completo de la clase — Outer.Nested. Es como dirigirte a la clase anidada usando el apellido: «Smith.Hijo».

Compáralo con una clase interna (inner):

Outer outer = new Outer();
Outer.Inner inner = outer.new Inner(); // se necesita el objeto outer

¡Y para static nested no se necesita en absoluto un objeto Outer!

3. Acceso a los miembros de la clase externa

Aquí está la diferencia principal respecto a la clase interna.

  • La clase anidada estática solo tiene acceso a los miembros estáticos de la clase externa.
  • No puede acceder a campos y métodos no estáticos (aunque sean public).

Ejemplo:

class Outer {
    private static int staticValue = 10;
    private int instanceValue = 20;

    static class Nested {
        void show() {
            System.out.println("Static value: " + staticValue); // OK
            // System.out.println("Instance value: " + instanceValue); // ¡Error!
        }
    }
}

Si intentas acceder al campo no estático instanceValue, el compilador te dará una buena charla.

¿Por qué? Porque una static nested class no «sabe» con qué objeto Outer debe vincularse — no tiene referencia al objeto de la clase externa.

4. Cuándo usar clases anidadas estáticas

¿Cuándo son apropiadas?

  • Cuando la clase anidada está lógicamente relacionada con la externa, pero no necesita acceder al objeto de la clase externa.
  • Cuando quieres encapsular una estructura auxiliar: por ejemplo, un builder, una utilidad, una enumeración o incluso un pequeño objeto inmutable.
  • Cuando necesitas reducir la “contaminación” del paquete: la clase solo la usa la clase externa y no tiene sentido sacarla fuera.

Escenarios típicos:

  • Patrón Builder (especialmente para objetos inmutables)
  • Implementación de estructuras auxiliares: por ejemplo, clases Node internas en colecciones
  • Agrupación de constantes o utilidades

Regla simple para decidir
Hazte esta pregunta: «¿Necesita mi clase anidada acceso a un objeto concreto de la clase externa?»
NO → usa static class (clase anidada estática)
→ usa una class normal (clase interna)

5. Ejemplos de uso

Ejemplo 1: Builder para una clase

Supongamos que tenemos una clase Person y queremos implementar para ella el patrón Builder:

public class Person {
    private final String name;
    private final int age;

    // Constructor privado
    private Person(Builder builder) {
        this.name = builder.name;
        this.age = builder.age;
    }

    // Clase anidada estática Builder
    public static class Builder {
        private String name;
        private int age;

        public Builder setName(String name) {
            this.name = name;
            return this;
        }

        public Builder setAge(int age) {
            this.age = age;
            return this;
        }

        public Person build() {
            return new Person(this);
        }
    }

    public void printInfo() {
        System.out.println("Person: " + name + ", " + age);
    }
}

Uso:

Person person = new Person.Builder()
    .setName("Iván")
    .setAge(30)
    .build();

person.printInfo(); // Person: Iván, 30

¿Por qué Builder es una clase anidada estática?
Porque no depende de un objeto Person, solo ayuda a crearlo. Está lógicamente relacionado con Person, pero no con una instancia concreta.

Ejemplo 2: Estructura auxiliar dentro de una colección

Imaginemos una clase «caja de enteros», donde para almacenar elementos se usa una clase estática anidada interna Node:

public class IntBox {
    private Node head;

    // Clase anidada estática
    private static class Node {
        int value;
        Node next;

        Node(int value) {
            this.value = value;
        }
    }

    public void add(int value) {
        Node node = new Node(value);
        node.next = head;
        head = node;
    }

    public void printAll() {
        Node current = head;
        while (current != null) {
            System.out.println(current.value);
            current = current.next;
        }
    }
}

Uso:

IntBox box = new IntBox();
box.add(1);
box.add(2);
box.add(3);
box.printAll(); // 3 2 1

¿Por qué Node es static?
Porque cada Node no debe conocer toda la caja (IntBox), solo almacena datos y una referencia al siguiente Node.

Ejemplo 3: Clase de utilidades dentro de la principal

public class MathUtils {
    // Clase anidada estática para trabajar con números complejos
    public static class Complex {
        private final double re;
        private final double im;

        public Complex(double re, double im) {
            this.re = re;
            this.im = im;
        }

        public Complex add(Complex other) {
            return new Complex(this.re + other.re, this.im + other.im);
        }

        @Override
        public String toString() {
            return re + " + " + im + "i";
        }
    }
}

Uso:

MathUtils.Complex a = new MathUtils.Complex(1, 2);
MathUtils.Complex b = new MathUtils.Complex(3, 4);
MathUtils.Complex sum = a.add(b);
System.out.println(sum); // 4.0 + 6.0i

6. Matices útiles

Clase interna vs clase anidada estática

Clase interna (inner) Anidada estática (static nested)
Palabra clave no
static
Referencia implícita al objeto externo no
Acceso a los miembros no estáticos de la clase externa no
Acceso a los miembros estáticos de la clase externa
Puede contener miembros estáticos no (solo constantes)
Sintaxis de creación
outer.new Inner()
new Outer.Nested()
Uso Cuando se necesita acceder al objeto de la clase externa Cuando no se necesita acceder al objeto de la clase externa

Ilustración

flowchart LR
    OuterClass -->|has| InnerClass
    OuterClass -.->|has| StaticNestedClass
    StaticNestedClass -.->|can access| staticMembers
    InnerClass -->|can access| instanceMembers
    InnerClass -->|can access| staticMembers

Características y limitaciones

  • Static nested class puede contener tanto campos y métodos normales como estáticos.
  • Puede declararse con cualquier modificador de acceso (public, private, protected, package-private).
  • Puede implementar interfaces y heredar de otras clases.
  • Puede ser generic.
  • Se usa normalmente para encapsular clases de soporte que no se necesitan fuera de la clase externa.

Ejemplo de clase anidada estática genérica:

public class Box {
    public static class Holder<T> {
        private T value;
        public Holder(T value) { this.value = value; }
        public T get() { return value; }
    }
}

Cuándo NO conviene usar una clase anidada estática

  • Si la clase anidada necesita acceso a campos/métodos no estáticos de la clase externa — usa una clase interna.
  • Si la clase se necesita fuera de la clase externa — muévela a un archivo aparte.
  • Si la clase es demasiado grande o compleja — mejor hazla independiente.

7. Errores típicos y matices

Error n.º 1: Confusión entre una clase interna y una clase anidada estática.
Muchos principiantes intentan, en una static nested class, acceder a miembros no estáticos de la clase externa. Pero una static nested class no tiene referencia al objeto de la clase externa, por lo que es imposible. Si necesitas acceso al estado de un objeto concreto, usa una clase interna normal.

Error n.º 2: Intentar crear una clase anidada estática a través de un objeto de la clase externa.
No hace falta escribir outer.new Inner(). Para una static nested class, usa siempre new Outer.Nested().

Error n.º 3: Usar una clase anidada estática para lógica que requiere acceso a la instancia de la clase externa.
Si la lógica de la clase está estrechamente ligada al estado del objeto de la clase externa, una static nested class es una mala elección. Usa una clase interna normal.

Error n.º 4: Anidamiento excesivamente complejo.
No abuses de las clases anidadas. Si la estructura se vuelve enrevesada, es mejor extraer parte de las clases.

Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION