Access Modifiers in Java

Naveen AnamaneniUpdated · 5 min read

In an office, some rooms are open to visitors, some only to staff, some only to one team, and a locker is for its owner alone. Java has the same four levels for code. An access modifier on a class, field, method or constructor decides who may use it: only its own class (private), its package (no modifier), its package plus subclasses (protected), or everyone (public).

The Four Levels

Each level opens one more door
ModifierSame classSame packageSubclass in another packageEverywhere
privateYesNoNoNo
(none), package-privateYesYesNoNo
protectedYesYesYes, through inheritanceNo
publicYesYesYesYes

In a Real Project

The bank project from this chapter has three packages. Account lives in com.poolstring.bank.model and uses all four levels:

src/com/poolstring/bank/model/Account.java
package com.poolstring.bank.model;
 
public class Account {
    private final String holder;
    private long balance;
 
    public Account(String holder, long opening) {
        this.holder = holder;
        this.balance = opening;
    }
 
    public String getHolder() { return holder; }
    public long getBalance() { return balance; }
 
    void adjust(long amount) { balance += amount; }
 
    protected void audit(String note) {
        System.out.println("[audit] " + holder + ": " + note);
    }
 
    public boolean withdraw(long amount) {
        if (amount <= 0 || amount > balance) {
            return false;
        }
        adjust(-amount);
        audit("withdraw " + amount);
        return true;
    }
 
    public void deposit(long amount) {
        if (amount <= 0) {
            throw new IllegalArgumentException("Deposit must be positive");
        }
        adjust(amount);
        audit("deposit " + amount);
    }
}
MemberLevelWhy
holder, balanceprivateOnly Account's own methods may change them
adjustpackage-privateA low-level helper for classes in the model package only
auditprotectedSubclasses such as a premium account may add audit lines
Constructor, getters, deposit, withdrawpublicThe API the rest of the program uses

A class in another package, com.poolstring.bank.app, tries each one:

src/com/poolstring/bank/app/Peek.java
package com.poolstring.bank.app;
 
import com.poolstring.bank.model.Account;
 
public class Peek {
    public static void main(String[] args) {
        Account a = new Account("Srihitha", 500);
        a.balance = 1000000;
        a.adjust(50);
        a.audit("peek");
    }
}
Terminal
javac -cp out -d out src/com/poolstring/bank/app/Peek.java
Terminal output
src/com/poolstring/bank/app/Peek.java:8: error: balance has private access in Account
        a.balance = 1000000;
         ^
src/com/poolstring/bank/app/Peek.java:9: error: adjust(long) is not public in Account; cannot be accessed from outside package
        a.adjust(50);
         ^
src/com/poolstring/bank/app/Peek.java:10: error: audit(String) has protected access in Account
        a.audit("peek");
         ^
3 errors

The compiler enforces all three levels: private, package-private and protected are all closed to an unrelated class in another package.

The protected Rule

protected opens a member to subclasses in other packages, but only through inheritance: a subclass may call it on itself (or on objects of its own type), not on any Account it happens to hold:

src/com/poolstring/bank/app/PremiumAccount.java
package com.poolstring.bank.app;
 
import com.poolstring.bank.model.Account;
 
public class PremiumAccount extends Account {
    public PremiumAccount(String holder, long opening) {
        super(holder, opening);
    }
 
    public void review(Account other) {
        audit("premium review");
        other.audit("not allowed");
    }
}
Terminal output
src/com/poolstring/bank/app/PremiumAccount.java:12: error: audit(String) has protected access in Account
        other.audit("not allowed");
             ^
1 error

Line 11, audit(...) on itself, compiles. Line 12, on another Account, doesn't.

Modifiers on Classes

WhereAllowed modifiers
Top-level class or interfacepublic or none (package-private)
Nested class, field, method, constructorAll four
Interface memberspublic by default; private allowed for helper methods

A file can contain at most one public top-level class, and the file must be named after it:

Compiler output
Shop.java:1: error: class Cart is public, should be declared in a file named Cart.java
public class Cart { }
       ^
1 error

Common Mistakes

Making everything public. Every public member is a promise you must keep; start private.

Expecting protected to hide from the package. Classes in the same package can use protected members freely.

Forgetting that package-private is the default. A method without a modifier isn't public; code in other packages can't call it.

Interview Corner

What are the access modifiers in Java?

There are four levels. private allows access only within the same class. Package-private, the default with no keyword, allows access within the same package. protected allows access within the package and from subclasses in other packages through inheritance. public allows access from everywhere. Top-level classes can only be public or package-private.

Can a subclass in another package call a protected method on a parent-type object?

Not on an arbitrary parent-type object. Outside the package, a subclass can access a protected member only through references of its own type or a subtype, such as this.audit(). Calling other.audit() on a plain Account reference is a compile error.

Practice

  1. Easy: For each member of Account, say whether TransferService in com.poolstring.bank.service can use it.
  2. Harder: Move Peek into the model package (change its package line and folder). Which of the three errors disappear, and why?

Quick check: Access modifiers

4 questions
1A method has no access modifier. Who can call it?
2Which level allows subclasses in other packages but not unrelated classes there?
3Which modifiers can a top-level class have?
4Order the levels from most to least restrictive:

Key Takeaways

Was this tutorial helpful?

Lesson 144 of 482