Question
Java Access Modifiers Explained: public, protected, package-private, and private
Question
In Java, what are the clear rules for choosing between the access modifiers public, protected, package-private (the default), and private when designing classes and interfaces, especially when inheritance is involved?
Short Answer
By the end of this page, you will understand what each Java access modifier allows, where it can be used, and how it affects visibility from the same class, same package, subclasses, and other classes. You will also learn practical guidelines for choosing the most restrictive modifier that still supports your design.
Concept
In Java, access modifiers control who can see and use a class, method, field, or constructor.
These modifiers are a core part of encapsulation, which means hiding internal details and exposing only what other code truly needs.
Java has four access levels:
public— accessible from anywhereprotected— accessible within the same package, and in subclasses outside the package- package-private — accessible only within the same package; this is the default when no modifier is written
private— accessible only within the same class
Why this matters
Choosing the right access level helps you:
- protect internal implementation details
- prevent accidental misuse
- make APIs easier to understand
- reduce coupling between classes
- change code later without breaking other parts of the program
A common rule in real Java code is:
- start with the most restrictive access possible
- only make something more visible when there is a real need
Where each modifier can be used
For top-level types
Top-level classes and interfaces can only be:
public- package-private
They cannot be private or protected.
For members inside a class
Fields, methods, constructors, and nested classes can use all four:
Mental Model
Think of a class as a house with rooms and doors:
private= a locked personal drawer. Only the owner can open it.- package-private = rooms shared with people in the same building.
protected= rooms shared with the building, plus family members who live elsewhere.public= the front desk open to everyone.
The key idea is: not every door should be open.
Good Java design means opening only the doors that need to be open. The fewer things other code can depend on, the easier your code is to maintain.
Syntax and Examples
Basic syntax
public class PublicClass {
}
class PackagePrivateClass {
}
public class User {
private String password;
String username; // package-private
protected void reset() {}
public String getUsername() {
return username;
}
}
Example: fields and methods
package app;
public class Account {
private double balance;
String ownerName;
protected void logAccess() {
System.out.println("Access logged");
}
public double getBalance() {
return balance;
}
public {
(amount > ) {
balance += amount;
}
}
}
Step by Step Execution
Consider this example:
package demo;
class Counter {
private int count = 0;
public void increment() {
count++;
}
public int getCount() {
return count;
}
}
public class Main {
public static void main(String[] args) {
Counter counter = new Counter();
counter.increment();
counter.increment();
System.out.println(counter.getCount());
}
}
Step by step
-
Counter counter = new Counter();- A new
Counterobject is created. - Its
privatefieldcountstarts at .
- A new
Real World Use Cases
1. Hiding sensitive data
public class User {
private String passwordHash;
public boolean checkPassword(String input) {
return passwordHash.equals(input); // simplified example
}
}
Sensitive fields should not be directly accessible.
2. Exposing a public API
Libraries often make only a small set of classes and methods public so users interact with a stable API.
public class JsonParser {
public Object parse(String json) {
return null;
}
}
3. Keeping helpers inside a package
A package may contain utility classes meant only for internal use.
class TokenValidator {
static boolean isValid(String token) {
return token != && !token.isEmpty();
}
}
Real Codebase Usage
In real Java projects, access modifiers are usually chosen as part of API design.
Common patterns
private for fields
Most fields are private.
public class Product {
private String name;
private double price;
public String getName() {
return name;
}
}
This protects object state and allows validation later.
public for stable operations
Methods that form the intended API are often public.
public void addItem(Item item) {
if (item == null) {
throw new IllegalArgumentException("item cannot be null");
}
items.add(item);
}
package-private for internal collaboration
In larger codebases, several classes in one package may work together without exposing themselves to the rest of the system.
Common Mistakes
1. Making fields public
Broken design:
public class Person {
public int age;
}
Why this is a problem:
- any code can set invalid values
- you cannot easily add validation later
Better:
public class Person {
private int age;
public void setAge(int age) {
if (age < 0) {
throw new IllegalArgumentException("Age cannot be negative");
}
this.age = age;
}
public int getAge() {
return age;
}
}
2. Confusing package-private with protected
Many beginners think protected means “subclasses only.” It does not.
Comparisons
Access modifier comparison
| Modifier | Where usable | Visible in same class | Visible in same package | Visible in subclass in other package | Visible everywhere |
|---|---|---|---|---|---|
private | Members, nested classes | Yes | No | No | No |
| package-private | Top-level types, members, nested classes | Yes | Yes | No | No |
protected | Members, nested classes | Yes | Yes | Yes | No |
public |
Cheat Sheet
Quick rules
private= only inside the same class- package-private = no modifier; same package only
protected= same package + subclasses in other packagespublic= everywhere
Top-level class rules
Allowed:
public class A {}
class B {}
Not allowed:
protected class C {}
private class D {}
Member example
public class Example {
private int a;
int b;
protected int c;
public int d;
}
Best practice
- keep fields
private
FAQ
When should I use private in Java?
Use private for fields and helper methods that should only be used inside the class. This is the safest default.
What is package-private in Java?
Package-private is the default access level when no modifier is written. It allows access only within the same package.
Is protected only for subclasses?
No. protected also allows access from any class in the same package, even if it is not a subclass.
Can a top-level Java class be private?
No. A top-level class can only be public or package-private.
Should Java fields be public?
Usually no. Public fields expose internal state directly and make validation and future changes harder.
When should I use protected instead of package-private?
Use protected when subclasses outside the package need access. If access is only needed inside the same package, package-private is often better.
What is the safest default access modifier?
Usually private for members, and package-private for helper top-level classes that should stay internal to a package.
Mini Project
Description
Build a small Java example that models a bank account and uses all four access levels correctly. This project demonstrates encapsulation, package-level collaboration, and controlled inheritance.
Goal
Create a simple set of classes where sensitive data stays private, internal helpers remain package-private, subclasses use protected behavior, and public methods expose the safe API.
Requirements
- Create a
BankAccountclass with a private balance field. - Add public methods to deposit money and read the balance.
- Add a protected method that subclasses can use for audit behavior.
- Add a package-private helper class used only inside the same package.
Keep learning
Related questions
Avoiding Java Code in JSP with JSP 2: EL and JSTL Explained
Learn how to avoid Java scriptlets in JSP 2 using Expression Language and JSTL, with examples, best practices, and common mistakes.
Choosing a @NotNull Annotation in Java: Validation vs Static Analysis
Learn how Java @NotNull annotations differ, when to use each one, and how to choose between validation, IDE hints, and static analysis tools.
Convert a Java Stack Trace to a String
Learn how to convert a Java exception stack trace to a string using StringWriter and PrintWriter, with examples and common mistakes.