Java Day-23
Java Notes: Encapsulation, Getters, Setters, and Data Validation
1. What is Encapsulation?
Encapsulation is a fundamental principle of Object-Oriented Programming (OOP). It is the technique of binding (or “capsuling”) an object’s private data (its fields) with the public methods that operate on that data.
Think of it like a medical capsule:
- Private Fields (the medicine): The internal data is protected and hidden from the outside world.
- Public Methods (the capsule shell): These are the only way to interact with the internal data.
The main goal of encapsulation is to provide security and control. By hiding the data, we prevent other classes from accessing or modifying it directly. This allows us to add proper data validation inside our public methods, ensuring the object’s state is always valid.
2. How to Achieve Encapsulation
You follow two simple rules to create an encapsulated class:
- Data Hiding: Declare all data members (instance variables or fields) as
private. This makes them inaccessible from outside the class. - Public Access: Write public methods to read and write the private data. These are called getters (accessors) and setters (mutators).
3. Getters and Setters
Getters and Setters are the public methods used to control access to your private fields.
Getter (Accessor Method)
- Purpose: To read (get) the value of a private field from outside the class.
- Return Type: Its return type must match the data type of the field it is reading (e.g.,
String,double,int). - Example:
- Java
// "getter" for the private 'salary' field public double getSalary() { return this.salary; }
Setter (Mutator Method)
- Purpose: To modify (set) the value of a private field.
- Return Type: It almost always has a
voidreturn type. - Key Feature: This is the perfect place to put data validation logic to protect your field.
- Example:
- Java
// "setter" for the private 'salary' field public void setSalary(double salary) { // Validation logic if (salary < 0) { System.err.println("Salary cannot be negative."); } else { this.salary = salary; } }
4. The Power of Validation (Why Encapsulation is Crucial)
By forcing all data changes to go through a setter method or a constructor, we can add logic to reject bad data and keep our object in a valid state.
You can (and should) add validation in two key places:
1. Validation in the Constructor: This ensures an object can never be created with invalid data in the first place.
Java
// Example from your notes
public class Product {
private int id;
private String name;
private double price; // Validation inside the parameterized constructor
public Product(int id, String name, double price) {
if (id < 0 || name == null || name.isBlank() || price < 0) {
System.err.println("Invalid Data: Cannot create product.");
System.exit(0); // Stop the program
}
this.id = id;
this.name = name;
this.price = price;
}
// ... other methods ...
}2. Validation in the Setter Method: This ensures an object’s state cannot be changed to an invalid one after it has been created.
Get Aman Verma’s stories in your inbox
Join Medium for free to get updates from this writer.
Java
// Example from your notes
public class Employee {
private String name;
private double salary;
// ... constructor ... // Validation inside the setter
public void setSalary(double salary) {
// Example: a salary can only be increased, not decreased
if (salary < this.salary) {
System.err.println("Invalid Data: Salary cannot be reduced.");
System.exit(0); // Stop the program
}
this.salary = salary;
}
// ... other methods ...
}5. Full Program Example (Employee)
This example ties everything together: private fields, a constructor, getters, setters, validation, and a toString method.
Employee.java (The Encapsulated Class)
Java
package com.ravi.encapsulation;public class Employee {
// 1. Private fields (Data Hiding)
private String name;
private double salary; // 2. Parameterized constructor (Initialization)
public Employee(String name, double salary) {
super();
this.name = name;
this.salary = salary;
}
// 3. Override toString() for easy printing
@Override
public String toString() {
return "Employee [name=" + name + ", salary=" + salary + "]";
} // 4. Getter for 'name'
public String getName() {
return name;
} // 5. Setter for 'name'
public void setName(String name) {
this.name = name;
} // 6. Getter for 'salary'
public double getSalary() {
return salary;
} // 7. Setter for 'salary' (WITH VALIDATION)
public void setSalary(double salary) {
// Validation: Salary cannot be less than the current salary
if (salary < this.salary) {
System.err.println("Invalid Data: Salary can only be increased.");
System.exit(0);
}
this.salary = salary;
}
}
EmployeeDemo.java (The Main Class)
Java
package com.ravi.encapsulation;import java.util.Scanner;public class EmployeeDemo {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in); // --- Create the object ---
System.out.print("Enter Employee Name: ");
String name = sc.nextLine();
System.out.print("Enter Employee Salary: ");
double salary = Double.parseDouble(sc.nextLine()); // Create object using the constructor
Employee emp = new Employee(name, salary);
System.out.println("Employee created: " + emp); // Calls toString() // --- Update the object using setter ---
System.out.print("Enter your increment amount: ");
double increment = Double.parseDouble(sc.nextLine()); // Use the getter and setter to safely update the object
// The setSalary() method will validate the new salary
emp.setSalary(emp.getSalary() + increment); System.out.println("Employee updated: " + emp); // Calls toString()
sc.close();
}
}
6. Summary & Key Conclusions
- Tightly Encapsulated Class: A class is “tightly encapsulated” if all of its instance variables are
private. - Ways to Initialize Object Properties (Summary):
- By using an object reference (e.g.,
emp.salary = 1000- Not recommended) - By using a method without parameters.
- By using a method with parameters (a setter).
- At the time of variable declaration (e.g.,
private int id = 101;). - Using a No-Argument Constructor.
- Using a Parameterized Constructor.
- Final Conclusion (Constructor vs. Setter vs. Getter):
- Parameterized Constructor: Used to initialize all object properties with user values at the time of creation.
- Setter (Write Operation): Used to modify an existing object’s properties (usually one at a time) after creation.
- Getter (Read Operation): Used to read an existing object’s private property value from outside the class.
toString(): Used to print all of an object's properties in a human-readable format.









