This is an advanced topic, and you can skip it for now if you want.
Access modifiers in Java control who can see and use your classes, methods, and variables. Think of them as different levels of privacy - like having a public park, a private home, a family room, or a room shared with neighbors.
Understanding access modifiers is crucial for writing secure, well-organized Java programs.
Java has four access modifiers, from most restrictive to most open:
-
private - Only the same class can access
-
package-private (no modifier) - Only classes in the same package can access
-
protected - Same package + subclasses can access
-
public - Everyone can access
private means only the same class can access the member.
This is the most restrictive access level.
public class Student {
private String socialSecurityNumber; // Only Student class can access
private int age; // Only Student class can access
public void setAge(int newAge) {
if (newAge >= 0 && newAge <= 150) {
this.age = newAge; // OK - same class
}
}
public int getAge() {
return this.age; // OK - same class
}
}
public class School {
public void enrollStudent() {
Student student = new Student();
// student.age = 25; // ERROR! Cannot access private field
student.setAge(25); // OK - using public method
}
}public means anyone can access the member from anywhere.
public class Calculator {
public int add(int a, int b) { // Anyone can call this method
return a + b;
}
public static final double PI = 3.14159; // Anyone can access this constant
}
public class ZipCode {
void compute() {
Calculator calc = new Calculator();
int result = calc.add(5, 3); // OK - public method
System.out.println("PI = " + Calculator.PI); // OK - public field
}
public static void main(String[] args) { new ZipCode().compute(); }
}When you don’t specify an access modifier, it defaults to package-private. Only classes in the same package can access the member.
public class BankAccount {
String accountNumber; // Package-private (no modifier)
double balance; // Package-private (no modifier)
void deposit(double amount) { // Package-private method
balance += amount;
}
}
// In the same package
public class BankManager {
public void processAccount() {
BankAccount account = new BankAccount();
account.balance = 1000.0; // OK - same package
account.deposit(500.0); // OK - same package
}
}protected allows access from the same package AND from subclasses (inheritance - we’ll learn more about this later).
public class Vehicle {
protected String engine; // Subclasses can access
protected int maxSpeed; // Subclasses can access
protected void startEngine() { // Subclasses can access
System.out.println("Engine started");
}
}
public class Car extends Vehicle {
public void drive() {
this.engine = "V6"; // OK - Car is a subclass of Vehicle
this.maxSpeed = 120; // OK - protected access
startEngine(); // OK - protected method
}
}public class Person {
private String name; // Private by default
private int age; // Private by default
// Public methods to access private data
public String getName() {
return name;
}
public void setName(String name) {
if (name != null && !name.trim().isEmpty()) {
this.name = name;
}
}
public int getAge() {
return age;
}
public void setAge(int age) {
if (age >= 0 && age <= 150) {
this.age = age;
}
}
}public class MathUtils {
// Public - part of the class's API
public static double calculateArea(double radius) {
return PI * radius * radius;
}
// Private - internal helper method
private static final double PI = 3.14159;
// Private - not meant for external use
private static void validateInput(double value) {
if (value < 0) {
throw new IllegalArgumentException("Value cannot be negative");
}
}
}Here’s a complete example showing proper use of access modifiers.
Notice how the methods are public but the instance variables that hold the
key information about the account are marked private.
This ensures that anyone using this class in their code can only adjust
the private variables using the public methods.
That is a very common pattern used in Java programs.
public class BankAccount {
private String accountNumber; // Private - sensitive data
private double balance; // Private - should be controlled
private String ownerName; // Private - personal information
// Public constructor
public BankAccount(String accountNumber, String ownerName) {
this.accountNumber = accountNumber;
this.ownerName = ownerName;
this.balance = 0.0;
}
// Public methods for controlled access
public void deposit(double amount) {
if (amount > 0) {
balance += amount;
System.out.println("Deposited: $" + amount);
}
}
public boolean withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
System.out.println("Withdrew: $" + amount);
return true;
}
return false;
}
public double getBalance() {
return balance;
}
public String getAccountNumber() {
return accountNumber;
}
// Private helper method
private boolean isValidAmount(double amount) {
return amount > 0;
}
}
public class ZipCode {
void compute() {
BankAccount account = new BankAccount("12345", "John Doe");
account.deposit(1000.0); // OK - public method
account.withdraw(250.0); // OK - public method
// account.balance = 5000.0; // ERROR! Cannot access private field
System.out.println("Balance: $" + account.getBalance()); // OK - public method
}
public static void main(String[] args) { new ZipCode().compute(); }
}| Modifier | Same Class | Same Package | Subclass | Everywhere |
|---|---|---|---|---|
private |
✅ Yes |
❌ No |
❌ No |
❌ No |
package-private |
✅ Yes |
✅ Yes |
❌ No |
❌ No |
protected |
✅ Yes |
✅ Yes |
✅ Yes |
❌ No |
public |
✅ Yes |
✅ Yes |
✅ Yes |
✅ Yes |
-
Encapsulation - Hide internal implementation details
-
Security - Protect sensitive data from unauthorized access
-
Maintainability - Control how your class is used by others
-
Debugging - Easier to track where data is modified
-
API Design - Clearly define what’s public vs internal
-
Making everything public - This breaks encapsulation
-
Not using getters/setters - Direct field access bypasses validation
-
Forgetting access modifiers - Default package-private may not be what you want
Access modifiers are fundamental to writing professional, secure Java code. They help you control the interface of your classes and protect your data!