Back to Access Modifiers
Q1Question 1 of 1

What are the four access modifiers in Java?

Key Concepts
  • public: visible everywhere, to any class in any package
  • protected: visible in the same package + subclasses in other packages
  • default (no keyword): visible only within the same package (package-private)
  • private: visible only within the same class (not even subclasses)
  • Top-level classes can only be public or package-private – not private or protected
  • In banking: fields are private, service methods are public, internal helpers are package-private

Definition

Java has four access levels: public (everywhere), protected (same package + subclasses), default/package-private (same package), and private (same class only).

Four levels from most open to most restricted:

  • public – accessible from any class in any package. Use for API methods and service interfaces.
  • protected – accessible within the same package, and by subclasses in other packages. Use sparingly for inheritance.
  • default (package-private) – no keyword written. Accessible only within the same package. Use for internal implementation classes.
  • private – accessible only within the declaring class. Not visible to subclasses or other classes. Use for all fields and internal methods.

A bank building with four security levels. Public areas (lobby) are open to everyone. Protected areas (back office) are accessible to employees of this branch and managers from other branches (subclasses). Package-private areas (operations room) are only for employees of this specific branch. Private areas (the vault) are accessible only to the vault officer (the class itself).

Understanding the Concepts

What is the visibility of each modifier?

| Modifier | Same class | Same package | Subclass (other package) | Other package |
|---|---|---|---|---|
| public | Yes | Yes | Yes | Yes |
| protected | Yes | Yes | Yes | No |
| default (none) | Yes | Yes | No | No |
| private | Yes | No | No | No |

How does each modifier work in code?

JAVA
package com.bank.core;

public class Account {
    public String accountId;          // visible everywhere
    protected String holderName;      // visible in package + subclasses
    String branchCode;                // package-private (no keyword)
    private BigDecimal balance;       // visible only inside Account

    public BigDecimal getBalance() {   // public getter
        return balance;
    }

    private void validateBalance() {   // only Account can call this
        if (balance.signum() < 0) {
            throw new IllegalStateException("Negative balance");
        }
    }
}
JAVA
package com.bank.core;  // SAME package

public class TransferService {
    public void transfer(Account from, Account to, BigDecimal amount) {
        // public field: accessible
        System.out.println(from.accountId);

        // protected field: accessible (same package)
        System.out.println(from.holderName);

        // package-private field: accessible (same package)
        System.out.println(from.branchCode);

        // private field: NOT accessible
        // System.out.println(from.balance);  // COMPILE ERROR
        System.out.println(from.getBalance());  // use public getter

        // private method: NOT accessible
        // from.validateBalance();  // COMPILE ERROR
    }
}
JAVA
package com.bank.mobile;  // DIFFERENT package

import com.bank.core.Account;

public class MobileApp {
    public void display(Account account) {
        // public: accessible
        System.out.println(account.accountId);

        // protected: NOT accessible (different package, not a subclass)
        // System.out.println(account.holderName);  // COMPILE ERROR

        // package-private: NOT accessible
        // System.out.println(account.branchCode);  // COMPILE ERROR

        // private: NOT accessible
        // System.out.println(account.balance);  // COMPILE ERROR
    }
}

How does protected work with subclasses?

Protected fields are accessible to subclasses even in different packages:

JAVA
package com.bank.savings;  // DIFFERENT package

import com.bank.core.Account;

public class SavingsAccount extends Account {
    public void showHolder() {
        // protected: accessible because SavingsAccount is a subclass
        System.out.println(this.holderName);  // works!

        // package-private: NOT accessible (different package)
        // System.out.println(this.branchCode);  // COMPILE ERROR
    }
}

Important: the subclass can access protected members on this or on instances of itself. It cannot access them on an arbitrary Account reference from a different package.

What access modifiers are allowed on top-level classes?

Top-level classes (not nested inside another class) can only be:

  • public – visible to all packages. The file must be named after the class.
  • package-private (default) – visible only within its own package. No keyword needed.
JAVA
// OK: public top-level class
public class Account { ... }

// OK: package-private top-level class
class InternalHelper { ... }

