HOWTO · Java

Clase interna y clase anidada estática en Java

En la programación de computadoras, una clase es un modelo que nos permite crear objetos de clase individuales para acceder a datos de miembros de datos o funciones de miembros. En programación Java, una clase se define con la palabra clave class. También podemos decir que una clase es un tipo de datos definido por el usuario con modificaciones personalizadas.

En esta página

Una clase anidada se declara dentro de otra clase. Java admite clases anidadas static y clases anidadas que no son static (clases internas). Usa una clase anidada static cuando el tipo pertenezca conceptualmente a su clase contenedora, pero no necesite un objeto contenedor. La palabra clave static describe esa relación; no convierte el tipo anidado en una clase de nivel superior ni crea una barrera de seguridad.

Clases anidadas estáticas en Java

Una clase anidada static es un tipo miembro declarado dentro de otra clase mediante la palabra clave static. Se puede nombrar junto con el tipo contenedor, por ejemplo, Envelope.Label, y crear una instancia sin crear primero un objeto Envelope. Esto resulta útil cuando una clase auxiliar o un tipo de valor está estrechamente relacionado con una clase y no tiene sentido como tipo de nivel superior independiente.

El tipo anidado sigue teniendo sus propias instancias. Declarar la clase anidada como static no hace que sus campos ni sus métodos sean static. La clase anidada puede tener sus propios constructores, estado de instancia y métodos, igual que una clase de nivel superior.

Relación entre las clases anidadas estáticas y su clase contenedora

Una clase anidada static no tiene una referencia implícita a una instancia de la clase contenedora. Puede acceder directamente a los miembros static de esa clase, incluidos sus miembros privados static. No puede usar directamente un campo o método de instancia de la clase contenedora, porque no está asociada a ningún objeto contenedor. Si necesita esos datos, pasa un objeto contenedor a un constructor o método y accede al miembro mediante esa referencia.

La relación de acceso inversa también es útil: el código de la clase contenedora puede trabajar con la clase anidada, incluidos sus miembros privados, conforme a las reglas de acceso habituales de Java. La visibilidad privada determina qué código puede nombrar un miembro; no debe presentarse como una característica de seguridad.

Declarar e instanciar una clase anidada estática

Declara el tipo en el cuerpo de la clase contenedora mediante static class Label. Desde fuera de la clase contenedora, haz referencia a él como Envelope.Label. El siguiente ejemplo completo mantiene agrupado el tipo de valor anidado con la clase que lo utiliza y lo crea directamente desde main:

Ejecuta este ejemplo:

El código y las etiquetas o salidas visibles de esta sección se mantienen en inglés.

public class Main {
    static class Label {
        private final String text;

        Label(String text) {
            this.text = text;
        }

        String display() {
            return "Label: " + text;
        }
    }

    public static void main(String[] args) {
        Label label = new Label("priority");
        System.out.println(label.display());
    }
}
Label: priority

Como main es un método static, crea Label sin instanciar Main. El código de otra clase puede usar el nombre cualificado Main.Label y llamar a un constructor con acceso adecuado. Si una clase anidada necesita información de un objeto contenedor concreto, haz explícita esa dependencia pasando el objeto. La salida mostrada es Label: priority; la etiqueta Label: permanece en inglés.

Clases anidadas estáticas frente a clases internas

Una clase interna es una clase miembro que no es static. Cada objeto de una clase interna está asociado a una instancia de su clase contenedora, y su código puede referirse directamente a los miembros de esa instancia contenedora. Para crear una desde fuera de la clase contenedora, primero crea el objeto externo y luego usa la forma outer.new Inner(); el tipo interno se nombra como Outer.Inner.

Una clase anidada static no tiene esa asociación, así que para crearla no se usa un objeto contenedor: desde fuera, usa new Outer.Nested(), o el nombre abreviado si está dentro del ámbito. Según la API prevista, ambas formas pueden ser privadas o públicas, y ambas pueden acceder a miembros privados de la clase contenedora. La diferencia radica en la relación implícita con una instancia contenedora, no en un nivel especial de seguridad.

Cuándo usar una clase anidada estática

Elige una clase anidada static cuando el tipo anidado forme parte lógica de su clase contenedora, pero cada instancia pueda funcionar sin un objeto contenedor implícito. Algunos casos adecuados son un tipo de valor pequeño, un constructor de objetos o una clase auxiliar cuyo propósito sea específico de una API contenedora. Una clase anidada static también puede recibir dependencias explícitamente, lo que permite que quienes la usan vean esos requisitos.

Elige una clase interna cuando cada instancia deba trabajar con el objeto contenedor concreto que la creó; por ejemplo, si necesita leer o actualizar el estado de instancia de ese objeto. Si el tipo tiene una función independiente y amplia, una clase de nivel superior puede ser más fácil de reutilizar y encontrar. Decide según la relación que necesite el código y elige después la visibilidad más restrictiva que permita el uso previsto.