Modificadores Não-de-Acesso em Java
Use os modificadores não-de-acesso do Java — static, final, abstract, synchronized, transient, volatile — e o que cada um controla.
Os modificadores de acesso do Java — public, protected, private — controlam quem pode ver um membro. Os modificadores não-de-acesso controlam como ele se comporta. São um pequeno conjunto de palavras-chave que alteram propriedade, mutabilidade, threading, serialização e algumas outras coisas. Este capítulo é o mapa; cada modificador tem um capítulo ou seção mais completo em outro lugar.
A lista completa
| Modificador | Aplica-se a | O que faz |
|---|---|---|
static | campos, métodos, classes aninhadas, blocos | Pertence à classe, não às instâncias |
final | classes, métodos, campos, parâmetros, variáveis locais | Não pode ser reatribuído/sobrescrito/estendido |
abstract | classes, métodos | Sem corpo / não pode ser instanciado; deve ser implementado por uma subclasse |
synchronized | métodos, blocos | Apenas uma thread por vez pode executá-lo em um dado lock |
volatile | campos | Leituras/escritas não são armazenadas em cache na memória local da thread |
transient | campos | Ignorado pela serialização padrão |
native | métodos | A implementação reside em código não-Java (geralmente C/C++) |
strictfp | classes, métodos | Força comportamento estrito de ponto flutuante IEEE-754 (em grande parte histórico) |
default | métodos de interface | Fornece um corpo padrão em uma interface |
sealed / non-sealed | classes, interfaces | Restringe quais classes podem estender (Java 17+) |
Você encontrará static, final, abstract e default constantemente. Os demais você verá apenas quando o problema específico deles surgir.
static — pertence à classe
Um membro static está associado à própria classe, não a nenhuma instância específica:
public class Counter {
int instanceCount; // one per Counter object
static int classCount; // one shared by everyone
}static é tão comum que tem seu próprio capítulo — veja java-static.
final — não pode mudar
final significa "esta ligação é fixa após ser definida." Aplica-se a algumas coisas diferentes:
final int MAX = 100; // local variable cannot be reassigned
public final class Money {} // class cannot be extended
public final void close() {} // method cannot be overridden
private final int balance; // field assigned once, then immutablefinal é a base das constantes (static final), objetos imutáveis e design de herança seguro. Tratamento completo em java-final.
abstract — não tem corpo, precisa ser preenchido
abstract aplicado a uma classe significa "você não pode instanciar isso diretamente — apenas subclasses podem." Aplicado a um método, significa "sem corpo aqui — toda subclasse concreta deve fornecer um":
public abstract class Shape {
public abstract double area(); // no body
}
public class Circle extends Shape {
double r;
public double area() { return Math.PI * r * r; }
}new Shape() é um erro de compilação; new Circle() funciona. Abordado em classes abstratas.
synchronized — uma thread por vez
Quando duas threads podem chamar o mesmo método no mesmo objeto, marcar o método como synchronized garante que apenas uma seja executada por vez:
public synchronized void deposit(int amount) {
balance += amount;
}Esta é a forma mais simples de locking. Há uma seção inteira sobre concorrência mais adiante no livro; por ora, reconheça que a palavra-chave existe e o que ela faz de forma geral. Veja sincronização para a história completa.
volatile — visível entre threads
Sem volatile, as threads têm permissão para armazenar em cache o valor de um campo. Leituras em uma thread podem nunca ver escritas de outra:
private volatile boolean stopped = false;volatile força cada leitura a vir da memória principal e cada escrita a ir para a memória principal. É o primo leve de synchronized para campos de flag simples — veja volatile para os detalhes do modelo de memória.
transient — ignorado na serialização
A serialização de objetos embutida do Java (Serializable) escreve todos os campos por padrão. transient diz "não inclua este" — normalmente usado para caches, valores computados ou coisas que não fazem sentido fora do programa em execução:
public class Session {
String userId;
transient String passwordHash; // not serialized
}O código moderno usa serializadores JSON mais do que Serializable, mas a palavra-chave ainda é útil em bibliotecas que se importam com ela. Mais em serialização.
native — implementado em outro lugar
native é para métodos cujo corpo está em outra linguagem (C/C++ via JNI). Você raramente os escreve você mesmo; você os vê apenas em bibliotecas de baixo nível:
public native int currentTimeMillis();strictfp — ponto flutuante estrito
Originalmente, strictfp forçava aritmética de ponto flutuante IEEE-754 previsível entre plataformas. A partir do Java 17, toda a matemática de ponto flutuante é implicitamente estrita, o que torna a palavra-chave um no-op. Você pode ignorá-la em grande parte; ela persiste em bases de código mais antigas.
default — em métodos de interface
Dentro de uma interface, default permite que você forneça um corpo para um método em vez de deixá-lo abstrato:
public interface Greeter {
default String greet(String name) {
return "Hello, " + name;
}
}Sem default, um método de interface não tem corpo e toda classe implementadora precisa escrever o seu. Tratamento completo em métodos default.
sealed e non-sealed
Uma classe sealed nomeia a lista exata de classes com permissão para estendê-la. As subclasses devem então escolher ser final, sealed ou non-sealed:
public sealed class Shape permits Circle, Square { }
public final class Circle extends Shape { }
public non-sealed class Square extends Shape { }Útil para hierarquias de tipos fechadas — veja classes sealed.
Combinando modificadores
Geralmente você pode empilhar modificadores livremente, nesta ordem convencional:
public static final int MAX = 100;
private static volatile int counter;
protected abstract void onInit();Algumas combinações são ilegais: um método não pode ser ao mesmo tempo abstract e final, ao mesmo tempo abstract e private, ou ao mesmo tempo abstract e static. O compilador informará quando você cruzar uma linha.
Um exemplo prático
O que vem a seguir
Os próximos dois capítulos aprofundam os dois modificadores que você usará com mais frequência: static para membros no nível de classe e final para imutabilidade. Leia-os em ordem.