Dominando Classes Aninhadas e Internas em Java: Tipos, Exemplos e Boas Práticas
Classes Aninhadas e Internas em Java
Descubra como as classes aninhadas do Java aprimoram encapsulamento, melhoram legibilidade e permitem poderosos padrões de inner classes.
Em Java você pode declarar uma classe dentro de outra classe — isso é chamado de classe aninhada. Por exemplo:
class ClasseExterna { // ... class ClasseAninhada { // ... } }
Existem dois sabores principais de classes aninhadas:
- Classe aninhada não-estática (comumente conhecida como inner class)
- Classe aninhada estática
Leitura recomendada:
- Modificadores de Acesso em Java
- Palavra-chave Static em Java
Classe Aninhada Não-Estática (Inner Class)
Uma inner class reside dentro de uma classe externa e pode acessar livremente os membros da classe externa, até mesmo os privados. Como está ligada a uma instância da classe externa, você deve instanciar a classe externa primeiro.
Exemplo 1: Inner Class
class CPU { double preco; // inner class class Processador{ double nucleos; String fabricante; double getCache(){ return 4.3; } } // inner class protected protected class RAM{ double memoria; String fabricante; double getClockSpeed(){ return 5.5; } } } public class Main { public static void main(String[] args) { CPU cpu = new CPU(); CPU.Processador processador = cpu.new Processador(); CPU.RAM ram = cpu.new RAM(); System.out.println("Cache do Processador = " + processador.getCache()); System.out.println("Clock speed da RAM = " + ram.getClockSpeed()); } }
Saída:
Cache do Processador = 4.3 Clock speed da RAM = 5.5
Aqui, Processador e RAM são aninhadas dentro de CPU. A classe RAM é declarada protected, demonstrando que inner classes podem usar qualquer modificador de acesso Java.
Em Main, primeiro instanciamos a classe externa CPU, então criamos instâncias de inner class via a instância externa:
CPU.Processador processador = cpu.new Processador(); CPU.RAM ram = cpu.new RAM();
Dica: O operador ponto (.) é usado para vincular uma instância de inner class à sua instância externa.
Acessando Membros da Classe Externa de uma Inner Class
Inner classes podem referenciar membros da classe externa através da palavra-chave this prefixada com o nome da classe externa, ex: Carro.this.tipoCarro. Esta sintaxe é necessária quando a inner class tem seu próprio contexto this.
Exemplo 2: Interagindo com a Classe Externa
class Carro { String nomeCarro; String tipoCarro; public Carro(String nome, String tipo) { this.nomeCarro = nome; this.tipoCarro = tipo; } private String getNomeCarro() { return this.nomeCarro; } // inner class class Motor { String tipoMotor; void setMotor() { if(Carro.this.tipoCarro.equals("4WD")){ if(Carro.this.getNomeCarro().equals("Chrysler")) { this.tipoMotor = "Menor"; } else { this.tipoMotor = "Maior"; } } else { this.tipoMotor = "Maior"; } } String getTipoMotor(){ return this.tipoMotor; } } } public class Main { public static void main(String[] args) { Carro carro1 = new Carro("Mazda", "8WD"); Carro.Motor motor = carro1.new Motor(); motor.setMotor(); System.out.println("Tipo Motor para 8WD= " + motor.getTipoMotor()); Carro carro2 = new Carro("Chrysler", "4WD"); Carro.Motor c2motor = carro2.new Motor(); c2motor.setMotor(); System.out.println("Tipo Motor para 4WD = " + c2motor.getTipoMotor()); } }
Saída:
Tipo Motor para 8WD= Maior Tipo Motor para 4WD = Menor
Mesmo que getNomeCarro() seja private, a inner class pode invocá-lo porque reside dentro da mesma classe externa.
Classe Aninhada Estática
Uma classe aninhada estática não requer instância da classe externa para ser criada. Consequentemente, não pode acessar diretamente membros não-estáticos da classe externa. É criada usando o nome da classe externa:
ClasseExterna.ClasseAninhada obj = new ClasseExterna.ClasseAninhada();
Exemplo 3: Classe Aninhada Estática
class PlacaMae { static class USB{ int usb2 = 2; int usb3 = 1; int getTotalPortas(){ return usb2 + usb3; } } } public class Main { public static void main(String[] args) { PlacaMae.USB usb = new PlacaMae.USB(); System.out.println("Total Portas = " + usb.getTotalPortas()); } }
Saída:
Total Portas = 3
Exemplo 4: Tentando Acessar Membros Externos em Classe Aninhada Estática
class PlacaMae { String modelo; public PlacaMae(String modelo) { this.modelo = modelo; } static class USB{ int usb2 = 2; int usb3 = 1; int getTotalPortas(){ if(PlacaMae.this.modelo.equals("MSI")) { return 4; } else { return usb2 + usb3; } } } } public class Main { public static void main(String[] args) { PlacaMae.USB usb = new PlacaMae.USB(); System.out.println("Total Portas = " + usb.getTotalPortas()); } }
Executar este código produz:
error: non-static variable this cannot be referenced from a static context
Este erro ocorre porque a classe aninhada estática não pode referenciar PlacaMae.this sem uma instância externa.
Principais Conclusões
- Inner classes são tratadas como membros regulares da classe externa e podem ser declaradas
private,protectedoupublic. - Elas podem acessar livremente todos os membros da classe externa, mesmo os marcados
private. - Classes aninhadas estáticas não requerem instância externa e não podem acessar membros não-estáticos da externa diretamente.
- Usar classes aninhadas promove encapsulamento e mantém lógica relacionada agrupada.
- Inner classes são ideais para callbacks, listeners ou objetos auxiliares firmemente acoplados à classe externa.
Java
- Entendendo Classes Aninhadas em C#: Definição, Uso e Herança
- Variáveis e Literais em Java: Guia Completo
- Classes e Objetos em Java: Guia Prático
- Entendendo a Palavra-chave final em Java: Variáveis, Métodos e Classes
- Operador instanceof em Java: Guia Completo
- Classes e Métodos Abstratos em Java: Guia Completo
- Entendendo Classes Aninhadas Estáticas em Java: Uso, Diferenças e Exemplos
- Dominando Classes Internas Anônimas em Java: Definição, Sintaxe e Exemplos Práticos
- Padrão Singleton em Java Explicado: Como Implementar e Usar com Segurança
- Dominando Reflection em Java: Inspecionando Classes, Métodos e Campos em Tempo de Execução