What is Encapsulation in Java and How to Implement It?

Java encapsulation is a powerful mechanism for storing a class's data members and methods in a secure field accessible only to the same class members.

Java encapsulation integrates data (variables) and the code that acts upon them (methods) as a single unit. By encapsulating a class's variables, other classes cannot access them, and only their methods can.

Get access and complete hands-on experience on a plethora of software development skills in our unique Masters program. Get job-ready with by enrolling in our comprehensive Full Stack Java Developer Masters program today!

What is Encapsulation?

Encapsulation is a fundamental concept in object-oriented programming (OOP) that involves bundling data (variables) and methods (functions) that operate on the data into a single unit or class. It restricts direct access to some of the object’s components, which helps protect the integrity of the data by controlling how it’s accessed or modified. By using access specifiers like private, public, or protected, encapsulation ensures that the internal state of an object can only be changed in controlled ways.

Become a Full Stack Developer in Just 6 Months!

Full Stack Java DeveloperExplore Program
Become a Full Stack Developer in Just 6 Months!

What is Encapsulation in Java?

Encapsulation in Java refers to integrating data (variables) and code (methods) into a single unit. In encapsulation, a class's variables are hidden from other classes and can only be accessed by the methods of the class in which they are found.

java

Java encapsulation is an object-oriented procedure for combining the class's data members and data methods inside the user-defined class. It is important to declare this class private.

Java encapsulation refers to the bundling of data and methods that operate on the data within a single unit, typically a class. This concept helps hide an object's internal state and only exposes necessary functionalities through methods. By encapsulating data, Java ensures better data security and code maintainability. Understanding encapsulation is fundamental for building robust and organized Java applications, making a Java Course essential for mastering this concept.

Next, we will understand the Syntax to be followed while implementing Java encapsulation.

Syntax:

<Access_Modifier> class <Class_Name> {

 private <Data_Members>;

 private <Data_Methods>;

}

Let us go through the following sample program to enhance the understanding of the encapsulation process.

Example:

package dc;

public class c 

{  

public static void main (String[] args) 

Employee e = new Employee(); 

e.setName("Robert"); 

e.setAge(33); 

e.setEmpID(1253); 

System.out.println("Employee's name: " + e.getName()); 

System.out.println("Employee's age: " + e.getAge()); 

System.out.println("Employee's ID: " + e.getEmpID()); 

package dc;

public class Employee {

private String Name;

private int EmpID;

private int Age;

public int getAge() {

return Age;

}

public String getName() {

return Name;

}

public int getEmpID() {

return EmpID;

}

public void setAge(int newAge) {

Age = newAge;

}

public void setName(String newName) {

Name = newName;

}

public void setRoll(int newEmpID) {

EmpID = newEmpID;

}

public void setEmpID(int EmpID) {

}

}

//

Output:

Employee's name: Robert

Employee's age: 33

Employee's ID: 1253

Master Core Java 8 Concepts, Java Servlet & More!

Java Certification TrainingENROLL NOW
Master Core Java 8 Concepts, Java Servlet & More!

Implementing Java Encapsulation

Here's an example of implementing Java encapsulation by using private fields and providing public getter and setter methods to control access to those fields:

// Class with private fields
class Employee {
    // Private fields (data is hidden from outside access)
    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 (with validation)
    public void setAge(int age) {
        if (age > 0) {  // Ensuring a valid age
            this.age = age;
        } else {
            System.out.println("Please enter a valid age.");
        }
    }

    // Public getter for salary
    public double getSalary() {
        return salary;
    }

    // Public setter for salary
    public void setSalary(double salary) {
        if (salary > 0) {  // Ensuring a valid salary
            this.salary = salary;
        } else {
            System.out.println("Salary must be positive.");
        }
    }
}

// Main class to demonstrate Java encapsulation
public class Main {
    public static void main(String[] args) {
        // Creating an instance of Employee
        Employee emp = new Employee();

        // Using setters to assign values
        emp.setName("John Doe");
        emp.setAge(30);
        emp.setSalary(50000);

        // Using getters to retrieve values
        System.out.println("Employee Name: " + emp.getName());
        System.out.println("Employee Age: " + emp.getAge());
        System.out.println("Employee Salary: " + emp.getSalary());
    }
}

Key Points

