Java Non-Access Modifiers
Use Java's non-access modifiers — static, final, abstract, synchronized, transient, volatile — and what each controls.
Java's access modifiers — public, protected, private — control who can see a member. The non-access modifiers control how it behaves. They're a small grab-bag of keywords that change ownership, mutability, threading, serialization, and a few other things. This chapter is the map; each modifier has a fuller chapter or section elsewhere.
The full list
| Modifier | Applies to | What it does |
|---|---|---|
static | fields, methods, nested classes, blocks | Belongs to the class, not to instances |
final | classes, methods, fields, parameters, locals | Cannot be reassigned/overridden/extended |
abstract | classes, methods | No body / cannot be instantiated; must be implemented by a subclass |
synchronized | methods, blocks | Only one thread at a time may execute it on a given lock |
volatile | fields | Reads/writes are not cached in thread-local memory |
transient | fields | Skipped by default serialization |
native | methods | Implementation lives in non-Java code (usually C/C++) |
strictfp | classes, methods | Forces strict IEEE-754 float behavior (largely historical) |
default | interface methods | Provides a default body in an interface |
sealed / non-sealed | classes, interfaces | Restricts which classes may extend (Java 17+) |
You'll meet static, final, abstract, and default constantly. The rest you'll see only when their problem comes up.
static — belongs to the class
A static member is associated with the class itself, not with any single instance:
public class Counter {
int instanceCount; // one per Counter object
static int classCount; // one shared by everyone
}static is so common it gets its own chapter — see java-static.
final — cannot change
final means "this binding is fixed after it's set." It applies to a few different things:
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 is the foundation of constants (static final), immutable objects, and safe inheritance design. Full treatment in java-final.
abstract — has no body, must be filled in
abstract applied to a class means "you can't instantiate this directly — only subclasses." Applied to a method, it means "no body here — every concrete subclass must provide one":
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() is a compile error; new Circle() works. Covered in abstract classes.
synchronized — one thread at a time
When two threads might call the same method on the same object, marking the method synchronized makes sure only one runs at a time:
public synchronized void deposit(int amount) {
balance += amount;
}This is the simplest form of locking. There's an entire concurrency chapter later in the book; for now, recognize that the keyword exists and what it broadly does.
volatile — visible across threads
Without volatile, threads are allowed to cache a field's value. Reads in one thread might never see writes from another:
private volatile boolean stopped = false;volatile forces every read to come from main memory and every write to go to main memory. It's the lightweight cousin of synchronized for simple flag fields.
transient — skip on serialization
Java's built-in object serialization (Serializable) writes every field by default. transient says "don't include this one" — typically used for caches, computed values, or things that don't make sense outside the running program:
public class Session {
String userId;
transient String passwordHash; // not serialized
}Modern code uses JSON serializers more than Serializable, but the keyword is still useful in libraries that care about it.
native — implemented elsewhere
native is for methods whose body is in another language (C/C++ via JNI). You rarely write them yourself; you only see them in low-level libraries:
public native int currentTimeMillis();strictfp — strict floating-point
Originally, strictfp forced predictable IEEE-754 float arithmetic across platforms. As of Java 17, all floating-point math is implicitly strict, which makes the keyword a no-op. You can mostly ignore it; it lingers in older codebases.
default — on interface methods
Inside an interface, default lets you provide a body for a method instead of leaving it abstract:
public interface Greeter {
default String greet(String name) {
return "Hello, " + name;
}
}Without default, an interface method has no body and every implementing class has to write its own. Full treatment in default methods.
sealed and non-sealed
A sealed class names the exact list of classes allowed to extend it. Subclasses must then choose to be final, sealed, or non-sealed:
public sealed class Shape permits Circle, Square { }
public final class Circle extends Shape { }
public non-sealed class Square extends Shape { }Useful for closed type hierarchies — see sealed classes.
Combining modifiers
You can usually stack modifiers freely, in this conventional order:
public static final int MAX = 100;
private static volatile int counter;
protected abstract void onInit();Some combinations are illegal: a method can't be both abstract and final, both abstract and private, or both abstract and static. The compiler will tell you when you've crossed a line.
A worked example
What's next
The next two chapters drill into the two modifiers you'll use most often: static for class-level members, then final for immutability. Read them in order.
Practice
Which non-access modifier means a class member belongs to the class itself rather than to each instance?