Clases Internas en Java Explicadas: Diseño, Sintaxis y Usos Prácticos
En Java, al igual que los métodos y variables, una clase puede tener otra clase como miembro. Escribir una clase dentro de otra está permitido. La clase interna se llama clase anidada (nested class), y la que la contiene es la clase externa (outer class).
Tipos de Clases Anidadas
- Clases anidadas no estáticas (Inner Classes): Miembros de instancia de la clase externa.
- Clases anidadas estáticas (Static Nested Classes): Miembros estáticos de la clase externa.
Clases Internas (Inner Classes / Non-static Nested Classes)
Son un mecanismo de seguridad: una clase normal no puede ser private, pero una clase interna sí. Además, pueden acceder a los miembros private de la clase externa.
Existen tres tipos según dónde y cómo se definen:
- Clase Interna (Miembro)
- Clase Interna Local a un Método (Method-local Inner Class)
- Clase Interna Anónima (Anonymous Inner Class)
1. Clase Interna (Miembro)
Se define como miembro de la clase externa. Puede ser private.
Ejemplo: Clase interna privada accedida vía método
class Outer_Demo {
int num;
// clase interna privada
private class Inner_Demo {
public void print() {
System.out.println("Esta es una clase interna");
}
}
// método para acceder a la clase interna
void display_Inner() {
Inner_Demo inner = new Inner_Demo();
inner.print();
}
}
public class My_class {
public static void main(String args[]) {
Outer_Demo outer = new Outer_Demo();
outer.display_Inner();
}
}
Salida: Esta es una clase interna.
Acceso a Miembros Privados de la Clase Externa
La clase interna puede acceder directamente a campos private de la externa.
class Outer_Demo {
private int num = 175;
public class Inner_Demo {
public int getNum() {
System.out.println("Método getNum de la clase interna");
return num; // acceso directo a private de Outer_Demo
}
}
}
public class My_class2 {
public static void main(String args[]) {
Outer_Demo outer = new Outer_Demo();
Outer_Demo.Inner_Demo inner = outer.new Inner_Demo();
System.out.println(inner.getNum());
}
}
Salida: Método getNum de la clase interna: 175
Nota: Para instanciar una clase interna no estática: OuterClass.InnerClass inner = outerObj.new InnerClass();
2. Clase Interna Local a un Método (Method-local Inner Class)
Se define dentro de un método. Su ámbito se restringe a ese método. Solo puede instanciarse dentro del método.
Ejemplo
public class Outerclass {
void my_Method() {
int num = 23;
class MethodInner_Demo {
public void print() {
System.out.println("Esta es una clase interna de método " + num);
}
}
MethodInner_Demo inner = new MethodInner_Demo();
inner.print();
}
public static void main(String args[]) {
Outerclass outer = new Outerclass();
outer.my_Method();
}
}
Salida: Esta es una clase interna de método 23
3. Clase Interna Anónima (Anonymous Inner Class)
Clase sin nombre, declarada e instanciada a la vez. Usada típicamente para sobrescribir métodos de una clase o interfaz.
Sintaxis
InterfaceType obj = new InterfaceType() {
@Override
public void method() {
// implementación
}
};
Ejemplo: Sobrescribir método de clase abstracta
abstract class AnonymousInner {
public abstract void mymethod();
}
public class Outer_class {
public static void main(String args[]) {
AnonymousInner inner = new AnonymousInner() {
public void mymethod() {
System.out.println("Ejemplo de clase interna anónima");
}
};
inner.mymethod();
}
}
Salida: Ejemplo de clase interna anónima
Clase Interna Anónima como Argumento
Si un método acepta una interfaz o clase abstracta, puedes pasar una implementación anónima directamente.
Ejemplo
interface Message {
String greet();
}
public class My_class {
public void displayMessage(Message m) {
System.out.println(m.greet() + ", ejemplo de clase anónima como argumento");
}
public static void main(String args[]) {
My_class obj = new My_class();
obj.displayMessage(new Message() {
public String greet() {
return "Hola";
}
});
}
}
Salida: Hola, ejemplo de clase anónima como argumento
Clase Anidada Estática (Static Nested Class)
Es un miembro static de la clase externa. No requiere instancia de la externa para crearse. No tiene acceso a miembros de instancia (no static) de la clase externa, solo a los estáticos.
Sintaxis
class MyOuter {
static class Nested_Demo {
public void my_method() {
System.out.println("Esta es mi clase anidada estática");
}
}
}
Instanciación
public class Outer {
static class Nested_Demo {
public void my_method() {
System.out.println("Esta es mi clase anidada");
}
}
public static void main(String args[]) {
Outer.Nested_Demo nested = new Outer.Nested_Demo(); // sin instancia de Outer
nested.my_method();
}
}
Salida: Esta es mi clase anidada
Resumen de Diferencias Clave
| Característica | Inner Class (No Estática) | Static Nested Class |
|---|---|---|
| Acceso a miembros de instancia de la externa | Sí (incluyendo private) | No |
| Requiere instancia de la externa | Sí | No |
| Puede ser private/protected | Sí | Sí |
| Uso típico | Acoplamiento fuerte, acceso a estado externo | Agrupamiento lógico, comportamiento independiente |
Java
- Palabra clave final en Java: Variables, métodos y clases
- Operador instanceof en Java: Guía completa
- Dominando clases anidadas e internas en Java: Tipos, ejemplos y mejores prácticas
- Entendiendo las clases anidadas estáticas en Java: Uso, diferencias y ejemplos
- Dominando las clases internas anónimas en Java: Definición, sintaxis y ejemplos prácticos
- Patrón Singleton en Java explicado: Cómo implementarlo y usarlo de forma segura
- Dominando la Reflexión en Java: Inspeccionando clases, métodos y campos en tiempo de ejecución
- Dominando ObjectOutputStream de Java: Serialización, Métodos y Ejemplos Prácticos
- Dominando Java Generics: Construyendo Código Reutilizable y Type-Safe
- Dominando las operaciones de archivos en Java con java.io: creación, lectura, escritura y eliminación
- Domina Java: Entendiendo Objetos, Clases y Conceptos Básicos de POO