  • Private fields (name, age, salary) do not allow direct access.
  • Public methods (getName(), setName(), etc.) allow controlled access.
  • Additional validations can be added inside the setter methods to enforce business rules (e.g., checking if age or salary is valid).

Advantages of Encapsulation

  1. Data Protection: Encapsulation restricts direct access to the object’s data, ensuring that it can only be modified through controlled methods, protecting the integrity of the data.
  2. Improved Security: By hiding the internal implementation, encapsulation enhances security, preventing unauthorized access to sensitive data.
  3. Simplified Maintenance: Encapsulated code is easier to maintain since changes in internal implementation do not affect other parts of the program.
  4. Increased Flexibility: You can modify internal components without changing the external API, allowing flexibility in improving or updating internal logic.
  5. Code Reusability: Encapsulation promotes the use of modular code, allowing for the reuse of code in different parts of a program or future projects.
  6. Better Control Over Data: By using getter and setter methods, you can apply validation and constraints on data, ensuring correctness.
  7. Reduced Complexity: It hides complex implementation details, making it easier for developers to work with objects without knowing the internal workings.
  8. Prevents Unintended Interactions: Encapsulation prevents accidental or improper changes to an object’s state by ensuring changes are controlled and intentional.
  9. Enhances Readability: Encapsulated code is generally more readable and understandable because it provides a clean interface for data interaction.
Become job-ready by opting for the decade's hottest career option. Score your dream job in no time by enrolling in our Full Stack Java Developer Program Today!

Disadvantages of Encapsulation

  1. Increased Code Size: Encapsulation may require additional methods (getters/setters), which can increase the amount of code and potentially make it more verbose.
  2. Slower Performance: Indirect access to data through methods can introduce slight performance overhead compared to direct access.
  3. More Complex Code Structure: Encapsulation can sometimes make the code structure more complex, especially in scenarios where simple direct access would suffice.
  4. Overhead of Maintenance: Managing encapsulated methods (especially with complex validation) requires careful maintenance, which can be more time-consuming.
  5. Restricted Flexibility for Users: The class user might need more flexibility in accessing data, as only predefined methods are provided, even when direct access could be simpler or more efficient in some cases.

Data Encapsulation in Java Examples

Here are examples of data encapsulation in Java, demonstrating how to hide data and control access through getter and setter methods.

Example 1: Basic Data Encapsulation

In this example, we encapsulate the Student class data (fields like name and age) by making them private and providing public getter and setter methods for controlled access.

// Encapsulated Student class
class Student {
    // Private fields (data encapsulation)
    private String name;
    private int age;

    // Getter for name
    public String getName() {
        return name;
    }

    // Setter for name
    public void setName(String name) {
        this.name = name;
    }

    // Getter for age
    public int getAge() {
        return age;
    }

    // Setter for age with validation
    public void setAge(int age) {
        if (age > 0) {
            this.age = age;
        } else {
            System.out.println("Invalid age");
        }
    }
}

public class Main {
    public static void main(String[] args) {
        // Create Student object
        Student student = new Student();

        // Set data using setters
        student.setName("Alice");
        student.setAge(21);

        // Get data using getters
        System.out.println("Student Name: " + student.getName());
        System.out.println("Student Age: " + student.getAge());
    }
}

Output

Student Name: Alice

Student Age: 21

Example 2: Data Encapsulation with Validation

Here, the BankAccount class encapsulates the balance field and provides more detailed validation to prevent the setting of invalid values.

// Encapsulated BankAccount class
class BankAccount {
    // Private field to store balance
    private double balance;

    // Getter for balance
    public double getBalance() {
        return balance;
    }

    // Setter for balance with validation (cannot be negative)
    public void setBalance(double balance) {
        if (balance >= 0) {
            this.balance = balance;
        } else {
            System.out.println("Invalid balance. Balance cannot be negative.");
        }
    }

    // Method to deposit money
    public void deposit(double amount) {
        if (amount > 0) {
            balance += amount;
        } else {
            System.out.println("Deposit amount must be positive.");
        }
    }

