Popular Searches
Popular Course Categories
Popular Courses

Understanding Encapsulation and Data Hiding

Understanding Encapsulation and Data Hiding

Encapsulation, Inheritance, and Polymorphism

Understanding Encapsulation and Data Hiding in Java

Course: Core Java Training

Topic: Understanding Encapsulation and Data Hiding

Course Link: Core Java Training Course

Demo Link: Register for a Free Course Demo

Official Website: JustAcademy


1. Introduction to Encapsulation in Java

Encapsulation is one of the four fundamental principles of Object-Oriented Programming (OOP), along with inheritance, polymorphism, and abstraction. It refers to combining data and the methods that operate on that data within a single unit, usually a class, while controlling how other parts of a program access the internal state of an object.

In Java, encapsulation is commonly implemented by declaring fields as private and providing carefully designed public methods for reading or modifying those fields when necessary. This approach helps protect data from accidental changes and allows a class to enforce rules about its own state.

For example, a bank account should not allow another class to directly assign a negative balance. By hiding the balance field and exposing methods such as deposit() and withdraw(), the account class can validate transactions before changing its data.

Key Characteristics of Encapsulation

  • Data protection: Restricts direct access to internal fields.
  • Controlled access: Allows access through selected methods.
  • Validation: Checks input before accepting changes.
  • Maintainability: Keeps internal implementation details separate from public usage.
  • Modularity: Groups related data and behavior inside a class.

2. What Is Data Hiding?

Data hiding is the practice of preventing other classes from directly accessing an object's internal data. In Java, the private access modifier is commonly used to hide fields from code outside the class in which they are declared.

When a field is private, an unrelated class cannot access it directly using an object reference. Instead, the class that owns the field decides which operations should be available to other parts of the program.

Consider a student record. Its marks should not be changed arbitrarily by other classes. A private field and a validation method can ensure that marks remain within an acceptable range, such as 0 to 100.

Example of Data Hiding

class Student {
    private int marks;

    public void setMarks(int marks) {
        if (marks >= 0 && marks <= 100) {
            this.marks = marks;
        } else {
            System.out.println("Invalid marks.");
        }
    }

    public int getMarks() {
        return marks;
    }
}

In this example, the marks field is hidden from direct external access. The setMarks() method validates the supplied value, while getMarks() provides controlled read access.

3. Difference Between Encapsulation and Data Hiding

Encapsulation and data hiding are closely related, but they are not exactly the same concept. Encapsulation focuses on grouping data and behavior and defining a controlled interface. Data hiding focuses on restricting access to internal implementation details.

Basis Encapsulation Data Hiding
Meaning Combines data and related methods in a class and controls access. Restricts direct access to internal data or implementation details.
Main purpose Organizes functionality and manages object state. Prevents uncontrolled access to internal information.
Java implementation Classes, access modifiers, and suitable methods. Often achieved using the private modifier and restricted interfaces.
Example A bank account class containing a balance and transaction methods. Declaring the account balance field as private.
Relationship Provides the broader design approach. Is an important technique used to support encapsulation.

4. Why Is Encapsulation Important?

Without encapsulation, different parts of an application may change an object's fields without following its business rules. This can produce invalid data, unexpected behavior, and difficult-to-diagnose errors.

4.1 Protecting Data Integrity

Encapsulation helps keep an object in a valid state. For instance, a product's price should not be negative, and a student's marks should not exceed the permitted range. Validation methods can reject inappropriate values before they are stored.

4.2 Controlling Access

A class can expose only the operations that callers need. A password-related field, for example, should not necessarily have a public getter that returns its raw value. Some internal fields may need no public access method at all.

4.3 Improving Maintainability

The internal representation of a class can change while its public methods remain stable. A class might change how it calculates a value without requiring every calling class to be rewritten.

4.4 Supporting Reusability

A well-encapsulated class can be reused in different applications because its behavior is accessed through a clear interface rather than through direct manipulation of its internal fields.

4.5 Simplifying Testing and Debugging

When state changes are handled through defined methods, developers can inspect those methods to understand how values are validated and updated. This makes it easier to test expected behavior and diagnose invalid state changes.

5. Access Modifiers Used in Encapsulation

Java provides access modifiers that control the visibility of classes, fields, constructors, and methods. Selecting the appropriate modifier is an important part of designing an encapsulated class.

