Introduction
Encapsulation is one of the four core principles of Object-Oriented Programming (OOP). It is also known as information hiding. Encapsulation refers to the packaging or bundling of data along with the methods that manipulate this data, thereby restricting direct external access to the data. These data are usually in form of variables with private access declared inside of a class, and a setters and getters method that can be used to update and retrieve the values of the variables.
An example of encapsulation can be seen from a medicine capsule. Here, the capsule protects its contents from direct external access. Before taking a capsule, we mostly don't open it to look at its content, but rather take the whole of it irrespective of the fact that we don't know what's inside and then expect it to start its functionalities. In this case, it is safe to say that the capsule has encapsulated its content from us. This is the same thing classes do; they protect their variables from external or clients access. In this case, the clients cannot manipulate this information because they don’t have direct access to them, and they cannot as well see the internal workings or implementations of objects created from that class.
Contents
- Background Knowledge
- Advantages of using Encapsulation
- The Account class
- The AccountTest class
- Conclusion
Expectations
By the end of this article, you will:
- Have a high-level knowledge of what encapsulation is.
- Know some of the advantages of using encapsulation.
- Write simple Java applications that apply the concept of encapsulation.
Background Knowledge
This article gives a high-level overview of one of the core principles of OOP. You are expected to have basic knowledge of OOP including:
- Objects
- Classes and methods
- Inheritance
Please check out Inheritance in Java for an article on inheritance.
Advantages of Using Encapsulation
- Data hiding: The use of private access modifiers in fields declaration protects that field in the class from an external source. Therefore, they can be used to store important information without the fear of information leakage.
- Control: The use of setters and getters methods to access private fields in a class gives more control over that variable. Suppose the
setBalance
method in an Account class processes only positive values and set negative values to zero, and a user wants to set an account balance to a negative value, because of the validation done in this method, zero will be stored in the balance instead of the negative value. - Reduces Exceptions: Suppose a user enters their age in a name field, the program is supposed to throw an exception because a
String
value is expected but it found anint
value. With encapsulation, this can be avoided by validating the input using a simple if-else statement of regular expression and handling the exception if one happens instead of terminating the program due to exceptions.
The Account Class
The account class depicts a bank account containing information related to the account. This class is used to demonstrate how encapsulation works and its benefits as well.
package Encapsulation;
public class Account {
private String firstName, lastName;
private double balance;
// set and get methods
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getFirstName() {
return firstName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getLastName() {
return lastName;
}
public void setBalance(int balance) {
// handles invalid balance
if (balance >= 0.0)
this.balance = balance;
else
this.balance = 0.0;
}
public double getBalance() {
return balance;
}
@Override
public String toString() {
return String.format("%s%n%s: %s%n%s: %s%n%s: %.2f%n",
"Account Info", "First Name", getFirstName(),
"Last Name", getLastName(), "Balance", getBalance());
}
}
The account class above declared all of its instance fields private thereby restricting access of these fields to the class alone.
private String firstName, lastName;
private double balance;
In this case, even objects of the class can’t access these private fields because they are encapsulated. They can only be accessed through the public get and set methods declared inside of the class. In a more robust system, the set methods usually have complex validations that external values must pass through before setting them but for the sake of this article and simplicity, we will be using an if-else statement to validate the balance entered by the user.
The setBalance
method first checks if the balance is a positive number (as there are no negative balance in most cases), similar to the deposit method. But the deposit method adds the deposit amount to the previous balance only if it is valid (deposit amount is mostly a positive value).
public void setBalance(int balance) {
// handles invalid balance
if (balance >= 0.0)
this.balance = balance;
else
this.balance = 0.0;
}
In a situation where the accountant mistakenly enters a negative amount for deposit, normally the program would have subtracted it from the previous balance left but because of encapsulation, this is not the case because an implementation that handles this kind of subtle error has been added to the program.
Another implementation in the Account class is the toString
method that displays the string representation of an object of that class.
@Override
public String toString() {
return String.format("%s%n%s: %s%n%s: %s%n%s: %,.2f%n",
"Account Info", "First Name", getFirstName(),
"Last Name", getLastName(), "Balance", getBalance());
}
This method overrides the default built-in toString
method inherited from the Object
class and adds implementation to it. The advantages of this will be seen later in this article.
The AccountTest Class
AccountTest class contains an object of the Account class and it is used to test the functionalities of the Account class.
package Encapsulation;
public class AccountTest {
public static void main(String[] args) {
Account clerk = new Account();
clerk.setFirstName("Clark");
clerk.setLastName("Tom");
clerk.setBalance(-200);
// Before depositing
System.out.println(clerk);
// After depositing invalid amount
clerk.deposit(-400);
System.out.printf("AFter depositing invalid amount %nBalance: %,.2f%n",
clerk.getBalance());
// After depositing valid amount
clerk.deposit(1500);
System.out.printf("AFter depositing valid amount %nBalance: %,.2f%n",
clerk.getBalance());
}
}
The main method of the AccountTest class starts by creating an object of the Account class and then using the set methods to initialize the values of the object.
The image below shows all of the properties of the Account class. As it is seen from the image below; the first name, last name, and account balance are not visible to the user because they are declared private. They can only be accessed through the get methods declared public.
After setting the name, the object tries to set a negative amount as the account balance
clerk.setBalance(-200);
but recall that the Account class automatically sets the negative amount received to 0.0 in the account balance. Encapsulation is seen at work here because we have successfully added some implementation to the setBalance
method which is not visible to the users.
Also, the clerk
object is displayed on the console using its object variable alone.
System.out.println(clerk);
Notice we didn’t call any method to help us properly display the object but it's variable alone, this is because the implementation for that is already handled as well in the overridden toString
method in the Account class. The user doesn’t have to go through the stress of trying to format the output because it has been handled already.
The next statement tries to deposit a negative amount to the user’s account and prints the new balance.
clerk.deposit(-400);
Same as the balance method, negative values are not allowed to be deposited and therefore the program skips adding this invalid deposit amount to the previous balance.
The next statement deposits a valid amount to the user’s account balance. In this case, the amount is added to the balance because it has been validated and passed the validation, and the new balance is then displayed.
clerk.deposit(1500);
The image below shows the output running the AccountTest class stored in AccountTest.java. It consists of the initial state of the account when the user tries to set an invalid balance, then when the user tries to deposit an invalid amount. And then to when the user enters the valid amount.
Conclusion
This article starts by introducing the concept of encapsulation using the medicine capsule as an example, another example that can be used here is the car instance. A car has at least a brake and accelerator, the driver uses these two to control the speed of the car but has no idea how the car does it. Their functionalities are hidden from the driver because most of the time the driver doesn't need to know how these things work before using the car. This is another good example of encapsulation.
We listed a few advantages of encapsulation, there are many other advantages out there but we chose only a few important ones for the sake of this article.
We then proceed to use the account class to explain the concept properly using some code examples.
Encapsulation is a broad concept in programming and the implementation slightly varies across different programming languages that support it. This article demonstrated a basic implementation of encapsulation using Java.
Top comments (0)