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)
SÍ → 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 | |
| Referencia implícita al objeto externo | sí | no |
| Acceso a los miembros no estáticos de la clase externa | sí | no |
| Acceso a los miembros estáticos de la clase externa | sí | sí |
| Puede contener miembros estáticos | no (solo constantes) | sí |
| Sintaxis de creación | |
|
| 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.
GO TO FULL VERSION