Classes aninhadas em Java: como tudo começou?
Imagine: você está escrevendo código em Java e, de repente, percebe que uma classe está logicamente ligada a outra. Por exemplo, Car e Engine. O motor não existe por si só — ele faz parte do carro. Como modelar isso de forma elegante e correta em Java? A resposta — classes aninhadas (nested classes).
O tópico Java inner class and static nested class é um dos mais frequentes no Stack Overflow. Milhares de desenvolvedores se confundem: qual é a diferença? Quando usar inner e quando usar static nested? Por que elas foram criadas?
Neste tutorial, vamos organizar tudo. Você não aprenderá apenas a sintaxe — entenderá a lógica dos designers do Java. Vamos nessa!
O que é uma nested class (classe aninhada)?
Vamos começar pelo básico. Uma Nested class é uma classe declarada dentro de outra classe. Em Java, existem quatro tipos de classes aninhadas, mas hoje estamos interessados nas duas mais populares:
- Static nested class (classe aninhada estática)
- Inner class (classe interna, também conhecida como non-static nested class)
A diferença principal é o modificador estático. Ele muda tudo: desde o acesso aos campos até o tempo de vida do objeto. Vamos entender na prática.
Static nested class: simples e independente
Uma classe aninhada estática se comporta como uma classe externa comum, mas "vive" dentro de sua classe pai. Ela não tem acesso a campos e métodos não estáticos da classe externa (a menos que receba uma referência ao objeto).
Exemplo do mundo real: Database e DatabaseConfig. A configuração não está vinculada a uma instância específica do banco de dados.
public class Database { private String url; private static String defaultDriver = "com.mysql.cj.jdbc.Driver";
public Database(String url) { this.url = url; }
// Static nested class public static class DatabaseConfig { private String driver; private int poolSize;
public DatabaseConfig(String driver, int poolSize) { this.driver = driver; this.poolSize = poolSize; }
public void printConfig() { // Tem acesso apenas aos membros estáticos da classe externa System.out.println("Default driver: " + defaultDriver); // System.out.println(url); // ERRO! url — campo não estático }
public static void staticMethodInNested() { System.out.println("Método estático em uma classe aninhada estática"); } }
public void useConfig() { // Criando uma instância da static nested class DatabaseConfig config = new DatabaseConfig("oracle.jdbc.OracleDriver", 10); config.printConfig(); }}Observe: para criar DatabaseConfig, não precisamos de um objeto Database. Essa é a principal vantagem — independência.
Quando usar static nested class?
- Quando a classe aninhada está logicamente relacionada à classe externa, mas não depende de sua instância.
- Quando você precisa agrupar classes auxiliares (builders, configurações, utilitários).
- Quando você está projetando o padrão Builder — um exemplo clássico.
Inner class (non-static nested class): ligadas para sempre
A classe interna é o oposto completo. Ela está sempre vinculada a um objeto específico da classe externa. Isso significa:
- Ela tem acesso a todos os campos e métodos da classe externa (mesmo os private).
- Ela não pode existir sem uma instância da classe externa.
- Ela armazena implicitamente uma referência ao objeto externo (
OuterClass.this).
Exemplo: Car e Engine. Cada car