What are Access Modifiers?
In Java, Access Modifiers are keywords that set the level of access for classes, methods, and variables. They ensure data security and proper encapsulation in Object-Oriented Programming (OOP).
Java provides four types of access modifiers — each controlling how visible a member is across different parts of your codebase.
Access modifiers are the foundation of encapsulation — one of the four pillars of OOP. They prevent accidental modification of data and expose only what is necessary to the outside world.
Types of Access Modifiers
Java has four access modifiers. Each has a different visibility scope — from the most restrictive to the most open:
Accessible from anywhere in the program — any class, any package, any module.
🌍 Universal AccessAccessible only within the same class. Most restrictive modifier — complete data hiding.
🔒 Same Class OnlyAccessible within the same package and by subclasses (even across packages via inheritance).
🛡 Package + SubclassesNo keyword needed. Accessible only within the same package. Also called package-private.
📦 Same Package OnlyAccess Scope at a Glance
This table shows where each modifier allows access — use it as a quick reference during development.
| Modifier | Same Class | Same Package | Subclass (diff pkg) | Anywhere |
|---|---|---|---|---|
| public | ✔ | ✔ | ✔ | ✔ |
| protected | ✔ | ✔ | ✔ | ✘ |
| default | ✔ | ✔ | ✘ | ✘ |
| private | ✔ | ✘ | ✘ | ✘ |
Advantages of Access Modifiers
Access modifiers let you hide internal implementation details and expose only what is necessary, protecting the integrity of your objects.
Restricted access reduces the chances of unintended interference, making code easier to debug, test, and maintain over time.
You can precisely define the public API of a class while keeping implementation details private — a core principle of good software architecture.
Limitations
Making everything private can reduce code reusability and make unit testing harder, as internal state becomes difficult to verify.
Improper use of modifiers — such as making implementation details public — can create tight coupling and fragile designs that are hard to refactor.
Relying on default (package-private) access can create unintended package dependencies and make code less portable across module boundaries.
Example Code
Here is a practical Java class demonstrating all four access modifiers together:
// Access Modifiers Demo class AccessDemo { // public — accessible from anywhere public int publicVar = 10; // private — accessible only within this class private int privateVar = 20; // protected — accessible in same package & subclasses protected int protectedVar = 30; // default (no keyword) — same package only int defaultVar = 40; // private method — internal use only private void showPrivate() { System.out.println("Private Method: " + privateVar); } // public getter — controlled access to private data public int getPrivateVar() { return privateVar; } public static void main(String[] args) { AccessDemo obj = new AccessDemo(); System.out.println("Public: " + obj.publicVar); System.out.println("Protected: " + obj.protectedVar); System.out.println("Default: " + obj.defaultVar); System.out.println("Private via getter: " + obj.getPrivateVar()); } }
Best Practices
Follow these guidelines for clean, maintainable, and well-encapsulated Java code:
- 🔒 Use private for all fields and internal helper methods — expose them through getters/setters only when required.
- 🌐 Expose only necessary APIs as public. Think of your class's public interface as a contract — once exposed, it's hard to change.
- 🛡️ Use protected when designing classes intended for inheritance — it signals that a member is part of the inheritance API.
- 📦 Avoid default (package-private) access unless you intentionally want package-level collaboration between tightly related classes.
- ⚙️ Prefer private fields with public getters/setters (the JavaBean pattern) to maintain encapsulation while allowing controlled access.
- 🔍 Review access levels during code reviews — unnecessarily wide access is a common source of bugs and design debt.