Table of Contents

    Encapsulation


    Chapter 16.7

    Encapsulation in Object-Oriented Programming

    Learn what encapsulation is in Object-Oriented Programming, how it protects object data, why private properties and public methods are used, and how encapsulation improves security, maintainability, validation, and clean software design.

    Introduction

    Encapsulation is one of the most important principles of Object-Oriented Programming. It means wrapping related data and methods together inside a single unit, usually a class, and controlling how that data can be accessed or modified from outside the class.

    In simple terms, encapsulation helps protect the internal data of an object. Instead of allowing other parts of the program to directly change object data, encapsulation encourages controlled access through methods such as getters, setters, or specific business methods like deposit(), withdraw(), updateMarks(), or changePassword().

    Encapsulation is useful because object data should not always be freely accessible. Some data is sensitive, some data needs validation, and some data should only be changed through proper rules. Encapsulation helps enforce those rules inside the class.

    "Encapsulation is the process of bundling data and methods together and protecting the data from direct unwanted access."

    Simple Definition of Encapsulation

    Encapsulation is an OOP concept where the internal data of an object is hidden from direct outside access, and controlled access is provided through methods.

    In simple words:

    • Encapsulation keeps data and related methods together.
    • It hides sensitive data from direct access.
    • It allows controlled access using methods.
    • It protects object state from invalid changes.
    • It improves security, maintainability, and code organization.
    • It helps apply validation before updating data.
    ENCAPSULATION CONCEPT
    Encapsulation = Data Hiding + Controlled Access
    Important: Encapsulation does not mean hiding everything completely. It means exposing only what is necessary and protecting what should not be directly accessed.

    Encapsulation as a Protective Box

    Encapsulation can be understood as placing important data inside a protective box. The outside world cannot directly touch the data inside the box. Instead, it must use specific buttons or controls provided by the box.

    In programming, the class acts like the box. The properties are the data inside the box. The methods are the controlled buttons used to access or modify the data safely.

    Encapsulation as a Locked Box

    Sensitive data is kept inside a locked box. Other parts of the program cannot directly change it. They must use safe methods provided by the class.

    Real-World Concept Programming Concept Explanation
    Locked Box Class Contains and protects related data and behavior.
    Items Inside Box Private Properties Data that should not be changed directly.
    Authorized Buttons Public Methods Safe ways to access or update internal data.
    Security Rules Validation Logic Checks whether requested changes are allowed.

    Why Do We Need Encapsulation?

    Encapsulation is needed because direct access to object data can create serious problems. If any part of the program can freely modify object properties, then invalid values may be stored. This can make the object unreliable and can cause unexpected program behavior.

    For example, a bank account balance should not be directly changed from outside the class. If direct access is allowed, someone could set the balance to a negative value or change it without proper transaction rules. Encapsulation prevents this by making the balance private and allowing updates only through deposit() and withdraw() methods.

    Without Encapsulation

    • Data can be changed directly from outside the class.
    • Invalid values may be assigned accidentally.
    • Business rules can be bypassed.
    • Object state can become inconsistent.
    • Security and reliability are reduced.
    • Debugging becomes difficult in large programs.

    With Encapsulation

    • Important data is protected from direct access.
    • Values are updated through controlled methods.
    • Validation can be applied before changes.
    • Object state remains valid and consistent.
    • Code becomes safer and easier to maintain.
    • Internal implementation can change without affecting outside code.

    Main Idea Behind Encapsulation

    The main idea behind encapsulation is to separate how data is stored internally from how data is accessed externally. This means outside code should not depend on the internal details of a class.

    A class should expose only necessary operations. For example, a BankAccount class may expose deposit(), withdraw(), and getBalance(), but it should not expose direct access to the balance property.

    ENCAPSULATION RULE
    Keep Data Private   |   Provide Methods Public

    This design makes the class responsible for protecting its own data. Other parts of the program interact with the object through a controlled interface.

    Access Modifiers in Encapsulation

    Access modifiers are keywords used to control the visibility of class members such as properties and methods. They are an important part of encapsulation in many object-oriented programming languages.

    Common access modifiers include public, private, and protected. Different programming languages may support different access modifiers, but the basic idea is to control what can be accessed from outside the class.

    Access Modifier Meaning Common Usage
    public Can be accessed from outside the class. Used for methods that should be available to other parts of the program.
    private Can be accessed only inside the same class. Used for sensitive data that should not be changed directly.
    protected Can be accessed inside the class and related child classes. Used when inheritance is involved.
    Beginner Tip: A common encapsulation approach is to make properties private and provide public methods for controlled access.

    Real-World Example: Bank Account

    A bank account is one of the best examples of encapsulation. The balance of a bank account is sensitive data. It should not be directly modified from outside the class.

    Instead of allowing direct balance changes, the BankAccount class should provide methods like deposit() and withdraw(). These methods can validate the amount before changing the balance.

    Bank Account Data Should Be Directly Accessible? Better Access Method
    accountNumber No, usually should be protected after creation. getAccountNumber()
    accountHolderName Maybe, but through controlled update. getAccountHolderName(), updateHolderName()
    balance No, should not be directly changed. deposit(), withdraw(), getBalance()
    transactionHistory No, should be protected. getTransactionHistory()

    Poor Design Without Encapsulation

    The following example shows a poor design where the balance property is directly accessible. This can cause invalid data and unsafe behavior.

    
    class BankAccount {
    
        public String accountNumber;
        public String accountHolderName;
        public double balance;
    }
    
    public class Main {
        public static void main(String[] args) {
    
            BankAccount account1 = new BankAccount();
    
            account1.accountNumber = "A101";
            account1.accountHolderName = "Rahul";
            account1.balance = 5000;
    
            // Problem: balance can be changed directly to invalid value
            account1.balance = -10000;
    
            System.out.println("Balance: " + account1.balance);
        }
    }
    

    In this example, the balance is public. Any part of the program can directly change it, even to a negative value. This is unsafe and violates encapsulation.

    Problem Direct access to sensitive data can create invalid object states and bypass important business rules.

    Better Design With Encapsulation

    A better design is to make sensitive data private and provide controlled methods to access or update it. This protects the object from invalid changes.

    
    class BankAccount {
    
        private String accountNumber;
        private String accountHolderName;
        private double balance;
    
        BankAccount(String number, String holderName, double initialBalance) {
            accountNumber = number;
            accountHolderName = holderName;
    
            if (initialBalance >= 0) {
                balance = initialBalance;
            } else {
                balance = 0;
            }
        }
    
        public void deposit(double amount) {
            if (amount > 0) {
                balance = balance + amount;
            } else {
                System.out.println("Invalid deposit amount");
            }
        }
    
        public void withdraw(double amount) {
            if (amount > 0 && amount <= balance) {
                balance = balance - amount;
            } else {
                System.out.println("Invalid withdrawal amount");
            }
        }
    
        public double getBalance() {
            return balance;
        }
    
        public void displayAccountDetails() {
            System.out.println("Account Number: " + accountNumber);
            System.out.println("Account Holder: " + accountHolderName);
            System.out.println("Balance: " + balance);
        }
    }
    
    public class Main {
        public static void main(String[] args) {
    
            BankAccount account1 = new BankAccount("A101", "Rahul", 5000);
    
            account1.deposit(1000);
            account1.withdraw(1500);
    
            account1.displayAccountDetails();
    
            System.out.println("Current Balance: " + account1.getBalance());
        }
    }
    

    In this example, the balance property is private. It cannot be changed directly from outside the class. It can only be changed through deposit() and withdraw() methods, which apply validation.

    Better Design The object controls its own data. Outside code can request actions, but it cannot directly corrupt the internal state.

    Getters and Setters in Encapsulation

    Getters and setters are methods commonly used to access and update private properties. A getter reads a value, while a setter updates a value.

    However, setters should not blindly assign values. A good setter should validate data before storing it. This is one of the main benefits of encapsulation.

    GETTER AND SETTER
    Getter Reads Data   |   Setter Updates Data Safely
    
    class Student {
    
        private String name;
        private int marks;
    
        public String getName() {
            return name;
        }
    
        public void setName(String studentName) {
            if (studentName != null && !studentName.isEmpty()) {
                name = studentName;
            } else {
                System.out.println("Invalid name");
            }
        }
    
        public int getMarks() {
            return marks;
        }
    
        public void setMarks(int studentMarks) {
            if (studentMarks >= 0 && studentMarks <= 100) {
                marks = studentMarks;
            } else {
                System.out.println("Invalid marks. Marks must be between 0 and 100.");
            }
        }
    }
    

    In this example, name and marks are private. They can be accessed or updated only through getter and setter methods. The setter for marks ensures that invalid marks are not stored.

    Student Example of Encapsulation

    In a student management system, marks should not be assigned directly without validation. Marks should be between 0 and 100. Encapsulation helps enforce this rule.

    
    class Student {
    
        private String name;
        private int rollNumber;
        private int marks;
    
        Student(String studentName, int studentRollNumber, int studentMarks) {
            name = studentName;
            rollNumber = studentRollNumber;
            setMarks(studentMarks);
        }
    
        public void setMarks(int studentMarks) {
            if (studentMarks >= 0 && studentMarks <= 100) {
                marks = studentMarks;
            } else {
                marks = 0;
                System.out.println("Invalid marks. Default value assigned.");
            }
        }
    
        public int getMarks() {
            return marks;
        }
    
        public String calculateGrade() {
            if (marks >= 90) {
                return "A";
            } else if (marks >= 75) {
                return "B";
            } else if (marks >= 60) {
                return "C";
            } else if (marks >= 40) {
                return "D";
            } else {
                return "Fail";
            }
        }
    
        public void displayDetails() {
            System.out.println("Name: " + name);
            System.out.println("Roll Number: " + rollNumber);
            System.out.println("Marks: " + marks);
            System.out.println("Grade: " + calculateGrade());
        }
    }
    
    public class Main {
        public static void main(String[] args) {
    
            Student student1 = new Student("Ayesha", 102, 92);
    
            student1.displayDetails();
    
            student1.setMarks(105);
    
            System.out.println("Updated Marks: " + student1.getMarks());
        }
    }
    

    In this example, marks are protected from invalid values. Even if someone tries to set marks to 105, the setter method can reject or control the update.

    JavaScript Example of Encapsulation

    JavaScript also supports encapsulation. Modern JavaScript allows private fields using the # symbol. These private fields cannot be directly accessed from outside the class.

    Prerequisites: To understand this example, you should know JavaScript classes, constructors, methods, the this keyword, conditional statements, and console output.
    
    class BankAccount {
    
        #balance;
    
        constructor(accountNumber, accountHolderName, initialBalance) {
            this.accountNumber = accountNumber;
            this.accountHolderName = accountHolderName;
    
            if (initialBalance >= 0) {
                this.#balance = initialBalance;
            } else {
                this.#balance = 0;
            }
        }
    
        deposit(amount) {
            if (amount > 0) {
                this.#balance = this.#balance + amount;
            } else {
                console.log("Invalid deposit amount");
            }
        }
    
        withdraw(amount) {
            if (amount > 0 && amount <= this.#balance) {
                this.#balance = this.#balance - amount;
            } else {
                console.log("Invalid withdrawal amount");
            }
        }
    
        getBalance() {
            return this.#balance;
        }
    
        displayAccountDetails() {
            console.log("Account Number: " + this.accountNumber);
            console.log("Account Holder: " + this.accountHolderName);
            console.log("Balance: " + this.#balance);
        }
    }
    
    const account1 = new BankAccount("A101", "Rahul", 5000);
    
    account1.deposit(1000);
    account1.withdraw(1500);
    
    account1.displayAccountDetails();
    
    console.log("Current Balance: " + account1.getBalance());
    

    In this example, #balance is private. It cannot be directly accessed from outside the BankAccount class. The balance can only be changed through deposit() and withdraw() methods.

    Encapsulation and Data Hiding

    Data hiding is closely related to encapsulation. It means hiding internal data from direct outside access. Encapsulation uses data hiding to protect object properties and expose only necessary methods.

    However, encapsulation is broader than data hiding. Encapsulation includes both bundling data and methods together and controlling access to data.

    Concept Meaning Example
    Encapsulation Wrapping data and methods together with controlled access. BankAccount class contains balance and deposit methods.
    Data Hiding Restricting direct access to internal data. balance is private and cannot be directly changed.
    Controlled Access Providing safe public methods to interact with private data. deposit(), withdraw(), getBalance()

    Encapsulation and Validation

    Encapsulation allows validation to be placed inside methods. This ensures that any change to important data follows rules.

    For example, product price should not be negative, student marks should be between 0 and 100, and withdrawal amount should not be greater than account balance.

    Property Validation Rule Controlled Method
    marks Must be between 0 and 100. setMarks()
    balance Cannot become negative after withdrawal. withdraw()
    price Should not be negative. setPrice()
    stockQuantity Should not be below zero. updateStock()
    email Should follow a valid email format. setEmail()

    Product Example of Encapsulation

    In an e-commerce system, product price and stock should be controlled properly. Price should not be negative, and stock should not become invalid.

    
    class Product {
    
        private String productName;
        private double price;
        private int stockQuantity;
    
        Product(String name, double productPrice, int stock) {
            productName = name;
            setPrice(productPrice);
            setStockQuantity(stock);
        }
    
        public void setPrice(double productPrice) {
            if (productPrice >= 0) {
                price = productPrice;
            } else {
                System.out.println("Invalid price");
                price = 0;
            }
        }
    
        public void setStockQuantity(int stock) {
            if (stock >= 0) {
                stockQuantity = stock;
            } else {
                System.out.println("Invalid stock quantity");
                stockQuantity = 0;
            }
        }
    
        public double getPrice() {
            return price;
        }
    
        public int getStockQuantity() {
            return stockQuantity;
        }
    
        public void reduceStock(int quantity) {
            if (quantity > 0 && quantity <= stockQuantity) {
                stockQuantity = stockQuantity - quantity;
            } else {
                System.out.println("Invalid stock reduction");
            }
        }
    
        public void displayProduct() {
            System.out.println("Product Name: " + productName);
            System.out.println("Price: " + price);
            System.out.println("Stock Quantity: " + stockQuantity);
        }
    }
    

    This Product class protects price and stockQuantity from invalid changes. All updates go through controlled methods.

    Public Interface and Private Implementation

    Encapsulation separates the public interface from the private implementation. The public interface is what outside code can use. The private implementation is the internal logic hidden inside the class.

    For example, a user of a BankAccount object needs to know that deposit() adds money and withdraw() removes money. They do not need to know exactly how the balance is stored internally.

    ENCAPSULATION DESIGN
    Public Interface What to Use   |   Private Implementation How It Works

    Public Interface

    • deposit(amount)
    • withdraw(amount)
    • getBalance()
    • displayAccountDetails()

    Private Implementation

    • How balance is stored internally.
    • How validation is performed.
    • How internal calculations are managed.
    • How internal data is protected.

    Encapsulation Helps Maintainability

    One of the biggest advantages of encapsulation is maintainability. If internal implementation details are hidden, developers can change the internal code without affecting other parts of the program.

    For example, suppose a class currently stores fullName as one property. Later, the developer may decide to store firstName and lastName separately. If outside code uses a method like getFullName(), the internal change can be made without breaking outside code.

    
    class UserProfile {
    
        private String firstName;
        private String lastName;
    
        UserProfile(String first, String last) {
            firstName = first;
            lastName = last;
        }
    
        public String getFullName() {
            return firstName + " " + lastName;
        }
    }
    

    Outside code only calls getFullName(). It does not need to know how the name is stored internally.

    Encapsulation vs Abstraction

    Encapsulation and abstraction are related but different concepts. Beginners often confuse them, so it is important to understand the difference clearly.

    Basis Encapsulation Abstraction
    Main Focus Protecting data and controlling access. Hiding complexity and showing only essential features.
    Question Answered How do we protect object data? How do we hide unnecessary details?
    Implemented Using Private properties, public methods, getters, setters. Interfaces, abstract classes, simplified public methods.
    Example Bank balance is private and updated through deposit(). User presses ATM buttons without knowing internal banking logic.
    Purpose Data protection and controlled modification. Simplification and hiding implementation complexity.

    Encapsulation vs Data Hiding

    Data hiding is a part of encapsulation, but encapsulation is not limited to data hiding only. Encapsulation also includes grouping data and methods together.

    Basis Encapsulation Data Hiding
    Meaning Bundling data and methods together with controlled access. Restricting direct access to data.
    Scope Broader concept. Part of encapsulation.
    Focus Organization and protection. Protection only.
    Example BankAccount class with private balance and public methods. Making balance private.

    Advantages of Encapsulation

    Encapsulation provides many practical benefits in software development. It helps keep code secure, organized, reusable, and easier to maintain.

    Benefits of Encapsulation

    • Data Protection: Sensitive data can be hidden from direct access.
    • Controlled Access: Data can be accessed only through defined methods.
    • Validation: Values can be checked before updating properties.
    • Maintainability: Internal implementation can change without affecting outside code.
    • Reduced Errors: Invalid object states can be prevented.
    • Improved Security: Important data is not exposed unnecessarily.
    • Cleaner Code: Related data and methods stay together inside a class.
    • Better Debugging: Data changes are controlled through specific methods.
    • Code Reusability: Encapsulated classes can be reused safely.
    • Real-World Modeling: Objects can behave like controlled real-world entities.

    Limitations of Encapsulation

    Encapsulation is very useful, but beginners should also understand its limitations. Like every design principle, it should be used properly.

    More Code Encapsulation may require extra getter, setter, and validation methods, which can increase the amount of code.
    Overuse of Getters and Setters Creating getters and setters for every property without thinking can weaken encapsulation and expose too much data.
    Initial Learning Curve Beginners may need time to understand private data, public methods, and controlled access.
    Poor Design Still Causes Problems Simply making properties private does not automatically create good encapsulation. Methods must be designed properly.

    Characteristics of Good Encapsulation

    Good encapsulation is not just about using private properties. It is about designing a class that protects its data and exposes meaningful operations.

    Good Encapsulation Principles

    • Keep sensitive data private.
    • Expose only necessary methods to outside code.
    • Use validation before updating important values.
    • Avoid providing setters for data that should not change.
    • Use meaningful method names that describe allowed operations.
    • Keep internal implementation details hidden.
    • Make sure object state remains valid after every operation.
    • Do not expose internal data structures directly when they should be protected.
    • Use constructors to initialize objects properly.
    • Design methods based on real business rules, not only property access.

    Encapsulation Best Practices

    To use encapsulation effectively, developers should focus on protecting data and exposing meaningful behavior. A class should not behave like a simple bag of public variables.

    Best Practices for Beginners

    • Make important properties private.
    • Use public methods to provide controlled access.
    • Validate input before changing private data.
    • Use getters only when outside code really needs to read the value.
    • Use setters only when outside code should be allowed to update the value.
    • Prefer meaningful methods like deposit() instead of generic setBalance().
    • Keep class responsibilities clear and focused.
    • Avoid exposing internal collections directly if they can be modified unsafely.
    • Use constructors to set required values at object creation.
    • Keep the public interface simple and understandable.

    Common Mistakes Beginners Make

    While learning encapsulation, beginners often make mistakes that reduce the benefits of data protection. Understanding these mistakes helps in writing better object-oriented programs.

    Common Mistakes

    • Making all properties public.
    • Using private properties but creating setters for everything.
    • Not validating input values inside setters.
    • Using generic methods like setData() without clear purpose.
    • Exposing sensitive data unnecessarily.
    • Allowing invalid object states.
    • Writing business rules outside the class instead of inside methods.
    • Thinking encapsulation only means using private keyword.

    Better Approach

    • Protect important properties using private access.
    • Expose only meaningful public methods.
    • Validate data before updating properties.
    • Use specific methods such as deposit(), withdraw(), updateEmail().
    • Hide unnecessary internal details.
    • Keep object state valid at all times.
    • Place object-related rules inside the class.
    • Use encapsulation as a design principle, not only a syntax rule.

    How to Apply Encapsulation Step by Step

    When designing a class, you can apply encapsulation by carefully deciding which data should be hidden and which operations should be exposed.

    Steps to Apply Encapsulation

    • Identify the important data of the class.
    • Decide which properties should not be directly accessible.
    • Make sensitive properties private.
    • Create public methods for safe operations.
    • Add validation inside methods where needed.
    • Use constructors to initialize required values.
    • Avoid unnecessary setters for read-only data.
    • Test whether invalid values can be prevented.
    • Keep method names meaningful and action-based.
    • Ensure the object remains valid after each method call.
    STEP-BY-STEP RULE
    Identify Data Protect It Provide Safe Methods

    Example: Encapsulation in Student Management System

    Suppose we are designing a student management system. The Student class may contain data such as name, roll number, marks, and course. Some of this data should be protected.

    Property Encapsulation Decision Reason Controlled Method
    name Private with controlled update Name should not be empty. setName()
    rollNumber Private and mostly read-only Roll number should not change frequently. getRollNumber()
    marks Private with validation Marks must be between 0 and 100. setMarks(), getMarks()
    course Private with controlled update Course should be updated only through proper process. changeCourse()

    Real-World Software Examples of Encapsulation

    Encapsulation is used in almost every real-world software system. It helps ensure that important data is changed only through valid operations.

    System Protected Data Controlled Operations
    Banking Application balance, accountNumber, transactionHistory deposit(), withdraw(), transferMoney()
    E-Commerce Application price, stockQuantity, orderStatus applyDiscount(), reduceStock(), updateOrderStatus()
    School Management System marks, rollNumber, attendance setMarks(), markAttendance(), calculateGrade()
    Hospital Management System patientRecord, billingInfo, appointmentStatus updateDiagnosis(), generateBill(), bookAppointment()
    User Account System passwordHash, email, loginAttempts changePassword(), updateEmail(), recordFailedLogin()

    Mini Practice Activity

    Try to identify which properties should be private and which methods should be provided for controlled access. This exercise will help you understand encapsulation practically.

    Class Private Properties Public Methods Validation Rule
    BankAccount balance, accountNumber deposit(), withdraw(), getBalance() Balance should not become negative.
    Student marks, rollNumber setMarks(), getMarks(), calculateGrade() Marks must be between 0 and 100.
    Product price, stockQuantity setPrice(), reduceStock(), getStockQuantity() Price and stock should not be negative.
    UserAccount passwordHash, loginAttempts changePassword(), login(), resetPassword() Password should follow security rules.
    Vehicle speed, fuelLevel accelerate(), brake(), refuel() Speed and fuel level should stay within valid limits.

    Frequently Asked Questions

    1. What is encapsulation in simple words?

    Encapsulation means keeping data and related methods together inside a class and protecting the data from direct outside access.

    2. Why is encapsulation important?

    Encapsulation is important because it protects object data, prevents invalid changes, supports validation, improves security, and makes code easier to maintain.

    3. How is encapsulation implemented?

    Encapsulation is commonly implemented by making properties private and providing public methods such as getters, setters, or specific business methods to access or update the data safely.

    4. Is encapsulation only data hiding?

    No. Data hiding is part of encapsulation. Encapsulation also includes bundling related data and methods together inside a class.

    5. What is the difference between private and public?

    Private members can be accessed only inside the class. Public members can be accessed from outside the class. Encapsulation commonly uses private properties and public methods.

    6. Should every property have getter and setter methods?

    Not always. Only provide getters and setters when they are needed. Some data should be read-only, and some data should only be changed through meaningful methods.

    7. What is a getter?

    A getter is a method used to read or return the value of a private property.

    8. What is a setter?

    A setter is a method used to update the value of a private property. A good setter usually validates the value before assigning it.

    9. Can encapsulation improve security?

    Yes. Encapsulation improves security by preventing direct access to sensitive data and allowing controlled access through methods.

    10. What is a real-world example of encapsulation?

    A bank account is a real-world example. The balance is hidden and cannot be changed directly. It can be changed only through deposit and withdraw operations.

    Summary

    Encapsulation is one of the core principles of Object-Oriented Programming. It means wrapping related data and methods together inside a class and protecting the data from direct outside access.

    Encapsulation helps keep object data safe and valid. It allows developers to make properties private and provide public methods for controlled access. These methods can validate input, apply business rules, and prevent invalid object states.

    Good encapsulation improves data protection, maintainability, readability, and reliability. It also makes large programs easier to manage because internal implementation details can be changed without affecting outside code.

    Key Takeaway

    Encapsulation is the OOP principle of keeping data and methods together while protecting internal data from direct access. It is commonly achieved using private properties and public methods, allowing safe, controlled, and validated interaction with objects.