Java Access Modifiers
Control visibility in Java with the public, private, protected, and package-private (default) access modifiers.
Access modifiers decide who can see and use a class, field, method, or constructor. Java has four levels — public, protected, package-private (no keyword), and private — that range from "the whole world" to "only this class." Picking the right one is how you draw a boundary between an object's interface and its internals.
The four levels
From most permissive to most restrictive:
| Modifier | Visible from |
|---|---|
public | Anywhere |
protected | Same package, or any subclass (even in another package) |
| (no keyword) | Same package only — package-private |
private | Same class only |
That's it. No "friend", no "module-internal" at this level; module visibility is a separate Java Platform Module System feature you mostly don't need.
public
A public member is part of the class's published API — visible to any code that can see the class itself:
public class Greeter {
public String greet(String name) {
return "Hello, " + name;
}
}
new Greeter().greet("world"); // anyone can call thisUse public for the things you intend other code — even other projects — to call. The cost is that once something is public, you've committed to it; changing the signature breaks every caller.
private
private restricts a member to its declaring class. Nothing outside can touch it — not even a subclass:
public class Account {
private int balance; // only Account can read/write
public void deposit(int amount) {
if (amount <= 0) throw new IllegalArgumentException();
balance += amount; // ok — same class
}
}
Account a = new Account();
a.balance = -1; // ERROR — balance is privateThis is the workhorse for fields. Hiding state behind private is what makes the validation in deposit actually mean something. The encapsulation chapter goes into the pattern.
Package-private (no keyword)
Leave the modifier off entirely and the member is visible to everything in the same package — but nothing outside it:
// in package com.shop
class CartHelper { // no public — package-private
static int sum(int[] prices) { ... }
}Other classes in com.shop can call CartHelper.sum(...); code in com.app cannot even see the class exists. Use this for internal helpers that the package needs to share but that aren't part of the project's outward API.
A common mistake: leaving the modifier off because you forgot, then being surprised when the class can be used from main (also in the same package while you're learning) but not from a test in a different package.
protected
protected is package-private plus subclasses. Code in the same package can use the member, and any subclass — even one in a different package — can use it:
public class Shape {
protected double area; // subclasses can read/write
}
public class Circle extends Shape {
Circle(double r) {
this.area = Math.PI * r * r; // ok — subclass access
}
}This is the one to reach for when you want subclasses to be able to plug into the parent's machinery, but you don't want general client code touching it. In practice, protected shows up far less often than public or private; many designers prefer private fields with protected accessor methods for the same effect with more control.
Where modifiers apply
You can put a modifier on:
- A class itself (
public class Foo). Top-level classes can only bepublicor package-private. Inner classes can be any of the four. - A field (
private int count). - A method (
public int get() {...}). - A constructor (
private Singleton() {...}— see singleton pattern).
You cannot put an access modifier on a local variable or a method parameter. Those are scoped purely by where they're declared.
The "one public class per file" rule
A .java file may declare multiple top-level classes, but at most one of them can be public, and that one's name must match the filename:
// file: Order.java
public class Order { ... } // ok — matches filename
class OrderHelper { ... } // ok — package-private
public class Customer { ... } // ERROR — second public classMost projects keep one class per file regardless, but package-private helpers next to a public class are sometimes useful.
Choosing the right one
A rule of thumb that scales:
- Default to
privatefor fields and helper methods. publicthe methods you actually want called from outside.- Package-private for things that need to be shared inside a package but not exposed beyond it.
protectedonly when you specifically want subclass access too.
It's easy to widen access later (private → public); it's painful to narrow it without breaking callers. Start narrow.
Modifiers don't change behavior
An access modifier is a compile-time check. At runtime, two equal int fields behave identically whether they were declared public or private. The modifier exists purely to stop other code from compiling against the member — to enforce a boundary you're declaring.
A worked example
What's next
public, protected, private are access modifiers. Java has another family — the non-access modifiers like static, final, abstract, synchronized — that control behavior rather than visibility. The next chapter, non-access modifiers, is a tour of those.
Practice
A field is declared without any access modifier — just int count;. Who can read it?