Modifier Access Level Common Use
private Accessible within the declaring top-level class, including its own nested code. Hiding implementation fields and internal helper methods.
No modifier (package-private) Accessible to classes within the same package. Allowing package-level collaboration without making a member public.
protected Accessible within the same package and, subject to Java's access rules, in subclasses outside the package. Supporting selected inheritance-based access.
public Generally accessible wherever the declaring type and member are accessible. Exposing methods intended for callers.

A useful guideline is to choose the most restrictive access level that meets the design requirements. Fields are commonly declared private, while only necessary operations are exposed through public methods.

6. How to Achieve Encapsulation in Java

Encapsulation is usually implemented through a few straightforward design steps.

  1. Declare fields as private: Prevent unrelated classes from reading or modifying fields directly.
  2. Provide suitable access methods: Add getters or other read operations only when callers need them.
  3. Control modifications: Use setters or meaningful methods that perform validation before changing state.
  4. Maintain class rules: Ensure that every operation preserves the object's required conditions.
  5. Avoid unnecessary exposure: Do not automatically create public getters and setters for every field.

General Syntax

class Example {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        if (name != null && !name.isBlank()) {
            this.name = name;
        }
    }
}

Here, name is private. External code can read it through getName() and request an update through setName(). The setter rejects null and blank input.

7. Understanding Getter Methods

A getter, also called an accessor method, is a method used to retrieve a field's value or provide a controlled representation of that value. A conventional getter for a field named name is often called getName().

Example

class Employee {
    private String name = "Aarav";

    public String getName() {
        return name;
    }
}

public class GetterDemo {
    public static void main(String[] args) {
        Employee employee = new Employee();
        System.out.println(employee.getName());
    }
}

Output:

Aarav

The field is private, so the calling class reads its value through the public getter instead of accessing the field directly. A getter is not required for every private field; exposing a value should be a deliberate design decision.

8. Understanding Setter Methods

A setter, also called a mutator method, is used to change a field's value through a defined operation. A conventional setter for a field named age is often called setAge().

A well-designed setter can check whether the new value is valid before storing it. If a value violates the class's rules, the method can reject it, return a status, or throw an appropriate exception.

Example with Validation

class Person {
    private int age;

    public void setAge(int age) {
        if (age >= 0 && age <= 120) {
            this.age = age;
        } else {
            throw new IllegalArgumentException(
                "Age must be between 0 and 120."
            );
        }
    }

    public int getAge() {
        return age;
    }
}

public class SetterDemo {
    public static void main(String[] args) {
        Person person = new Person();
        person.setAge(25);
        System.out.println(person.getAge());
    }
}

Output:

25

The setter validates the input before updating the field. If an invalid value is passed, an IllegalArgumentException is thrown rather than silently accepting the value.

9. Practical Example: Encapsulation in a Bank Account

A bank account is a useful real-world example of encapsulation. The account balance must be protected because deposits and withdrawals need to follow specific rules. External code should not be able to change the balance by assigning any arbitrary number.

Complete Java Program

class BankAccount {
    private String accountHolder;
    private double balance;

    public BankAccount(String accountHolder, double openingBalance) {
        if (accountHolder == null || accountHolder.isBlank()) {
            throw new IllegalArgumentException(
                "Account holder name is required."
            );
        }

        if (openingBalance < 0) {
            throw new IllegalArgumentException(
                "Opening balance cannot be negative."
            );
        }

        this.accountHolder = accountHolder;
        this.balance = openingBalance;
    }

    public String getAccountHolder() {
        return accountHolder;
    }

    public double getBalance() {
        return balance;
    }

    public void deposit(double amount) {
        if (amount <= 0) {
            throw new IllegalArgumentException(
                "Deposit amount must be positive."
            );
        }

        balance += amount;
    }

    public boolean withdraw(double amount) {
        if (amount <= 0) {
            throw new IllegalArgumentException(
                "Withdrawal amount must be positive."
            );
        }

        if (amount > balance) {
            return false;
        }

        balance -= amount;
        return true;
    }
}

public class BankAccountDemo {
    public static void main(String[] args) {
        BankAccount account = new BankAccount("Priya", 5000.00);

        account.deposit(1500.00);

        boolean successful = account.withdraw(1000.00);

        System.out.println("Account Holder: "
                + account.getAccountHolder());
        System.out.println("Withdrawal Successful: " + successful);
        System.out.println("Current Balance: " + account.getBalance());
    }
}

Output:

Account Holder: Priya
Withdrawal Successful: true
Current Balance: 5500.0