    // Method to withdraw money
    public void withdraw(double amount) {
        if (amount > 0 && amount <= balance) {
            balance -= amount;
        } else {
            System.out.println("Invalid withdraw amount or insufficient balance.");
        }
    }
}

public class Main {
    public static void main(String[] args) {
        // Create BankAccount object
        BankAccount account = new BankAccount();

        // Set initial balance
        account.setBalance(1000.00);

        // Perform deposit and withdraw operations
        account.deposit(500.00);
        account.withdraw(300.00);

        // Get the final balance
        System.out.println("Final Balance: " + account.getBalance());
    }
}

Output

Final Balance: 1200.0

Get Mentored by Leading Java Experts!

Full Stack Java DeveloperExplore Program
Get Mentored by Leading Java Experts!

Example 3: Encapsulation with Multiple Fields

In this example, the Employee class encapsulates multiple fields (name, salary, and department) and ensures that these fields can be accessed or modified only through getter and setter methods.

// Encapsulated Employee class
class Employee {
    // Private fields
    private String name;
    private double salary;
    private String department;

    // Getter for name
    public String getName() {
        return name;
    }

    // Setter for name
    public void setName(String name) {
        this.name = name;
    }

    // Getter for salary
    public double getSalary() {
        return salary;
    }

    // Setter for salary with validation
    public void setSalary(double salary) {
        if (salary > 0) {
            this.salary = salary;
        } else {
            System.out.println("Invalid salary.");
        }
    }

    // Getter for department
    public String getDepartment() {
        return department;
    }

    // Setter for department
    public void setDepartment(String department) {
        this.department = department;
    }
}

public class Main {
    public static void main(String[] args) {
        // Create Employee object
        Employee employee = new Employee();

        // Set employee details using setters
        employee.setName("John Smith");
        employee.setSalary(70000);
        employee.setDepartment("Engineering");

        // Get and display employee details using getters
        System.out.println("Employee Name: " + employee.getName());
        System.out.println("Employee Salary: " + employee.getSalary());
        System.out.println("Employee Department: " + employee.getDepartment());
    }
}

Output

Employee Name: John Smith

Employee Salary: 70000.0

Employee Department: Engineering

Data Hiding in Java

Data hiding is a procedure for avoiding access to the data members, data methods, and their logical implementation. It can be done by using the access specifiers. We have four access specifiers, which are as follows.

Default

Default is the first line of data hiding. If any class in Java is not mentioned with an access specifier, then the compiler will set ‘default’ as the access specifier. The default access specifications are highly similar to those of the public access specifier.

Public

The public access specifier provides access specifications to a class so that it can be accessed from anywhere within the program.

Example:

package Simplilearn;

class vehicle {

public int tires;

public void display() {

System.out.println("I have a vehicle.");

System.out.println("It has " + tires + " tires.");

}

}

public class Display {

public static void main(String[] args) {

vehicle veh = new vehicle();

veh.tires = 4;

veh.display();

}

}

Output

I have a vehicle.

It has four tires.

Private

The private access specifier provides access to the data members, and the data methods are limited to the class.

Example:

package Simplilearn;

class Student {

private int rank;

public int getRank() {

return rank;

}

public void setRank(int rank) {

this.rank = rank;

}

}

public class school {

public static void main(String[] args) {

Student s = new Student();

s.setRank(1022);

System.out.println("Student rank is " + s.getRank());

}

}

Output

Student rank is 1022

Protected

The protected access specifier protects class methods and members, similar to the private access specifier. The main difference is that access is limited to the entire package, unlike only a class with the private access specifier.

Example:

package Simplilearn;

class human {

protected String stream;

protected void display() {

System.out.println("Hello, I am a " + stream + " Student");

}

}

public class Student extends human {

public static void main(String[] args) {

Student s = new Student();

s.stream = "Computer Science and Engineering Technology";

s.display();

}

}

Output

Hello, I am a Computer Science and Engineering Technology Student

Data Hiding vs. Encapsulation in Java

Data Hiding

Data Encapsulation

Data hiding can be considered as the parent process

Encapsulation is a sub-process of data hiding

Access specifier is always private

Access specifiers can be private and public

Data hiding is about hiding method implementation

Encapsulation is about combining methods with data members

The main motto is to hide data and its implementation

The main motto is to combine data and methods 

Dive Deep Into Java Core Concepts

Java Certification TrainingENROLL NOW
Dive Deep Into Java Core Concepts

Getter and Setter Methods

Getter and setter techniques are commonly referred to in object-oriented programming languages. An attribute can be retrieved using a getter method, and it can also be changed using a setter method, as indicated by the names. Your implementation methods will determine if an attribute may be read and updated. Additionally, you may choose whether or not the attribute is read-only or wholly hidden from view.

Example 1

Following is an example that demonstrates how to achieve encapsulation in Java -

/* File name : EncapTest.java */

public class EncapTest {

