Learning outcome: Explain how public, private, protected, and default access control visibility and support encapsulation.
Access modifiers control where a class, field, method, or constructor can be used. They are one of Java's main tools for data privacy and encapsulation.
Java has four access levels: public, private, protected, and default access, also called package-private access, which applies when no modifier is written.
A class groups fields, methods, and constructors. An access modifier placed before one of these members determines which other parts of a program may use it. This brief class context is sufficient for understanding access control; class design is developed fully in Chapter 1.2.
Java API, Packages, and Imports
Package boundaries determine what default and protected access mean.
In simple terms: A package is a folder with a full postal name. Two classes called Node coexist happily in different packages, exactly as two files called notes.txt can live in different folders.
The Java API is the standard library supplied with the JDK. It is organized into packages, classes, interfaces, methods, fields, and constructors. To use a class from another package, a program normally imports it.
import java.util.Scanner;
In this import:
| Part | Meaning |
|---|---|
java |
Top-level package |
util |
Subpackage |
Scanner |
Class inside java.util |
Packages help with:
| Benefit | Explanation |
|---|---|
| Organization | Related classes are grouped together. |
| Reuse | Classes can be imported and used in other programs. |
| Name conflict control | Two packages can contain classes with the same name. |
| Access control | Default access is limited to the same package. |
When present, the package declaration is the first declaration in a compilation unit (comments and whitespace may precede it). Import declarations come after the package declaration and before type declarations.
package anotherpackage;
import java.util.Scanner;
public class Example {
// class body
}
Access Levels
| Access level | Declaring class and its nest | Same package | Subclass in another package | Any class anywhere |
|---|---|---|---|---|
private |
Yes | No | No | No |
| default, no modifier | Yes | Yes | No | No |
protected |
Yes | Yes | Yes | No |
public |
Yes | Yes | Yes | Yes |
The cross-package protected entry has an important restriction: subclass access is provided through inheritance. Code in the subclass cannot use an arbitrary superclass object merely because the member is protected; for an instance member, the qualifying reference must have the subclass's type or a subtype of it.
private is most restrictive; public is least restrictive.public
The public modifier makes a member accessible from any class in any package.
In simple terms: public is a notice board in the town square. Anyone, from anywhere, can read it — and once published, you are committed to keeping it there.
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello");
}
}
Typical uses:
| Use | Example |
|---|---|
| Program entry point | public static void main(String[] args) |
| API methods intended for other classes | public void deposit(double amount) |
| Top-level class intended for use outside its package | public class Student |
Use public only for behaviour that should genuinely be available to other code.
private
The private modifier confines a member to its declaring top-level class nest. In ordinary examples this means the declaring class itself; nested classes enclosed by the same top-level class can also access one another's private members.
In simple terms: private is a diary in a locked drawer. Only code inside the same top-level class can open it: not subclasses, not the rest of the package.
public class Account {
private double balance;
public double getBalance() {
return balance;
}
public void deposit(double amount) {
if (amount > 0) {
balance = balance + amount;
}
}
}
Here, balance cannot be changed directly from outside the class. Other code must use the public methods, where validation can be applied.
This is the basis of encapsulation: keep internal data private and expose controlled behaviour.
protected
In simple terms: protected is a family recipe. Relatives get it wherever they live, and so do the neighbours in the same package — but a stranger from another package does not.
The protected modifier allows access:
- Inside the same class.
- From classes in the same package.
- From subclasses, even when the subclass is in another package.
class Animal {
protected String name;
protected void describe() {
System.out.println("Animal: " + name);
}
}
class Dog extends Animal {
public void bark() {
System.out.println(name + " says woof");
}
}
protected is mainly useful when a parent class wants to share selected details with child classes without making those details fully public.
In the same package, protected also behaves like package access, so non-subclass neighbours can use the member. Across packages, only subclass code receives the special inherited access, subject to the qualifying-reference rule above.
Default Access
If no access modifier is written, Java uses default access, also called package-private access.
In simple terms: Default access is a note pinned inside one office. Everyone in that office — the package — can read it; nobody outside can, not even a subclass living elsewhere.
class Helper {
void showMessage() {
System.out.println("Package helper");
}
}
Helper and showMessage are accessible only to classes in the same package.
Default access is useful for helper classes and methods that belong inside one package but should not be part of the public API.
Top-Level Classes vs Members
Access rules differ for top-level classes and class members.
| Program element | Allowed access levels |
|---|---|
| Top-level class | public or default |
| Field | public, protected, default, private |
| Method | public, protected, default, private |
| Constructor | public, protected, default, private |
| Nested class | public, protected, default, private |
A top-level class cannot be declared private or protected.
Encapsulation and Data Privacy
Encapsulation means bundling data and behaviour inside a class while restricting direct access to internal data.
The normal pattern is:
- Make fields
private. - Provide
publicmethods for controlled access. - Validate changes inside those methods.
public class BankAccount {
private double balance;
public BankAccount(double initialBalance) {
if (initialBalance < 0) {
throw new IllegalArgumentException("Initial balance must not be negative");
}
balance = initialBalance;
}
public double getBalance() {
return balance;
}
public boolean withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance = balance - amount;
return true;
}
return false;
}
}
This class prevents code like this:
// account.balance = -5000; // does not compile if balance is private
All changes must go through controlled methods.
Access Modifier Selection Guide
| If the member should be... | Use |
|---|---|
| Hidden implementation detail within one class nest | private |
| Shared only inside the package | default access |
| Shared with subclasses | protected |
| Part of the public API | public |
Prefer the most restrictive access level that still supports the design.
Common Mistakes
| Mistake | Correction |
|---|---|
Making every field public |
Use private fields and public methods. |
Thinking protected means package-only |
It also allows subclass access. |
Assuming a cross-package subclass may access protected through any parent object |
Outside the package, access must occur through inheritance and an appropriately typed subclass reference. |
Trying to declare a top-level class private |
Top-level classes can be only public or default. |
Confusing default access with public |
Default access is limited to the same package. |
Practice
Problem 1: Choose the Modifier
Choose a suitable access level:
- A
balancefield inBankAccount. - A
mainmethod. - A helper method used only inside the same class nest.
- A method intended for child classes.
- A package-only utility class.
Problem 2: Fix the Class
Improve the design:
public class Student {
public int marks;
}
Possible answer:
public class Student {
private int marks;
public int getMarks() {
return marks;
}
public void setMarks(int marks) {
if (marks < 0 || marks > 100) {
throw new IllegalArgumentException("Marks must be from 0 to 100");
}
this.marks = marks;
}
}
Quick Check
1. Which access modifier is most restrictive?
private is the most restrictive access modifier. Access is confined to the declaring top-level class nest, which includes its nested classes.
2. What access level is used when no modifier is written?
Java uses default access, also called package-private access. The member is accessible only inside the same package.
3. Which modifier allows access from subclasses?
protected allows access from subclasses, and it also allows access from classes in the same package.
4. Can a top-level class be private?
No. A top-level class can be only public or default access. It cannot be private or protected.
5. May a nested class access a private member of its enclosing class?
Yes. Nested classes in the same top-level class nest may access one another's private members.
6. How do access modifiers support encapsulation?
They hide internal data and expose only controlled methods. A common pattern is to keep fields private and provide public methods that validate access or changes.
Lecture Quiz
1. Which access specifier must be used for the main() method?
public must be used so the JVM can access the entry point from outside the class.
2. Which statement is incorrect? (a) Public members are the most widely accessible. (b) Private members are confined to the declaring class nest. (c) Private members become protected in a subclass. (d) Protected members support subclass access.
Answer: (c) is incorrect. Private members are not directly accessible in subclasses and do not become protected.
3. Does import abc.*; automatically import classes from subpackages such as abc.foo?
No. A wildcard import imports classes directly inside that package only. To use classes from a subpackage, import the subpackage separately, for example import abc.foo.*;.
Summary
Access modifiers decide who can use a class member. private hides implementation details, default access keeps code inside a package, protected supports inheritance, and public exposes behaviour widely. Good Java design usually keeps fields private and exposes controlled methods.