Explanation of the Program

  • The accountHolder and balance fields are private, so outside code cannot directly assign values to them.
  • The constructor validates the account holder name and opening balance.
  • The getAccountHolder() and getBalance() methods provide read access.
  • The deposit() method accepts only positive amounts.
  • The withdraw() method prevents withdrawals that exceed the available balance.
  • The class controls how its balance changes and protects its core business rules.

Important: This is an educational example. Financial applications require additional protections, such as suitable decimal arithmetic for money, transaction consistency, concurrency control, authorization, and secure audit logging.

10. Example of a Class Without Proper Encapsulation

Consider a class that exposes its balance as a public field. Other code can directly assign an invalid value without using any validation logic.

class UnsafeAccount {
    public double balance;
}

public class UnsafeAccountDemo {
    public static void main(String[] args) {
        UnsafeAccount account = new UnsafeAccount();
        account.balance = -10000;
        System.out.println(account.balance);
    }
}

Output:

-10000.0

The program compiles, but the account can enter an invalid state because the balance is publicly accessible. In a properly encapsulated design, the balance would be private and changes would be handled through validated operations.

11. Read-Only and Write-Only Access

Encapsulation does not require every field to have both a getter and a setter. The class should expose only the operations that are appropriate for its requirements.

11.1 Read-Only Field Access

A class can provide a getter but no public setter. This allows callers to read a value without giving them a direct method to replace it.

class Product {
    private final String productCode;

    public Product(String productCode) {
        this.productCode = productCode;
    }

    public String getProductCode() {
        return productCode;
    }
}

The final field can be assigned once during initialization and cannot subsequently be reassigned. This is useful for values such as an immutable product code.

11.2 Write-Only Access

A class may provide a method to accept a value without providing a method that returns the stored value. For example, a credential-handling component might accept a password and store a derived representation without exposing the original password. In practice, sensitive credentials should be handled with appropriate security measures rather than stored as plain text.

12. Encapsulation vs. Abstraction

Encapsulation and abstraction are related OOP concepts, but they solve different design problems.

Feature Encapsulation Abstraction
Primary focus Controls access to data and implementation details. Exposes essential behavior while hiding unnecessary complexity.
Common Java techniques Private fields and controlled methods. Interfaces, abstract classes, and clear public APIs.
Main question How should an object's internal state be accessed or changed? What operations should a caller be able to use?
Example Keeping a balance private and changing it through deposit and withdrawal methods. Providing a payment interface that exposes a pay operation without revealing its implementation.

13. Best Practices for Encapsulation

  • Declare instance fields private by default unless a clear reason justifies wider access.
  • Expose behavior through meaningful methods rather than allowing arbitrary field updates.
  • Validate inputs at the point where the object accepts them.
  • Do not create setters for fields that should not change after construction.
  • Avoid getters that expose mutable internal collections or arrays directly; return defensive copies or read-only views where appropriate.
  • Use meaningful operations such as deposit(), withdraw(), or changePassword() when they better express business rules than generic setters.
  • Keep validation rules consistent across constructors and methods that update the same state.
  • Document important conditions and exceptions so callers understand how to use the class.
  • Remember that encapsulation controls ordinary access; it does not automatically provide encryption, authorization, or complete security.

14. Common Mistakes to Avoid

Mistake Why It Is a Problem Recommended Approach
Making all fields public Any accessible code can change the object's state directly. Use private fields and expose only necessary operations.
Creating setters without validation Invalid data can still enter the object. Validate values before updating fields.
Providing unnecessary getters Internal or sensitive information may be exposed unnecessarily. Expose only the information callers need.
Returning mutable internal objects Callers may modify internal state indirectly. Use defensive copies or immutable representations when needed.
Confusing private access with complete security Access modifiers alone do not protect an application from every threat. Combine good class design with suitable application security controls.
Using generic setters for every operation Business rules can become unclear or difficult to enforce. Prefer domain-specific methods when they express the required action more accurately.

15. Troubleshooting Encapsulation Errors

Problem 1: The Field Has Private Access

Example error: Attempting to access person.age from another class when age is private.

Solution: Call a suitable public method, such as person.getAge(), or add a validated update method if modification is required.

Problem 2: A Setter Accepts Invalid Values

Cause: The setter assigns the supplied value without checking whether it is allowed.

Solution: Add appropriate validation and reject invalid input using a documented approach, such as throwing IllegalArgumentException.

Problem 3: The Field Value Does Not Change

Cause: A setter may be missing, the validation condition may reject the value, or the method may assign a parameter to itself instead of updating the field.