   private String name;

   private String idNum;

   private int age;

   public int getAge() {

      return age;

   }

   public String getName() {

      return name;

   }

   public String getIdNum() {

      return idNum;

   }

   public void setAge( int newAge) {

      age = newAge;

   }

   public void setName(String newName) {

      name = newName;

   }

   public void setIdNum( String newId) {

      idNum = newId;

   }

}

The public setXXX() and getXXX() methods provide access to the EncapTest class's instance variables.

The terms "getters" and "setters" are often used to describe these techniques. As a result, every class that needs to access the variables should use these getters and setters.

The variables of the encap test class can be accessed using the following program – 

/* File name : RunEncap.java */

public class RunEncap {

   public static void main(String args[]) {

      EncapTest encap = new EncapTest();

      encap.setName("James");

      encap.setAge(20);

      encap.setIdNum("12343ms");

      System.out.print("Name : " + encap.getName() + " Age : " + encap.getAge());

   }

}

It will result in the following outcome:

Output:

Name: James Age: 20

The CoffeeMachine Example

Encapsulation, or "Information Hiding," refers to concealing the details of an object's internal processes. It's nothing more than a simple data masking technique.

The encapsulation method was implemented when the CoffeeMachine class was developed. The current state of the CoffeeMachine object is recorded in the attributes configMap, beans, grinder, and brewingUnit. 

The methods brewCoffee, brewEspresso, brewFilterCoffee, and addBeans are available to perform various operations on these properties.

Code:

import java.util.HashMap;

import java.util.Map;

public class CoffeeMachine {

    private Map configMap;

    private Map beans;

    private Grinder grinder;

    private BrewingUnit brewingUnit;

    public CoffeeMachine(Map beans) {

        this.beans = beans;

        this.grinder = new Grinder();

        this.brewingUnit = new BrewingUnit();

        this.configMap = new HashMap();

        this.configMap.put(CoffeeSelection.ESPRESSO, new Configuration(8, 28));

        this.configMap.put(CoffeeSelection.FILTER_COFFEE, new Configuration(30, 480));

    }

    public Coffee brewCoffee(CoffeeSelection selection) throws CoffeeException {

        switch (selection) {

            case FILTER_COFFEE:

                return brewFilterCoffee();

            case ESPRESSO:

                return brewEspresso();

            default:

                throw new CoffeeException("CoffeeSelection [" + selection + "] not supported!");

        }

    }

    private Coffee brewEspresso() {

        Configuration config = configMap.get(CoffeeSelection.ESPRESSO);

        // grind the coffee beans

        GroundCoffee groundCoffee = this.grinder.grind(

            this.beans.get(CoffeeSelection.ESPRESSO), config.getQuantityCoffee());

        // brew an espresso

        return this.brewingUnit.brew(CoffeeSelection.ESPRESSO, 

            groundCoffee, config.getQuantityWater());

    }

    private Coffee brewFilterCoffee() {

        Configuration config = configMap.get(CoffeeSelection.FILTER_COFFEE);

        // grind the coffee beans

        GroundCoffee groundCoffee = this.grinder.grind(

            this.beans.get(CoffeeSelection.FILTER_COFFEE), config.getQuantityCoffee());

        // brew a filter coffee

        return this.brewingUnit.brew(CoffeeSelection.FILTER_COFFEE, 

            groundCoffee, config.getQuantityWater());

    }

