Palavra-chave static em Java
Declare membros de nível de classe em Java com static — campos, métodos, blocos e classes aninhadas estáticas.
static é a palavra-chave que eleva um membro de classe de "um por instância" para "um por classe". Um campo estático possui uma única cópia compartilhada por todos os objetos. Um método estático pertence à própria classe e executa sem nenhuma instância. Um bloco estático é executado uma vez, quando a classe é carregada pela primeira vez. Uma classe aninhada estática vive dentro de outra classe sem precisar de um objeto envolvente.
A regra geral: membros static não têm this. Todo o restante do comportamento decorre disso.
Campos estáticos
Um campo estático é declarado com static no corpo da classe. Há exatamente uma cópia, independentemente de quantas instâncias existam:
public class Counter {
static int total; // one Counter.total for everybody
int count; // each Counter has its own count
}
Counter a = new Counter(); a.count++; Counter.total++;
Counter b = new Counter(); b.count++; Counter.total++;
System.out.println(a.count); // 1
System.out.println(b.count); // 1
System.out.println(Counter.total); // 2Acesse um campo estático pelo nome da classe (Counter.total) — essa é a forma canônica. O Java também permite escrever a.total porque a é um Counter, mas todo linter do mundo sinaliza esse estilo.
Métodos estáticos
Um método estático pertence à classe. Chame-o com NomeDaClasse.metodo(...):
public class MathUtil {
public static int square(int n) {
return n * n;
}
}
int x = MathUtil.square(7); // 49Dentro de um método estático, não há this — você não pode ler campos de instância nem chamar métodos de instância sem qualificação, pois não há instância atual a partir da qual lê-los:
public class Counter {
int count;
static void reset() {
count = 0; // ERROR: cannot reference instance field from static context
}
}Você ainda pode receber uma instância como parâmetro e operar sobre ela:
static void resetThis(Counter c) {
c.count = 0; // ok — c is a parameter, not this
}A direção inversa funciona bem: um método de instância pode chamar um método estático sem cerimônia, pois a classe está sempre disponível mesmo quando uma instância existe.
Quando escolher static
O único teste é verificar se o membro depende de estado por instância.
Depende de this? | Usar |
|---|---|
| Não — cálculo puro, contador compartilhado, método fábrica | static |
| Sim — lê ou grava os próprios campos do objeto | instância |
public static int hoursToSeconds(int h) { return h * 3600; } // no this needed → static
public int rentalDays() { return days; } // reads this.days → instanceUm cheiro comum: um método de instância que ignora this. Ele está mentindo sobre ser específico da instância — torne-o static e o chamador não precisará mais inventar um objeto apenas para usá-lo.
Constantes estáticas
A combinação static final é a forma padrão para constantes:
public static final double TAX_RATE = 0.08;
public static final int MAX_RETRIES = 3;
public static final String DEFAULT_LOCALE = "en";Por convenção, constantes são nomeadas em UPPER_SNAKE_CASE. Elas são incorporadas em tempo de compilação quando o valor é primitivo ou um literal String, o que as torna tão rápidas quanto um literal no ponto de chamada.
Blocos estáticos
Um bloco static { ... } é executado uma vez, quando a classe é carregada na JVM pela primeira vez. Use-o para a configuração única de campos estáticos que precisam de mais do que uma única expressão:
public class Lookup {
static final Map<String, Integer> WEEKDAYS = new HashMap<>();
static {
WEEKDAYS.put("Mon", 1);
WEEKDAYS.put("Tue", 2);
WEEKDAYS.put("Wed", 3);
WEEKDAYS.put("Thu", 4);
WEEKDAYS.put("Fri", 5);
WEEKDAYS.put("Sat", 6);
WEEKDAYS.put("Sun", 7);
}
}Blocos estáticos são poderosos, mas fáceis de usar em excesso. Prefira um inicializador de campo simples quando uma expressão for suficiente.
Campos estáticos e blocos estáticos são executados de cima para baixo na ordem em que aparecem no código-fonte. Se um inicializador acessar um campo (por meio de um método) antes da própria linha desse campo ter sido executada, ele verá o valor padrão (0, false ou null) — portanto, a ordem importa:
public class Order {
static int a = compute(); // runs first; b is still 0 → a becomes 1
static int b = 10; // runs second
static int compute() { return b + 1; }
}
// Order.a == 1, Order.b == 10(Ler b diretamente nessa primeira linha — static int a = b + 1; — seria um erro de compilação "referência direta ilegal"; somente o caminho indireto por meio de um método expõe o valor padrão.)
Classes aninhadas estáticas
Uma classe declarada static dentro de outra classe é uma classe aninhada estática. Ao contrário de uma classe interna não estática, ela não carrega uma referência implícita a uma instância da classe externa:
public class Outer {
static class Inner { // does not need an Outer instance
void hello() { System.out.println("hi"); }
}
}
Outer.Inner i = new Outer.Inner(); // create directly
i.hello();É assim que temos encapsulado classes auxiliares no mesmo arquivo que main em blocos static class Foo {...} anteriores — main é estático, portanto precisamos que o auxiliar também seja estático para instanciá-lo sem uma instância Outer envolvente. O capítulo de classes aninhadas cobre todos os quatro tipos.
static não é "o construtor"
Iniciantes às vezes confundem "static = executa uma vez" com "static = executa na criação do objeto". A inicialização estática acontece uma vez por classe, não uma vez por objeto. O construtor executa uma vez por objeto. São mecanismos distintos e disparam em situações diferentes.
Membros estáticos em interfaces
Interfaces também podem ter métodos static. Eles se comportam da mesma forma que estáticos de classe — chame-os com NomeDaInterface.metodo(...):
public interface Path {
static Path of(String s) { return new SimplePath(s); }
}
Path p = Path.of("/tmp/foo");O capítulo de interfaces cobre quando isso é uma boa ideia (métodos fábrica na própria interface).
Um exemplo prático
Este programa imprime:
#1 apple base=0.50 USD, with tax=0.54
#2 bread base=2.40 USD, with tax=2.59
#3 butter base=3.10 USD, with tax=3.35
Total items ever created: 3Observe como o exemplo mistura todos os quatro tipos: as constantes e a tabela de pesquisa são preenchidas antes de qualquer Item existir, cada Item mantém seus próprios name e basePrice, e o campo compartilhado único itemsCreated distribui o id sequencial.
O que vem a seguir
static permite dizer quem possui um membro. O próximo complemento é final, que permite dizer se ele pode mudar. Juntos, static final é a forma padrão para constantes; por si só, final molda herança e design imutável. Continue em java-final.