Solution: Use this.fieldName = fieldName; when the parameter and instance field share the same name. Check validation conditions and test both valid and invalid input.

Problem 4: A Getter Exposes Internal Data

Cause: A getter returns a mutable collection or array stored directly inside the object.

Solution: Return a defensive copy or an appropriately restricted view, depending on the requirements.

16. Practical Exercises

  1. Student class: Create private fields for student name, roll number, and marks. Add getters and setters that validate marks between 0 and 100.
  2. Employee class: Create a private salary field and a method that accepts only positive salary values.
  3. Bank account: Implement deposit and withdrawal methods that prevent negative transactions and overdrafts.
  4. Product class: Create private product name and price fields. Reject blank names and negative prices.
  5. Read-only object: Create a class whose identifier is assigned in the constructor and cannot be changed through public methods.
  6. Defensive copying: Create a class that stores a list internally and prevents external callers from modifying that list directly.

17. Mini Project: Student Record Management

Objective: Build a small Java program that demonstrates encapsulation by storing student details safely.

Requirements

  • Create a StudentRecord class.
  • Declare the student's name, roll number, and marks as private fields.
  • Validate that the name is not null or blank.
  • Accept marks only in the range 0 to 100.
  • Provide getters for information that users are allowed to view.
  • Create a method to display the student record without exposing the fields directly.
  • Test valid inputs and invalid inputs to confirm that the validation rules work correctly.

Expected Learning Outcome

After completing this project, learners should understand how private fields, controlled methods, and validation work together to protect an object's state and make a Java program easier to maintain.

18. Core Java Interview Questions and Answers

Q1. What is encapsulation in Java?

Answer: Encapsulation is the OOP principle of combining data and related methods in a class while controlling access to the object's internal state through a defined interface.

Q2. What is data hiding?

Answer: Data hiding restricts direct access to internal data. Java commonly uses the private access modifier to hide fields from unrelated classes.

Q3. How do you achieve encapsulation in Java?

Answer: A common approach is to declare fields private and expose only the necessary public methods for reading or changing values. Methods can validate input before modifying the object's state.

Q4. What is the difference between a getter and a setter?

Answer: A getter provides read access to a value, while a setter provides a way to update a value. A setter can validate input before storing it.

Q5. Is a setter required for every private field?

Answer: No. A field may be read-only, internally managed, or intentionally inaccessible from outside the class. Provide only the access methods required by the design.

Q6. Can encapsulation improve data integrity?

Answer: Yes. Encapsulation allows a class to validate operations and maintain its required conditions before accepting changes to its state.

Q7. What happens if a private field is accessed directly from another unrelated class?

Answer: The code normally fails to compile because the field is not accessible from that class.

Q8. Is encapsulation the same as abstraction?

Answer: No. Encapsulation controls access to an object's internal state and implementation, while abstraction focuses on presenting essential functionality without exposing unnecessary complexity.

Q9. Can a class be encapsulated without using setters?

Answer: Yes. A class can use constructors, getters, and domain-specific methods, or provide no public access to certain fields. Setters are not mandatory.

Q10. Does making a field private guarantee complete security?

Answer: No. Private access limits ordinary direct access according to Java's access rules, but application security also depends on authentication, authorization, secure storage, validation, and other protections.

19. Quick Revision Notes

  • Encapsulation combines data and related behavior within a class and controls access to the object's state.
  • Data hiding restricts direct access to internal information.
  • The private modifier is commonly used for fields.
  • Getters provide controlled read access when needed.
  • Setters or domain-specific methods can validate input before updating state.
  • Not every field needs a getter or setter.
  • Good encapsulation improves maintainability, reusability, and data integrity.
  • Encapsulation and abstraction are related but distinct OOP concepts.
  • Access modifiers do not replace application-level security measures.

20. Conclusion

Encapsulation and data hiding are essential concepts in Core Java because they help developers build reliable, maintainable, and well-organized applications. By keeping fields private and exposing only appropriate methods, a class can control how its internal state is accessed and modified. Validation, meaningful operations, and careful access decisions help prevent invalid data and make programs easier to test and extend.

Practice these concepts by creating student records, employee details, product inventories, and bank account classes. Focus on protecting internal fields, validating updates, and exposing only the functionality that callers genuinely need.

Learn More with JustAcademy

Explore the Core Java Training Course to continue learning Java programming, classes, objects, constructors, OOP principles, and practical application development.

Interested in learning more about the course? Register for a Course Demo or visit the JustAcademy website.

Previous Next
whatsapp