BhauAutomation

Access Modifiers in Java

Access Modifiers in Java define the visibility or scope of variables, methods, constructors, and classes. They help implement encapsulation and control how different parts of a program can interact.

📘 Topic: Core Java / OOPs
Read time: 5 min
📊 Level: Beginner
Includes: Code + Table
📖 Overview

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.

💡
Why does it matter?

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

Types of Access Modifiers

Java has four access modifiers. Each has a different visibility scope — from the most restrictive to the most open:

public

Accessible from anywhere in the program — any class, any package, any module.

🌍 Universal Access
private

Accessible only within the same class. Most restrictive modifier — complete data hiding.

🔒 Same Class Only
protected

Accessible within the same package and by subclasses (even across packages via inheritance).

🛡 Package + Subclasses
default

No keyword needed. Accessible only within the same package. Also called package-private.

📦 Same Package Only
📊 Scope Matrix

Access 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

Advantages of Access Modifiers

🔒
Encapsulation & Data Hiding

Access modifiers let you hide internal implementation details and expose only what is necessary, protecting the integrity of your objects.

🛡️
Security & Maintainability

Restricted access reduces the chances of unintended interference, making code easier to debug, test, and maintain over time.

📐
Controlled API Design

You can precisely define the public API of a class while keeping implementation details private — a core principle of good software architecture.

⚠️ Limitations

Limitations

⚠️
Overuse of private

Making everything private can reduce code reusability and make unit testing harder, as internal state becomes difficult to verify.

🧩
Design Complexity

Improper use of modifiers — such as making implementation details public — can create tight coupling and fragile designs that are hard to refactor.

📦
Default Access Pitfalls

Relying on default (package-private) access can create unintended package dependencies and make code less portable across module boundaries.

💻 Code Example

Example Code

Here is a practical Java class demonstrating all four access modifiers together:

Java
// 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

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.