Access Modifiers (public, private, protected)
Good objects hide their inner workings and expose only what's safe to touch. Access modifiers are the keywords that draw that boundary — they decide who can read and change each field, method, and class. Master them and you master encapsulation .
Learn Access Modifiers (public, private, protected) in our free Java course — a beginner-friendly interactive lesson with worked examples, a practice…
Part of the free Java course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
You'll want to be comfortable with classes and objects (fields, methods, constructors) and have seen inheritance , since protected only makes sense alongside subclasses.
💡 Analogy: Think of a class as a house. public members are the front door — anyone may walk through. protected is a door for family (subclasses) and neighbours in the same street (package). Package-private is a gate only your street's neighbours can open. private is your bedroom safe — only you, inside the house, can open it. Encapsulation is choosing the right door for each room so visitors can't wander into the wiring.
The golden rule: make everything as private as you can, and only open it up when you have a concrete reason. A small public surface is easier to use, test, and change without breaking callers.
Java has exactly four levels. Note that the third one — package-private — has no keyword: you get it by writing nothing at all.
Encapsulation means keeping an object's data private and exposing only safe, controlled methods to work with it. If a bank account's balance were public, any code could set it to -9999 and break the rules. Making it private forces every change to go through deposit and withdraw , which can enforce "no overdrafts" and "no negative deposits".
The example below is the classic case: the field is locked away, and the public methods are the only door in.
A getter returns a private field; a setter changes it. The reason they exist — instead of a public field — is that a setter can validate before storing. You can also expose a getter with no setter to make a field read-only, or compute a value on the fly that has no backing field at all.
Naming convention: getters are getX() (or isX() for booleans) and setters are setX(value) . Many frameworks (and the records feature) rely on this convention.
protected opens a member to subclasses (and to the same package), while still hiding it from unrelated outside code. Use it for the parts of a parent class that a child legitimately needs to read or override — but keep truly internal details private , hidden even from subclasses.
These lines form a properly encapsulated Score class with a private field and a validating setter. They've been shuffled.
Open the class, declare the private field, then the getter, then the setter whose body validates before storing, and finally close both the method and the class.
Predict the result before opening each answer.
Answer: It does not compile. n is private, so it is invisible to Main even though both are in the same file: error: n has private access in Box . You'd need a public getter to read it.
Answer: false 100.0 . The withdrawal of 150 exceeds the balance of 100, so withdraw returns false and leaves balance untouched — exactly the guarantee private + a guarded method gives you.
Answer: The return line fails because id is private — even a subclass can't see it. name is fine because it's protected . Remove id (or make it protected) and it compiles.
🎯 Your Turn #1 — Encapsulate a counter
Make the field private and provide controlled access. The count must only ever go up via increment() .
🎯 Your Turn #2 — Validating setter
Write a setter that rejects an email without an @ , keeping the previous value.
🧩 Mini-Challenge — Hide a password
Build a Password class that lets callers set and check a password but never read it back.
You now know all four access levels, why the keyword-less default is package-private, how protected reaches subclasses, and how private fields plus validating getters/setters give you real encapsulation. The habit to keep: make everything as private as possible.
Next up: Packages & Imports — how Java organises classes into namespaces and how you pull in code from elsewhere.
Practice quiz
Which access level applies when you write a field with NO access keyword at all?
- public
- protected
- package-private (default)
- private
Answer: package-private (default). No keyword means package-private: visible only within the same package, narrower than protected.
From most open to most restrictive, which ordering is correct?
- private, default, protected, public
- public, protected, default (package-private), private
- public, default, protected, private
- protected, public, private, default
Answer: public, protected, default (package-private), private. public ⊃ protected ⊃ package-private ⊃ private. Each level adds reach to the one below it.
What is the key difference between protected and package-private?
- They are identical
- protected also reaches subclasses in other packages; package-private does not
- package-private is broader than protected
- protected hides a member from the same package
Answer: protected also reaches subclasses in other packages; package-private does not. protected adds cross-package inheritance access on top of same-package access; package-private stays within one package.
A top-level class (not nested) may be declared as:
- public or package-private only
- any of the four levels
- private or protected only
- protected only
Answer: public or package-private only. private and protected are not allowed on a top-level class — only public or package-private (no keyword).
Why make a field private and expose a setter instead of a public field?
- It runs faster
- So the setter can validate input before storing it
- Private fields use less memory
- It is required by the compiler
Answer: So the setter can validate input before storing it. A setter can validate, log, or reject bad values; a public field can be set to anything, breaking invariants.
Inside a subclass, a parent's private field is:
- Accessible directly
- Accessible only with a cast
- NOT accessible — private hides it even from subclasses
- Accessible only in the same file
Answer: NOT accessible — private hides it even from subclasses. private means same class only. Subclasses cannot see a private member; use protected for members a child needs.
Two classes in the SAME file but different (top-level) classes. Class Main reads a private field of class Box. What happens?
- It compiles and prints the value
- It compiles with a warning
- Compile error: the field has private access in Box
- It prints null
Answer: Compile error: the field has private access in Box. private is invisible outside its own class even within one file. You need a public getter to read it.
A setter that just assigns the value with no validation gives you, over a public field:
- Much better performance
- Essentially nothing extra
- Automatic thread safety
- Compile-time constant checking
Answer: Essentially nothing extra. A no-op setter adds ceremony without benefit. Only add a setter when it validates, logs, or notifies.
Which combination best describes a field that can be read but never changed after construction?
- public field
- private final field set once in the constructor
- protected field with a setter
- package-private field
Answer: private final field set once in the constructor. private final, assigned once in the constructor, is immutable — no setter needed, and it cannot be corrupted.
The golden rule of access modifiers is:
- Make everything public for convenience
- Make everything as private as you can, opening up only with a concrete reason
- Always use protected
- Prefer package-private for all fields
Answer: Make everything as private as you can, opening up only with a concrete reason. A small public surface is easier to use, test, and change. Widen access only when you truly need to.