Modifiers are special keywords that you can use to define or control the behavior, accessibility, and properties of classes, methods, constructors, or variables.
It helps programmers to control access to data and methods, and organize code in a secure and structured way.
Without modifiers, all classes, methods, and variables would be open by default, which is not secure or efficient in large programs.
Types of Modifiers in Java
Java modifiers are mainly divided into two categories:
- Access Modifiers
- Non-Access Modifiers
1) Access Modifiers
Access modifiers control who can access a class, method, or variable. Java provides four access levels:
- public
- private
- protected
- default (no modifier)

a) public Modifier
The public modifier makes a class, method, or variable accessible from anywhere in the program, whether it’s in the same package or a different one.
This method is commonly used when you want other classes or packages to interact with your code directly.
Example:
class Greeting {
public String message = "Hello, Java World!";
public void sayHello() {
System.out.println(message);
}
}
public class Main {
public static void main(String[] args) {
Greeting greet = new Greeting();
greet.sayHello(); // Accessible from anywhere
}
}
Output:
Hello, Java World!
- The variable message and method sayHello() are marked as public.
b) private Modifier
The private modifier restricts access only to the same class. It means, no other classes or subclasses can access private variables or methods.
It is mostly used to protect sensitive data or hide internal implementation details.
Example:
class Account {
private double balance = 5000.0;
// Private method
private void showBalance() {
System.out.println("Current Balance: ₹" + balance);
}
// Public method to access private method safely
public void checkBalance() {
showBalance();
}
}
public class Main {
public static void main(String[] args) {
Account acc = new Account();
acc.checkBalance(); // Allowed (through public method)
// acc.balance or acc.showBalance() -> Not allowed
}
}
Output:
Current Balance: ₹5000.0
- In this code, the balance variable and showBalance() method are private; they can’t be accessed from outside the Account class.
- If you want to view the balance, the class provides a public method checkBalance() as a safe interface.
c) protected Modifier
The protected modifier allows access within the same package and to subclasses in different packages.
It’s mostly used in inheritance where the parent class shares certain information with child classes but not with everyone.
Example:
class Animal {
protected String type = "Mammal";
protected void showType() {
System.out.println("Animal Type: " + type);
}
}
class Dog extends Animal {
void bark() {
System.out.println("Dog is barking...");
showType(); // Accessible because of protected modifier
}
}
public class Main {
public static void main(String[] args) {
Dog d = new Dog();
d.bark();
}
}
Output:
Dog is barking...
Animal Type: Mammal
- Here, the variable type and method showType() are declared protected.
- They are accessible inside the subclass (Dog), even though they belong to the parent class Animal.
d) Default Modifier
When you don’t write any access modifier, it becomes default (also known as package-private). That means the class or member is accessible only within the same package, not from outside packages.
Example:
class Student {
String name = "Ravi"; // default access
void showName() { // default access
System.out.println("Student Name: " + name);
}
}
public class Main {
public static void main(String[] args) {
Student s = new Student();
s.showName(); // Works fine (same package)
}
}
Output:
Student Name: Ravi
2. Non-Access Modifiers in Java
non-access modifiers are keywords that provide extra features or behaviors to classes, variables, or methods to control access.
They define how something should behave, not who can access it.
For example:
- We can use static to make common variable for all objects.
- We can also use final keyword to stop modification.
Let’s explore each type one by one with simple code examples
Types of Non-Access Modifiers
- static
- final
- abstract
- synchronized
- transient
- volatile
a) static Modifier
The static modifier means the member belongs to the class, not to any specific object. That means it is shared among all instances and can be accessed without creating an object.
Example:
class Counter {
static int count = 0; // shared by all objects
Counter() {
count++;
}
static void showCount() {
System.out.println("Total objects created: " + count);
}
}
public class Main {
public static void main(String[] args) {
new Counter();
new Counter();
new Counter();
Counter.showCount(); // Accessing static method directly using class name
}
}
Output:
Total objects created: 3
- Here, every time a new object is created, the count increases. And the count is static; all objects share the same memory, not separate copies.
b) final Modifier
The final modifier is used to make variables constant, methods non-overridable, and classes non-inheritable. Meaning, it represents something fixed and unchangeable.
- Final Variable: Value cannot be changed.
- Final Method: Cannot be overridden.
- Final Class: Cannot be subclassed.
Example:
final class Vehicle {
final int MAX_SPEED = 120;
final void displaySpeed() {
System.out.println("Maximum allowed speed: " + MAX_SPEED + " km/h");
}
}
// Uncommenting below will cause error because Vehicle is final
// class Car extends Vehicle {}
public class Main {
public static void main(String[] args) {
Vehicle v = new Vehicle();
v.displaySpeed();
// v.MAX_SPEED = 200; // Not allowed, because MAX_SPEED is final
}
}
Output:
Maximum allowed speed: 120 km/h
c) abstract Modifier
The abstract modifier is used to define abstract classes and abstract methods.
Example:
abstract class Shape {
abstract void area(); // abstract method - no body
void message() {
System.out.println("Calculating area of a shape...");
}
}
class Circle extends Shape {
double radius = 3.5;
void area() {
double result = Math.PI * radius * radius;
System.out.println("Area of Circle: " + result);
}
}
public class Main {
public static void main(String[] args) {
Shape shape = new Circle();
shape.message();
shape.area();
}
}
Output:
Calculating area of a shape...
Area of Circle: 38.48451000647496
- Here, the shape class cannot be directly used because it’s abstract.
d) synchronized Modifier
The synchronized modifier ensures that only one thread can execute a method at a time. It is used in multithreading to avoid data corruption when multiple threads access shared resources.
Code example:
class Printer {
synchronized void printDocument(String fileName) {
for (int i = 1; i <= 3; i++) {
System.out.println("Printing " + fileName + " - Page " + i);
try {
Thread.sleep(400);
} catch (InterruptedException e) {
System.out.println("Error: " + e);
}
}
}
}
public class Main {
public static void main(String[] args) {
Printer printer = new Printer();
Thread t1 = new Thread(() -> printer.printDocument("Report.pdf"));
Thread t2 = new Thread(() -> printer.printDocument("Invoice.pdf"));
t1.start();
t2.start();
}
}
Output:
Printing Report.pdf - Page 1
Printing Report.pdf - Page 2
Printing Report.pdf - Page 3
Printing Invoice.pdf - Page 1
Printing Invoice.pdf - Page 2
Printing Invoice.pdf - Page 3
e) transient Modifier
The transient modifier is used in serialization. When an object is converted to a file or network stream, transient variables are skipped; they are not saved.
import java.io.*;
class User implements Serializable {
String username;
transient String password; // Will not be serialized
User(String u, String p) {
username = u;
password = p;
}
}
public class Main {
public static void main(String[] args) throws Exception {
User user = new User("Rahul", "secret123");
// Serialize the object
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("user.txt"));
out.writeObject(user);
out.close();
// Deserialize the object
ObjectInputStream in = new ObjectInputStream(new FileInputStream("user.txt"));
User newUser = (User) in.readObject();
in.close();
System.out.println("Username: " + newUser.username);
System.out.println("Password: " + newUser.password); // will print null
}
}
Output:
Username: Rahul
Password: null
- Here, the password was marked transient, so it was not stored during serialization for security reasons.
f) volatile Modifier
The volatile modifier is used in multithreading to ensure that every thread reads the latest value of a variable directly from memory.
For example:
class FlagExample {
volatile boolean running = true;
void runTask() {
while (running) {
System.out.println("Task running...");
try {
Thread.sleep(300);
} catch (InterruptedException e) {
System.out.println(e);
}
}
System.out.println("Task stopped!");
}
}
public class Main {
public static void main(String[] args) throws Exception {
FlagExample obj = new FlagExample();
Thread t1 = new Thread(obj::runTask);
t1.start();
Thread.sleep(1000); // Let it run for a while
obj.running = false; // Update from main thread
}
}
Output:
Task running...
Task running...
Task running...
Task stopped!
- Because the variable running is volatile, the change made by the main thread is immediately visible to the other thread.