Access Modifiers in Java OOP – public, private, protected, default Explained

Illustration for Access Modifiers in Java OOP – public, private, protected, default Explained
By Last updated:

Introduction

Access modifiers are essential building blocks of Object-Oriented Programming (OOP) in Java. They help control the visibility and accessibility of classes, methods, and variables, promoting encapsulation, modular design, and maintainability. Whether you're designing APIs, structuring enterprise applications, or securing sensitive data, access modifiers play a vital role.

In this tutorial, we'll explore the four access modifiers in Java – public, private, protected, and default (package-private) – and how they shape class interactions in real-world development.


What are Access Modifiers?

Access modifiers in Java define where a class member (field, method, constructor, class) can be accessed from. They enforce encapsulation by restricting or exposing implementation details.

Modifier Class Package Subclass World
public
protected
default
private

1. public Modifier

Definition

A public class or member is accessible from anywhere – inside the class, package, or even from unrelated classes in other packages.

Syntax

public class Vehicle {
    public String type;
    public void drive() {
        System.out.println("Driving a " + type);
    }
}

Use Case

Utility classes, APIs, and constants that are meant to be used across the codebase.


2. private Modifier

Definition

A private member is accessible only within the same class. It is not visible to subclasses or even other classes in the same package.

Syntax

public class BankAccount {
    private double balance;

    public double getBalance() {
        return balance;
    }
    public void deposit(double amount) {
        if (amount > 0) balance += amount;
    }
}

Use Case

Encapsulation, data hiding, restricting direct access to sensitive fields.


3. protected Modifier

Definition

A protected member is accessible within the same package and in subclasses (even if they're in different packages).

Syntax

public class Animal {
    protected void makeSound() {
        System.out.println("Animal makes sound");
    }
}

class Dog extends Animal {
    public void bark() {
        makeSound(); // accessible
    }
}

Use Case

Designing frameworks where you want child classes to override or use methods.


4. Default (No Modifier)

Definition

If no modifier is specified, the member is package-private, meaning it's accessible within the same package but not outside.

Syntax

class Product {
    int id; // default access

    void printId() {
        System.out.println("ID: " + id);
    }
}

Use Case

Internal implementation details meant for use only within a package.


UML-style Visibility

In UML diagrams:

  • + denotes public
  • - denotes private
  • # denotes protected
  • ~ denotes package-private

Real-world Analogy

Think of access modifiers like house access:

  • public – Anyone can enter.
  • protected – Only family members or those with a key.
  • default – Only roommates (same package) allowed.
  • private – Only you.

Best Practices

  • Start with private and loosen restrictions only when needed.
  • Avoid protected unless subclassing is necessary.
  • Use public for APIs or utility functions only.
  • Maintain encapsulation by accessing fields through getters/setters.

Version Notes (Java 17/21+)

Java record types implicitly use private final fields with public accessors.

public record Person(String name, int age) { }

Common Mistakes

  • Accessing private members directly from other classes.
  • Overusing public in large codebases – reduces encapsulation.
  • Misunderstanding protected outside packages.

Refactoring Example

BEFORE

public class User {
    public String name;
}

AFTER

public class User {
    private String name;
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
}

Conclusion

Access modifiers are vital for building secure, modular, and maintainable applications. Understanding when and how to use each modifier leads to better OOP design in Java.


✅ Key Takeaways

  • Use private for encapsulation.
  • Use public sparingly and only for required external access.
  • protected gives access to subclasses and same-package classes.
  • Default is package-private – hidden from external packages.

💬 FAQ

1. Can a top-level class be private in Java?

No, only public or package-private is allowed.

2. Can interfaces have protected methods?

No. All methods in interfaces are public by default.

3. How do access modifiers affect inheritance?

Subclasses can’t access private members, but can access protected ones.

4. Can we override private methods?

No. They are not inherited.

5. What happens if no modifier is used?

It becomes package-private (default access).

6. Are fields in interfaces public?

Yes. Fields in interfaces are implicitly public static final.

7. Can constructors be private?

Yes. Useful in Singleton or Factory patterns.

8. Does protected allow access in unrelated packages?

No. Only subclasses outside the package can access.

9. Can abstract classes have private methods?

Yes. But they won’t be accessible to subclasses.

10. What’s the difference between protected and default?

protected allows subclass access outside the package, default does not.