En muchos lenguajes podemos anidar clases dentro de otras, pero no siempre significan lo mismo ni tienen las mismas capacidades. Veamos la comparación entre Java y C#.
Java tiene Inner Classes. Cuando declaramos una clase dentro de otra, tenemos dos opciones principales:
Static nested class: funciona como una clase estática, no tiene referencia a la instancia externa.
Inner class (no estática): mantiene una referencia implícita a la instancia de la clase que la contiene.
Esto permite escribir cosas como:
class Contenedora {
private int valor = 42;
class Inner {
void mostrar() {
// Acceso implícito a la instancia externa
System.out.println("Valor: " + Contenedora.this.valor);
}
}
public static void main(String[] args) {
Contenedora c = new Contenedora();
Contenedora.Inner i = c.new Inner();
i.mostrar(); // Valor: 42
}
}
Aquí, Contenedora.this es una referencia implícita que permite acceder directamente a la instancia de la clase externa.
En C# tenemos Nested Classes. En C#, todas las clases anidadas son conceptualmente clases estáticas (aunque no las declares static).
Esto significa que no existe referencia implícita a la instancia externa.
Ejemplo equivalente en C#:
public class Contenedora
{
private int valor = 42;
public class Nested
{
// No existe "Contenedora.this"
public void Mostrar(Contenedora externa)
{
Console.WriteLine($"Valor: {externa.valor}");
}
}
public static void Main()
{
var c = new Contenedora();
var n = new Nested();
n.Mostrar(c); // Valor: 42
}
}
Si querés acceder a los atributos de la clase externa, tenés que pasar explícitamente la referencia (Contenedora externa en este caso).
Entonces, Java Inner Class:
- Tiene un puntero implícito a la instancia externa.
- Podés usar Outer.this.atributo.
- Muy útil en callbacks o cuando la clase interna depende fuertemente de la externa.
C# Nested Class:
- No tiene referencia implícita.
- No existe Outer.this.
- Son más “independientes”, como una clase estática que solo vive en el scope de otra.
¿Por qué esta diferencia?
- Java diseñó las inner classes como un mecanismo para trabajar con GUI y callbacks (ejemplo clásico: listeners en Swing). Por eso necesitan la referencia a la instancia externa.
- C# tomó otro camino: sus delegates y lambdas con closures resuelven ese escenario sin necesidad de que las nested classes tengan referencia implícita.