// NOT OK: private top-level class
// private class Secret { ... }  // COMPILE ERROR

// NOT OK: protected top-level class
// protected class SemiPublic { ... }  // COMPILE ERROR

Private and protected only make sense for members (fields, methods, inner classes) that are inside another class. A top-level class has no enclosing class to be private or protected relative to.

What access modifiers are allowed on nested/inner classes?

Nested classes can use all four modifiers:

JAVA
public class Account {
    public static class Builder { ... }          // public nested
    protected static class Validator { ... }     // protected nested
    static class Formatter { ... }               // package-private nested
    private static class Cache { ... }           // private nested
}

What is the correct encapsulation pattern for banking entities?

JAVA
public class Account {
    // ALL fields private – never expose state directly
    private final String accountId;
    private BigDecimal balance;
    private boolean active;

    // Constructor validates inputs
    public Account(String accountId, BigDecimal initialBalance) {
        this.accountId = Objects.requireNonNull(accountId);
        this.balance = initialBalance;
        this.active = true;
    }

    // Public methods control access with validation
    public void debit(BigDecimal amount) {
        if (amount.signum() <= 0) throw new IllegalArgumentException("Positive amount required");
        if (balance.compareTo(amount) < 0) throw new IllegalStateException("Insufficient funds");
        balance = balance.subtract(amount);
    }

    // Read-only access
    public BigDecimal getBalance() { return balance; }
    public String getAccountId() { return accountId; }
    public boolean isActive() { return active; }

    // Internal helper – private, not part of the API
    private void audit(String action, BigDecimal amount) {
        // log for internal audit trail
    }
}

Rule: fields are always private. Methods that external code calls are public. Methods used only within the class are private. Methods used within the package are default (package-private).

What are common mistakes?

  • Making fields public. public BigDecimal balance lets anyone set it to a negative number. Use private + controlled methods.
  • Using protected when default is enough. Protected is for inheritance across packages. If you do not need that, use default.
  • Confusing default with public. If no modifier is written, the member is package-private (NOT public). void transfer() is only visible in the same package.
  • Accessing protected via a different class reference. A subclass in another package can access this.protectedField but not someOtherAccount.protectedField.

What should a senior engineer know?

  • Modules (Java 9+) add another layer. Even public classes must be exports-ed from their module to be visible to other modules. A public class in a non-exported package is invisible outside the module.
  • Interfaces: methods are implicitly public. You cannot make an interface method private (before Java 9) or package-private. Java 9+ allows private methods in interfaces for code reuse within default methods.
  • Reflection can bypass access modifiers. field.setAccessible(true) makes a private field accessible. But Java modules restrict this via --add-opens.
  • Records: components generate public getters. A record component String accountId generates a public accountId() method. The component itself is private final.
  • Encapsulation is not just about getters. A setBalance(BigDecimal) method is almost as bad as a public field. Provide behavior methods (debit, credit) instead of setters.

Visual Overview

DIAGRAM
  Access modifier visibility:

                Same class  Same package  Subclass (other pkg)  Other package
  public          Yes          Yes              Yes                  Yes
  protected       Yes          Yes              Yes                  No
  default         Yes          Yes              No                   No
  private         Yes          No               No                   No

  Top-level class: only public or default
  Inner class: all four modifiers allowed

  Banking pattern:
    Fields     → private (always)
    Getters    → public
    Behavior   → public (debit, credit)
    Helpers    → private or default
    Interfaces → public

Key Takeaway

Java has four access modifiers that control visibility: public (everywhere), protected (same package plus subclasses), default or package-private (same package only, no keyword written), and private (same class only).

In banking code, the pattern is consistent. All fields are private to prevent external code from corrupting state. Public methods like debit() and credit() validate inputs and enforce business rules. Internal helper methods are private. Classes shared within the package but not with external code use package-private access.

Top-level classes can only be public or package-private. Private and protected are only for members inside a class. And since Java 9, the module system adds another layer: even public classes must be explicitly exported from their module to be visible to other modules.

One sentence to remember: public means everywhere, protected means package plus subclasses, default means same package, private means same class – and fields should always be private.

---

Share