    public void addBeans(CoffeeSelection sel, CoffeeBean newBeans) throws CoffeeException {

        CoffeeBean existingBeans = this.beans.get(sel);

        if (existingBeans != null) {

            if (existingBeans.getName().equals(newBeans.getName())) {

                existingBeans.setQuantity(existingBeans.getQuantity() + newBeans.getQuantity());

            } else {

                throw new CoffeeException("Only one kind of beans supported for each CoffeeSelection.");

            }

        } else {

            this.beans.put(sel, newBeans);

        }

    }

}

The Coffee class exemplifies the process of hiding information and represents a beverage produced by a Coffee Machine. The Coffee Vending Machine encapsulates internal processes and ingredients (data).

In Object-oriented languages, encapsulation is provided via modifiers such as "private" and "protected." Transient and volatile can encapsulate modifiers, but only in specific contexts.

Java encapsulation can be used in other languages in addition to OOP languages. Webservices, SOA (Service Oriented Architecture), and other cutting-edge technologies are part of the notion. If you look closely, you can see encapsulation in real-world objects; this is what Object-Oriented Programming seeks to mimic.

Master Java programming and elevate your career with the Java Certification Course by Simplilearn. Gain in-demand skills and become job-ready. Enroll now and transform your future!

Benefits of Encapsulation in Java

Implementing Java encapsulation has proven to be highly effective and beneficial for programming in real-time. The following are the significant benefits of encapsulation.

  • A class can have complete control over its data members and data methods.
  • The class will maintain its data members and methods as read-only.
  • Data hiding prevents the user from the complex implementations in the code.
  • The class variables can be read-only or write-only as per the programmer's requirement.
  • Java encapsulation provides an option for code-reusability.
  • Using encapsulation will help in making changes to an existing code quickly.
  • Unit testing a code designed using encapsulation is elementary.
  • Standard IDEs support getters and setters, which makes coding even faster. 

Conclusion

As an object-oriented programming principle, Java encapsulation describes the grouping of data and methods that interact with this data into a single unit.

It's frequently employed as a means of concealing sensitive data. This approach restricts external access to specific attributes while still allowing them to be accessed by current class members via public getter and setter methods. You can specify which attributes can be read or updated using these methods and validate a new value before changing an attribute using them.

Encapsulation provides the fundamental property of hiding data to protect user data. OOP best practices like encapsulation are beneficial when paired with an APM solution like Retrace for error detection.

Are you interested in learning more about the Java Programming Language and getting certified as a professional Java Developer? Then, check out our Java training and certification program curated by the most experienced real-time industry experts.

FAQs

1. What is the difference between encapsulation and abstraction?

Encapsulation hides an object's internal state and implementation details, exposing only what’s necessary through methods. Conversely, Abstraction simplifies complex systems by focusing on essential features while hiding unnecessary details. Encapsulation protects data, while abstraction simplifies complexity.

2. What are the types of encapsulation?

There are generally two types of encapsulation:

  • Data Encapsulation: Hiding the data (attributes) of a class.
  • Function Encapsulation: Hiding a class's functionality (methods) behind an interface to control how data is accessed or modified.

3. What is an example of abstraction and encapsulation in real life?

  • Abstraction: You interact with the car through the steering wheel and pedals without knowing the internal engine mechanics.
  • Encapsulation: The engine’s internal components are hidden and protected, ensuring you cannot modify them directly, only through specific controls like the gas pedal.

4. What are the types of encapsulation?

The two key types of encapsulation are:

  • Private Encapsulation: Data is completely hidden from outside access, and only internal methods can modify it.
  • Protected Encapsulation: Data is accessible within the class and its subclasses but not to the rest of the program.

5. Why use encapsulation?

Encapsulation enhances data security, maintains data integrity, and allows better modularity. It ensures controlled access to an object’s data through getter and setter methods, helping prevent unauthorized or unintended modifications while simplifying maintenance by separating a class's internal workings from its external interface.

About the Author

Haroon Ahamed KitthuHaroon Ahamed Kitthu

Haroon is the Senior Associate Director of Products at Simplilearn. bringing 10 years of expertise in product management and software development. He excels in building customer-focused, scalable products for startups and enterprises. His specialties include CRM, UI/UX and product strategy.

View More
  • Disclaimer
  • PMP, PMI, PMBOK, CAPM, PgMP, PfMP, ACP, PBA, RMP, SP, OPM3 and the PMI ATP seal are the registered marks of the Project Management Institute, Inc.