Clases anidadas en Java: ¿cómo empezó todo?
Imagina: estás escribiendo código en Java y de repente te das cuenta de que una clase está lógicamente e inseparablemente vinculada a otra. Por ejemplo, Car y Engine. El motor no existe por sí solo, es parte del coche. ¿Cómo modelar esto de forma elegante y correcta en Java? La respuesta son las clases anidadas (nested classes).
El tema Java inner class and static nested class es uno de los más frecuentes en Stack Overflow. Miles de desarrolladores se confunden: ¿cuál es la diferencia? ¿Cuándo usar inner y cuándo static nested? ¿Por qué se inventaron?
En este tutorial lo desglosaremos todo. No solo aprenderás la sintaxis, sino que entenderás la lógica de los diseñadores de Java. ¡Allá vamos!
¿Qué es una nested class (clase anidada)?
Empecemos por lo básico. Una nested class es una clase declarada dentro de otra clase. En Java hay cuatro tipos de clases anidadas, pero hoy nos interesan las dos más populares:
- Static nested class (clase anidada estática)
- Inner class (clase interna, también conocida como non-static nested class)
La diferencia clave es el modificador static. Esto lo cambia todo: desde el acceso a los campos hasta el tiempo de vida del objeto. Vamos a analizarlo en la práctica.
Static nested class: simple e independiente
Una clase anidada estática se comporta como una clase externa normal, pero "vive" dentro de su clase padre. No tiene acceso a los campos y métodos no estáticos de la clase externa (a menos que reciba una referencia al objeto).
Ejemplo del mundo real: Database y DatabaseConfig. La configuración no está vinculada a una instancia específica de la base de datos.
public class Database { private String url; private static String defaultDriver = "com.mysql.cj.jdbc.Driver";
public Database(String url) { this.url = url; }
// Static nested class public static class DatabaseConfig { private String driver; private int poolSize;
public DatabaseConfig(String driver, int poolSize) { this.driver = driver; this.poolSize = poolSize; }
public void printConfig() { // Solo tiene acceso a los miembros estáticos de la clase externa System.out.println("Default driver: " + defaultDriver); // System.out.println(url); // ¡ERROR! url es un campo no estático }
public static void staticMethodInNested() { System.out.println("Método estático en una clase anidada estática"); } }
public void useConfig() { // Creamos una instancia de la static nested class DatabaseConfig config = new DatabaseConfig("oracle.jdbc.OracleDriver", 10); config.printConfig(); }}Observa: para crear DatabaseConfig no necesitamos un objeto Database. Esta es la principal ventaja: la independencia.
¿Cuándo usar static nested class?
- Cuando la clase anidada está lógicamente relacionada con la externa, pero no depende de su instancia.
- Cuando necesitas agrupar clases auxiliares (builders, configuraciones, utilidades).
- Cuando diseñas el patrón Builder — un ejemplo clásico.
Inner class (non-static nested class): vinculadas para siempre
La clase interna es todo lo contrario. Siempre está vinculada a un objeto específico de la clase externa. Esto significa:
- Tiene acceso a todos los campos y métodos de la clase externa (incluso privados).
- No puede existir sin una instancia de la clase externa.
- Almacena implícitamente una referencia al objeto externo (
OuterClass.this).
Ejemplo: Car y Engine. Cada coche