Lesson 3
Encapsulation in Java Classes
Encapsulation in Java Classes

Hello! In this lesson, we're revisiting Encapsulation, Private Attributes, and Private Methods in Object-Oriented Programming (OOP). Think of encapsulation as an invisible fence that safeguards your garden (the class) from outside interference, keeping data and methods secure inside. Within this garden, certain elements (Private Attributes and Methods) are only accessible to the gardener, providing an extra layer of protection and ensuring data integrity in your classes!

Encapsulation Explained

Encapsulation is a fundamental concept in Object-Oriented Programming (OOP) that involves bundling data (attributes) and methods (functions) that operate on the data into a single unit, called a class. This concept also limits direct access to some of an object's components, preventing accidental interference and misuse of the data. For instance, in a multiplayer game, you might create a Player class that encapsulates data (health, armor, stamina) and methods (receiveDamage, shieldHit, restoreHealth).

Java
1class Player { 2 private int health; 3 private int armor; 4 private int stamina; 5 6 public Player(int health, int armor, int stamina) { 7 this.health = health; 8 this.armor = armor; 9 this.stamina = stamina; 10 } 11 12 public void receiveDamage(int damage) { 13 health -= damage; // Reduce health 14 } 15 16 public void shieldHit(int armorDamage) { 17 armor -= armorDamage; // Decrease armor 18 } 19 20 public void restoreHealth(int healthIncrease) { 21 health += healthIncrease; // Restore health 22 } 23 24 public void displayStatus() { 25 System.out.println("Health: " + health + ", Armor: " + armor + ", Stamina: " + stamina); 26 } 27} 28 29public class Solution { 30 public static void main(String[] args) { 31 Player player = new Player(100, 50, 77); 32 player.displayStatus(); // Outputs: Health: 100, Armor: 50, Stamina: 77 33 } 34}

In Java, player is an instance of the Player class on which you can call methods.

Private Attributes

In Java, the private keyword is used to designate attributes and methods as accessible only within their own class. This ensures the integrity of an object by restricting direct external access and interference.

Private Attributes, such as balance in a BankAccount class, ensure the integrity and security of data by restricting modifications to the methods within the class and disallowing direct external access.

Java
1class BankAccount { 2 private double balance; // Declare a private field 3 4 // Constructor to initialize the balance 5 public BankAccount(double balance) { 6 this.balance = balance; // Initialize the private attribute 7 } 8 9 // Method to deposit money into the account 10 public void deposit(double amount) { 11 balance += amount; // Deposit money 12 } 13 14 // Getter for balance 15 public double getBalance() { 16 return balance; // A public method to access balance 17 } 18 19 // Optional setter for balance with validation 20 public void setBalance(double balance) { 21 if (balance >= 0) { 22 this.balance = balance; 23 } else { 24 System.out.println("Balance cannot be negative."); 25 } 26 } 27} 28 29public class Solution { 30 public static void main(String[] args) { 31 BankAccount bankAccount = new BankAccount(100); // Initialize account with balance of 100 32 bankAccount.setBalance(200); // Works: sets balance to 200 33 System.out.println(bankAccount.getBalance()); // Works: logs 200 34 bankAccount.setBalance(-50); // Logs: "Balance cannot be negative." 35 } 36}
Private Methods

Like private attributes, private methods are accessible only within their class. They are useful for hiding complex implementation details or helper functions from outside access. Here's an example:

Java
1class BankAccount { 2 private double balance; // Declare a private field 3 4 public BankAccount(double balance) { 5 this.balance = balance; // Initialize the private attribute 6 } 7 8 // Private method to calculate interest 9 private void addInterest(double interestRate) { 10 balance += balance * interestRate; // Calculation of interest 11 } 12 13 // Public method calling the private method 14 public void addYearlyInterest() { 15 addInterest(0.02); // Adds 2% interest 16 } 17 18 // Getter for balance 19 public double getBalance() { 20 return balance; 21 } 22} 23 24public class Solution { 25 public static void main(String[] args) { 26 BankAccount bankAccount = new BankAccount(100); // Initialize account with balance of 100 27 bankAccount.addYearlyInterest(); // Works, calling a public method 28 System.out.println(bankAccount.getBalance()); // Logs the updated balance 29 // bankAccount.addInterest(0.1); // Error: can't call a private method from outside 30 } 31}

Here, addYearlyInterest() is a public method that calls the private method addInterest().

Getters

In Java, getters provide a method to access private attributes indirectly while maintaining control over how values are retrieved, adhering to the encapsulation principle. Here's how you can define a getter method for a private attribute:

Java
1class BankAccount { 2 private double balance; // Declare a private field 3 4 // Constructor to initialize the balance 5 public BankAccount(double balance) { 6 this.balance = balance; // Initialize the private attribute 7 } 8 9 // Getter for balance 10 public double getBalance() { 11 return balance; 12 } 13 14 // Method to deposit money into the account 15 public void deposit(double amount) { 16 balance += amount; // Deposit money 17 } 18} 19 20public class Solution { 21 public static void main(String[] args) { 22 BankAccount bankAccount = new BankAccount(100); // Initialize account with balance of 100 23 System.out.println(bankAccount.getBalance()); // Works: logs 100 24 } 25}

In this example, the getBalance method provides a controlled way to access the private balance attribute.

Setters

Java setters allow the modification of the value of a private attribute through a controlled interface. Here’s how you can define a setter method for a private attribute:

Java
1class BankAccount { 2 private double balance; // Declare a private field 3 4 // Constructor to initialize the balance 5 public BankAccount(double balance) { 6 this.balance = balance; // Initialize the private attribute 7 } 8 9 // Setter for balance with validation 10 public void setBalance(double balance) { 11 if (balance >= 0) { 12 this.balance = balance; 13 } else { 14 System.out.println("Balance cannot be negative."); 15 } 16 } 17 18 // Getter for balance 19 public double getBalance() { 20 return balance; 21 } 22 23 // Method to deposit money into the account 24 public void deposit(double amount) { 25 this.balance += amount; // Deposit money 26 } 27} 28 29public class Solution { 30 public static void main(String[] args) { 31 BankAccount bankAccount = new BankAccount(100); // Initialize account with balance of 100 32 bankAccount.setBalance(200); // Works: sets balance to 200 33 System.out.println(bankAccount.getBalance()); // Works: logs 200 34 bankAccount.setBalance(-50); // Logs: "Balance cannot be negative." 35 } 36}

In this example, the setBalance method ensures that the balance is only set to non-negative values, adding a layer of validation.

By using getters and setters, you can incorporate logic for validating or processing data, making your class more flexible and secure while adhering to encapsulation principles.

Lesson Summary

Great job refreshing your understanding of encapsulation, private attributes, and private methods concepts in Java! Correctly understanding and applying these foundational principles of OOP make your code concise, robust, and secure.

Coming up next is hands-on practice. Keep up the good work — exciting exercises in Java are just around the corner!

Enjoy this lesson? Now it's time to practice with Cosmo!
Practice is how you turn knowledge into actual skills.