Encapsulation
Encapsulation is one of the fundamental principles of Object-Oriented Programming (OOP) in Java. It is the process of bundling data (fields) and methods (functions) that operate on the data into a single unit, typically a class. Encapsulation also involves restricting direct access to some of an object's components, which is achieved by using access modifiers like private, protected, and public. This ensures that the internal state of an object is hidden from the outside world and can only be accessed or modified through controlled mechanisms, such as getter and setter methods.
Encapsulation promotes data security, modularity, and maintainability, making it a key concept in writing robust and scalable Java applications.
Key Features of Encapsulation
- Data Hiding: By declaring class variables as
private, you prevent direct access to them from outside the class. This ensures that sensitive data is protected. - Controlled Access: Access to private fields is provided through public getter and setter methods, allowing controlled modification and retrieval of data.
- Improved Maintainability: Encapsulation makes it easier to modify or update the internal implementation of a class without affecting external code that uses the class.
- Modularity: Encapsulation helps in dividing the code into smaller, manageable units, making the application easier to understand and maintain.
Example of Encapsulation in Java
Below is an example that demonstrates encapsulation by using private fields and public getter and setter methods.
class Employee {
// Private fields (data hiding)
private String name;
private int age;
private double salary;
// Public getter for 'name'
public String getName() {
return name;
}
// Public setter for 'name'
public void setName(String name) {
this.name = name;
}
// Public getter for 'age'
public int getAge() {
return age;
}
// Public setter for 'age'
public void setAge(int age) {
if (age > 0) { // Validation to ensure valid data
this.age = age;
} else {
System.out.println("Age must be positive.");
}
}
// Public getter for 'salary'
public double getSalary() {
return salary;
}
// Public setter for 'salary'
public void setSalary(double salary) {
if (salary > 0) { // Validation to ensure valid data
this.salary = salary;
} else {
System.out.println("Salary must be positive.");
}
}
}
public class Main {
public static void main(String[] args) {
Employee emp = new Employee();
// Setting values using setter methods
emp.setName("John Doe");
emp.setAge(30);
emp.setSalary(50000);
// Accessing values using getter methods
System.out.println("Name: " + emp.getName()); // John Doe
System.out.println("Age: " + emp.getAge()); // 30
System.out.println("Salary: $" + emp.getSalary()); // $50000.0
}
}
Explanation
- The fields
name,age, andsalaryare declared asprivate, ensuring they cannot be accessed directly from outside theEmployeeclass. - Public getter and setter methods provide controlled access to these fields, allowing validation and logic to be applied when setting or retrieving values.
Benefits of Encapsulation
- Data Security: By hiding sensitive data, encapsulation prevents unauthorized access and ensures that only valid data is stored in the fields.
- Flexibility: You can change the internal implementation of a class (e.g., modify how data is stored or processed) without affecting external code that uses the class.
- Code Reusability: Encapsulation promotes modularity, making it easier to reuse and maintain code.
- Improved Debugging: Encapsulation makes it easier to identify and fix issues since the data and methods are tightly coupled within a single class.
Real-World Example of Encapsulation
Consider a banking application where a BankAccount class is used to manage customer accounts. Encapsulation ensures that sensitive data, such as the account balance, is protected and can only be accessed or modified through controlled methods.
class BankAccount {
private double balance;
public double getBalance() {
return balance;
}
public void deposit(double amount) {
if (amount > 0) {
balance += amount;
System.out.println("Deposited: $" + amount);
} else {
System.out.println("Invalid deposit amount.");
}
}
public void withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
System.out.println("Withdrawn: $" + amount);
} else {
System.out.println("Invalid withdrawal amount or insufficient balance.");
}
}
}
public class Main {
public static void main(String[] args) {
BankAccount account = new BankAccount();
account.deposit(1000);
account.withdraw(500);
System.out.println("Current Balance: $" + account.getBalance());
}
}
Output:
Deposited: $1000.0
Withdrawn: $500.0
Current Balance: $500.0
In this example, the balance field is private, and all operations on it (deposit and withdrawal) are performed through public methods, ensuring data security and controlled access.
