Sobes.tech
Middle

Fale sobre classes aninhadas e em que casos elas são aplicadas.

sobes.tech IA

Resposta da IA

As classes aninhadas (Nested Classes) em Java são classes definidas dentro de outra classe. Elas dividem-se em dois tipos: estáticas (Static Nested Classes) e internas (Inner Classes).

Classes aninhadas estáticas

  • Declaradas com o modificador static.
  • Têm acesso apenas aos membros estáticos da classe externa (mesmo os ocultos).
  • Não têm acesso aos membros não estáticos da classe externa.
  • Para criar uma instância de uma classe aninhada estática, não é necessária uma instância da classe externa:
    // Classe externa
    class Outer {
        static int outerStaticField;
        int outerInstanceField;
    
        // Classe aninhada estática
        static class StaticNested {
            void accessOuter() {
                // Acesso ao campo estático da classe externa
                System.out.println(Outer.outerStaticField);
                // Sem acesso a outerInstanceField
                // System.out.println(outerInstanceField); // Erro de compilação
            }
        }
    }
    
    // Uso da classe aninhada estática
    class Main {
        public static void main(String[] args) {
            Outer.StaticNested nestedObject = new Outer.StaticNested();
            nestedObject.accessOuter();
        }
    }
    

Classes internas

  • Não são declaradas com o modificador static.
  • Têm acesso completo a todos os membros da classe externa (estáticos e não estáticos, mesmo os ocultos).
  • Uma instância da classe interna não pode existir sem uma instância da classe externa.
  • Para criar uma instância da classe interna, é necessária uma instância da classe externa:
    // Classe externa
    class Outer {
        static int outerStaticField;
        int outerInstanceField;
    
        // Classe interna
        class Inner {
            void accessOuter() {
                // Acesso ao campo estático da classe externa
                System.out.println(Outer.outerStaticField);
                // Acesso ao campo não estático da classe externa
                System.out.println(outerInstanceField);
            }
        }
    }
    
    // Uso da classe interna
    class Main {
        public static void main(String[] args) {
            Outer outerObject = new Outer();
            Outer.Inner innerObject = outerObject.new Inner();
            innerObject.accessOuter();
        }
    }
    

As classes internas subdividem-se em:

  • Classes internas regulares: Definidas diretamente dentro do corpo da classe externa.
  • Classes internas locais: Definidas dentro de métodos, construtores ou blocos de inicialização. São visíveis apenas dentro desse bloco.
    class Outer {
        void display() {
            class LocalInner { // Classe interna local
                void message() {
                    System.out.println("Classe interna local");
                }
            }
            LocalInner obj = new LocalInner();
            obj.message();
        }
    }
    
  • Classes internas anónimas: Classes sem nome, usadas para criar uma instância de uma classe ou interface e fornecer sua implementação imediatamente. São frequentemente usadas com ouvintes de eventos.
    interface Greeting {
        void sayHello();
    }
    
    class Main {
        public static void main(String[] args) {
            Greeting greeting = new Greeting() { // Classe interna anónima
                @Override
                public void sayHello() {
                    System.out.println("Olá!");
                }
            };
            greeting.sayHello();
        }
    }
    

Quando aplicar classes aninhadas:

  • Agrupamento lógico: Se uma classe faz parte apenas de outra classe e faz sentido agrupá-las juntas. Isso melhora a legibilidade e a manutenção do código.
  • Encapsulamento: As classes aninhadas podem acessar os membros da classe externa, o que garante uma relação mais estreita e a capacidade de esconder detalhes de implementação.
  • Código mais legível: Quando uma pequena classe simples é usada apenas em um lugar, aninhá-la pode tornar o código mais organizado.
  • Uso eficiente de recursos: As classes internas têm acesso aos membros da classe externa sem necessidade de passá-los explicitamente, o que pode simplificar o código. Um exemplo é a implementação de iteradores.
  • Implementação de interfaces ou extensão de classes no contexto: As classes internas anónimas são frequentemente usadas para fornecer uma implementação compacta de interfaces ou classes abstratas "em tempo real".
  • Ocultamento de implementação: Ocultar uma classe dentro de outra, tornando-a invisível de fora.

Comparação entre classes aninhadas estáticas e internas:

Parâmetro Classe aninhada estática Classe interna
Modificador static Sim Não
Acesso aos membros da classe externa Apenas estáticos (mesmo privados) Todos os membros (estáticos e não estáticos, privados)
Requer uma instância da classe externa para criar Não Sim
Relação com a instância da classe externa Não Sim

A escolha entre uma classe aninhada estática e uma interna depende de se a classe interna precisa de acesso aos membros não estáticos da classe externa. Se precisar, use a classe interna. Caso contrário, a classe aninhada estática é uma escolha mais adequada, pois não está vinculada a uma instância da classe externa e pode ser mais eficiente.