Access Modifiers
Access Modifiers in Java
Access modifiers control visibility of classes, methods, and variables.
Four Access Levels
public class AccessExample {
public int publicVar = 1; // Everywhere
protected int protectedVar = 2; // Same package + subclasses
int defaultVar = 3; // Same package only
private int privateVar = 4; // This class only
}
Package Structure
// File: com/example/Person.java
package com.example;
public class Person {
public String name; // Accessible everywhere
protected int age; // Accessible in com.example + subclasses
String email; // Accessible in com.example only
private String password; // Accessible in Person only
}
// File: com/example/Student.java
package com.example;
public class Student extends Person {
public void test() {
System.out.println(name); // OK
System.out.println(age); // OK (subclass)
System.out.println(email); // OK (same package)
// System.out.println(password); // ERROR!
}
}
// File: com/other/Main.java
package com.other;
public class Main {
public void test() {
Person p = new Person();
System.out.println(p.name); // OK
// System.out.println(p.age); // ERROR!
// System.out.println(p.email); // ERROR!
// System.out.println(p.password); // ERROR!
}
}
Summary Table
| Modifier | Class | Package | Subclass | World |
|---|---|---|---|---|
| public | Y | Y | Y | Y |
| protected | Y | Y | Y | N |
| default | Y | Y | N | N |
| private | Y | N | N | N |
Getters and Setters
Getters and Setters
Getter and setter methods provide controlled access to private fields.
Basic Getters and Setters
public class Person {
private String name;
private int age;
// Getter
public String getName() {
return name;
}
// Setter
public void setName(String name) {
this.name = name;
}
// Getter
public int getAge() {
return age;
}
// Setter with validation
public void setAge(int age) {
if (age >= 0 && age <= 150) {
this.age = age;
} else {
throw new IllegalArgumentException("Invalid age");
}
}
}
Boolean Getters
public class Employee {
private boolean active;
private boolean isManager;
// For boolean, use is prefix
public boolean isActive() {
return active;
}
// For isXxx fields, use getXxx
public boolean getIsManager() {
return isManager;
}
public void setActive(boolean active) {
this.active = active;
}
}
Read-Only Properties
public class Circle {
private double radius;
private final String id; // Set only in constructor
public Circle(double radius, String id) {
this.radius = radius;
this.id = id;
}
// Getter only - no setter
public double getRadius() {
return radius;
}
public String getId() {
return id;
}
// Calculated property
public double getArea() {
return Math.PI * radius * radius;
}
}
Builder Pattern with Setters
public class User {
private String name;
private int age;
private String email;
private User() { }
public static Builder builder() {
return new Builder();
}
public static class Builder {
private User user = new User();
public Builder name(String name) {
user.name = name;
return this;
}
public Builder age(int age) {
user.age = age;
return this;
}
public Builder email(String email) {
user.email = email;
return this;
}
public User build() {
return user;
}
}
}
User user = User.builder()
.name("Alice")
.age(25)
.email("alice@example.com")
.build();
Data Hiding
Data Hiding Benefits
Data hiding protects internal state and provides controlled access.
Why Hide Data?
public class BankAccount {
private double balance;
// Without encapsulation - anyone can manipulate
// public double balance; // DANGEROUS!
// account.balance = -1000; // No validation!
// With encapsulation - controlled access
public double getBalance() {
return balance;
}
public void deposit(double amount) {
if (amount > 0) {
balance += amount;
}
}
public void withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
}
}
}
Invariant Protection
public class Date {
private int day;
private int month;
private int year;
public void setDay(int day) {
if (day < 1 || day > 31) {
throw new IllegalArgumentException("Invalid day");
}
this.day = day;
}
public void setMonth(int month) {
if (month < 1 || month > 12) {
throw new IllegalArgumentException("Invalid month");
}
this.month = month;
}
}
Implementation Flexibility
public class Employee {
private String firstName;
private String lastName;
// Can change internal representation without affecting clients
public String getFullName() {
return firstName + " " + lastName;
}
// Later, change to single name field
// Client code still works!
}
Validation
public class User {
private String email;
public void setEmail(String email) {
if (email == null || !email.contains("@")) {
throw new IllegalArgumentException("Invalid email");
}
this.email = email.toLowerCase();
}
}
Best Practices
// 1. Always make fields private
private int count;
// 2. Provide public getters/setters
public int getCount() { return count; }
// 3. Validate in setters
public void setCount(int count) {
if (count < 0) throw new IllegalArgumentException();
this.count = count;
}
// 4. Make classes final if not meant to be extended
public final class ImmutableClass { }
Practice Problems
Design a phone directory that stores phone numbers for given numbers.
Example:
Input: add(1, "Alice"), get(1)
Output: Alice
Basic CRUD operations
Optimal Solution — O(1) time, O(n) space
Use HashMap for O(1) operations.
class PhoneDirectory {
private Map<Integer, String> contacts;
public PhoneDirectory() { contacts = new HashMap<>(); }
public void add(int num, String name) { contacts.put(num, name); }
public String get(int num) { return contacts.getOrDefault(num, null); }
}Edge Cases:
- Add duplicate
- Get non-existent
- Empty directory
Design a logger that prints messages with timestamps.
Example:
Input: log("msg1", 1), log("msg2", 2)
Output: true
Logger stores messages
Optimal Solution — O(1) time, O(n) space
Use HashSet to track messages.
class Logger {
private Set<String> messages;
public Logger() { messages = new HashSet<>(); }
public boolean shouldPrint(int timestamp, String message) {
if (messages.add(message)) { return true; }
return false;
}
}Edge Cases:
- Duplicate message
- Empty message
- Same timestamp
Quiz
1. Which access modifier allows access only within the same class?
2. What is the benefit of encapsulation?
3. What is a getter method?
4. What is the primary purpose of Encapsulation?
Flashcards
Question
What is encapsulation?
Click to reveal answer
Answer
Bundling data with methods that operate on that data, hiding internal state behind public interfaces.
Question
What is the difference between public and private?
Click to reveal answer
Answer
public is accessible everywhere. private is only accessible within the same class.
Question
Why use getters and setters?
Click to reveal answer
Answer
To control access to private fields, add validation, and maintain encapsulation.
Question
What is Encapsulation?
Click to reveal answer
Answer
Encapsulation is a key concept in Java programming.
Question
When to use Encapsulation?
Click to reveal answer
Answer
Use Encapsulation when building production systems that require reliability, scalability, and maintainability.
Revision Notes
Key Takeaways
- 1.Always make fields private
- 2.Use getters/setters for access
- 3.Validate in setters
- 4.Encapsulation enables flexibility
Interview Tips
- •Know all four access modifiers
- •Understand when to use each modifier
- •Practice designing encapsulated classes
- •Know benefits of data hiding
Cheat Sheet
Cheat Sheet
- public: everywhere
- protected: same package + subclasses
- default: same package
- private: same class
- Getter: returns field value
- Setter: sets field value with validation