Java Non-Access Modifiers
Introduction to Non-Access Modifiers
Non-access modifiers in Java define the behavior and additional properties of classes, methods, and variables beyond visibility (public, private, etc.).
They control aspects like memory allocation, inheritance, thread-safety, and serialization. Common non-access modifiers include `static`, `final`, `abstract`, `synchronized`, `transient`, and `volatile`.
Common Non-Access Modifiers
Modifier | Applied To | Purpose |
---|---|---|
static | Variables, Methods, Blocks | Shared across all instances; belongs to the class |
final | Variables, Methods, Classes | Prevents reassignment, overriding, or inheritance |
abstract | Classes, Methods | Defines incomplete functionality to be implemented by subclasses |
synchronized | Methods, Blocks | Ensures thread-safe execution by allowing one thread at a time |
transient | Variables | Excludes the field from serialization |
volatile | Variables | Guarantees visibility of changes across threads |
Static Modifier
The `static` keyword makes a field or method belong to the class instead of specific objects.
Static variables are shared across all instances, and static methods can be invoked without creating an object.
public class Counter {
static int count = 0;
Counter() {
count++;
}
static void displayCount() {
System.out.println("Total count: " + count);
}
public static void main(String[] args) {
new Counter();
new Counter();
new Counter();
Counter.displayCount();
}
}
Total count: 3
Final Modifier
The `final` keyword ensures immutability in certain contexts:
- A final variable becomes a constant and cannot be reassigned.
- A final method cannot be overridden.
- A final class cannot be extended.
final class MathConstants {
public static final double PI = 3.14159;
public final void displayPI() {
System.out.println("PI value: " + PI);
}
}
public class Example {
public static void main(String[] args) {
System.out.println("PI: " + MathConstants.PI);
}
}
PI: 3.14159
Abstract Modifier
The `abstract` keyword is used for declaring abstract classes and methods.
- Abstract classes cannot be instantiated directly.
- Abstract methods have no body and must be implemented by subclasses.
abstract class Shape {
abstract double area();
public void display() {
System.out.println("This is a shape");
}
}
class Circle extends Shape {
double radius;
Circle(double r) {
radius = r;
}
double area() {
return Math.PI * radius * radius;
}
}
public class Test {
public static void main(String[] args) {
Shape circle = new Circle(5.0);
System.out.println("Area: " + circle.area());
}
}
Area: 78.53981633974483
Synchronized Modifier
The `synchronized` keyword ensures that only one thread at a time can execute a method or block, preventing race conditions when accessing shared mutable state.
class SyncCounter {
private int count = 0;
public synchronized void increment() {
count++;
}
public int getCount() {
return count;
}
}
public class SyncDemo {
public static void main(String[] args) throws InterruptedException {
SyncCounter counter = new SyncCounter();
Runnable task = () -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
};
Thread t1 = new Thread(task);
Thread t2 = new Thread(task);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Final Count: " + counter.getCount());
}
}
Final Count: 2000
Transient Modifier
The `transient` keyword marks a variable as non-serializable. When an object is serialized, transient fields are skipped.
import java.io.*;
class User implements Serializable {
String name;
transient String password;
User(String n, String p) {
name = n;
password = p;
}
}
public class TransientDemo {
public static void main(String[] args) throws Exception {
User u = new User("Alice", "secret123");
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("user.ser"));
out.writeObject(u);
out.close();
ObjectInputStream in = new ObjectInputStream(new FileInputStream("user.ser"));
User restored = (User) in.readObject();
in.close();
System.out.println("Name: " + restored.name);
System.out.println("Password: " + restored.password);
}
}
Name: Alice Password: null
Volatile Modifier
The `volatile` keyword ensures that changes to a variable are always visible to all threads. It prevents threads from caching the variable locally.
class SharedData {
volatile boolean running = true;
public void stop() {
running = false;
}
}
public class VolatileDemo {
public static void main(String[] args) throws InterruptedException {
SharedData data = new SharedData();
Thread worker = new Thread(() -> {
while (data.running) {
// busy wait
}
System.out.println("Stopped!");
});
worker.start();
Thread.sleep(1000);
data.stop();
}
}
Stopped!
Best Practices
- ✅ Use `static` for utility methods and constants shared across objects
- ✅ Use `final` for constants and to prevent unintended modifications or subclassing
- ✅ Use `abstract` to define contracts for subclasses to implement
- ✅ Use `synchronized` only when necessary to avoid performance bottlenecks
- ✅ Use `transient` for fields that should not be serialized
- ✅ Use `volatile` for variables shared by multiple threads where visibility is critical