CodeGym /Cursos /JAVA 25 SELF /Classes aninhadas estáticas (static nested)

Classes aninhadas estáticas (static nested)

JAVA 25 SELF
Nível 16 , Lição 1
Disponível

1. Classe aninhada estática

Classe aninhada estática (static nested class) — é uma classe declarada dentro de outra classe com o modificador static. Na essência, é uma classe comum que apenas “vive” dentro de outra classe, mas não está vinculada ao objeto dela.

Se a classe interna é como um irmão mais novo que sempre dá a mão ao mais velho (o objeto da classe externa), então a aninhada estática é como um primo que aparece só nas festas de família e, no resto do tempo, vive a própria vida.

Principais diferenças:

  • Não possui referência implícita ao objeto da classe externa — nada de OuterClass.this e sem acesso a membros não estáticos.
  • Pode conter membros estáticos (ao contrário da classe interna comum).
  • É criada sem um objeto da classe externa.

Sintaxe de declaração

Declarar uma classe aninhada estática é muito simples: usamos a palavra‑chave static dentro da classe externa.

class Outer {
    static class Nested {
        void print() {
            System.out.println("Hello from Nested!");
        }
    }
}

E só! Nada de construções sintáticas mirabolantes — apenas static class.

Visualização:

Outer (classe externa)
│
├── Nested (classe aninhada estática)
│      └── print()

2. Criação de instância da classe aninhada estática

O mais legal: não é necessário um objeto da classe externa!

Outer.Nested nested = new Outer.Nested();
nested.print(); // Hello from Nested!

Observe que usamos o nome completo da classe — Outer.Nested. É como se referir à classe aninhada pelo sobrenome: “Smith.Son”.

Compare com a classe interna (inner):

Outer outer = new Outer();
Outer.Inner inner = outer.new Inner(); // precisa do objeto outer

Já para a static nested — o objeto Outer não é necessário!

3. Acesso aos membros da classe externa

É aqui que está a principal diferença em relação à classe interna.

  • A classe aninhada estática tem acesso SOMENTE aos membros estáticos da classe externa.
  • Não é possível acessar campos e métodos não estáticos (mesmo que sejam public).

Exemplo:

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); // Erro!
        }
    }
}

Se você tentar acessar o campo não estático instanceValue, o compilador reclamará imediatamente.

Por que isso? Porque a static nested class não “sabe” a qual objeto Outer deve ser associada — ela não tem referência ao objeto da classe externa.

4. Quando usar classes aninhadas estáticas

Quando são apropriadas?

  • Quando a classe aninhada está logicamente relacionada à externa, mas não precisa de acesso ao objeto da classe externa.
  • Quando você quer encapsular uma estrutura auxiliar: por exemplo, um builder, utilitário, enumeração ou até um pequeno objeto imutável.
  • Quando é preciso reduzir a “poluição” do pacote: a classe é necessária apenas para a classe externa, não faz sentido levá-la para fora.

Cenários típicos:

  • Padrão Builder (especialmente para objetos imutáveis)
  • Implementação de estruturas auxiliares: por exemplo, classes Node internas em coleções
  • Agrupamento de constantes ou utilitários

Regra simples de escolha
Faça a si mesmo a pergunta: “A minha classe aninhada precisa de acesso a um objeto específico da classe externa?”
NÃO → use static class (classe aninhada estática)
SIM → use uma class comum (interna)

5. Exemplos de uso

Exemplo 1: Builder para uma classe

Suponha que temos a classe Person e queremos implementar o padrão Builder para ela:

public class Person {
    private final String name;
    private final int age;

    // Construtor privado
    private Person(Builder builder) {
        this.name = builder.name;
        this.age = builder.age;
    }

    // Classe aninhada 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("Ivan")
    .setAge(30)
    .build();

person.printInfo(); // Person: Ivan, 30

Por que o Builder é uma classe aninhada estática?
Porque ele não depende de um objeto Person, apenas ajuda a criá-lo. Ele está logicamente ligado a Person, mas não a uma instância específica.

Exemplo 2: Estrutura auxiliar dentro de uma coleção

Imagine uma classe “caixa de inteiros”, em que para armazenar os elementos é usada uma classe estática interna Node:

public class IntBox {
    private Node head;

    // Classe estática aninhada
    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 que Node é static?
Porque cada Node não precisa conhecer toda a caixa (IntBox); ele apenas armazena os dados e a referência para o próximo Node.

Exemplo 3: Classe utilitária dentro da principal

public class MathUtils {
    // Classe aninhada estática para trabalhar com números complexos
    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. Nuances úteis

Classe interna vs classe aninhada estática

Classe interna (inner) Classe aninhada estática (static nested)
Palavra‑chave nenhuma
static
Referência implícita ao objeto externo sim não
Acesso aos membros não estáticos da classe externa sim não
Acesso aos membros estáticos da classe externa sim sim
Pode conter membros estáticos não (apenas constantes) sim
Sintaxe de criação
outer.new Inner()
new Outer.Nested()
Uso Quando é necessário acessar o objeto da classe externa Quando não é necessário acessar o objeto da classe externa

Ilustração

flowchart LR
    OuterClass -->|has| InnerClass
    OuterClass -.->|has| StaticNestedClass
    StaticNestedClass -.->|can access| staticMembers
    InnerClass -->|can access| instanceMembers
    InnerClass -->|can access| staticMembers

Características e limitações

  • Static nested class pode conter tanto campos e métodos comuns quanto estáticos.
  • Pode ser declarada com qualquer modificador de acesso (public, private, protected, package‑private).
  • Pode implementar interfaces e herdar de outras classes.
  • Pode ser generic.
  • Normalmente é usada para encapsular classes de suporte que não são necessárias fora da classe externa.

Exemplo de classe aninhada 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; }
    }
}

Quando NÃO usar classe aninhada estática

  • Se a classe aninhada precisar de acesso a campos/métodos não estáticos da classe externa — use uma inner class comum.
  • Se a classe for necessária fora da classe externa — extraia para um arquivo separado.
  • Se a classe for grande ou complexa demais — melhor torná-la separada.

7. Erros comuns e nuances

Erro nº 1: Confusão entre inner e classe aninhada estática.
Muitos iniciantes tentam acessar, a partir de uma classe aninhada estática, campos não estáticos da classe externa. Mas a static nested class não possui referência ao objeto da classe externa, portanto isso é impossível. Se você precisa acessar o estado de um objeto específico — use uma inner class comum.

Erro nº 2: Tentar criar uma classe aninhada estática por meio de um objeto da classe externa.
Não há necessidade de escrever outer.new Inner(). Para uma static nested class, sempre use new Outer.Nested().

Erro nº 3: Usar uma classe aninhada estática para lógica que exige acesso à instância da classe externa.
Se a lógica da classe está fortemente ligada ao estado do objeto externo, a static nested class é uma má escolha. Use uma classe interna comum.

Erro nº 4: Aninhamento excessivamente complexo.
Não exagere no uso de classes aninhadas. Se a estrutura começar a ficar confusa, é melhor extrair parte das classes para fora.

Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION