What is Encapsulation: An Introduction with Examples in Java and Python

Sharing is caring

In this post, we are going to introduce the concept of encapsulation in object-oriented programming. We will first look at encapsulation in Java followed by encapsulation in Python. If you are only interested in how to implement encapsulation in one of those languages, feel free to skip to the relevant section.

What is Encapsulation?

Encapsulation describes the idea that the functionality of code should be limited to a largely self-contained unit. The encapsulated code is isolated in a class or module. Communication with the outside world happens through an interface.

In a properly encapsulated class, you usually have

  • variables storing data, and internal methods that only work with variables and other methods within the class.
  • public methods that form an API that is accessible by the outside world.
What is encapsulation

Many languages also have a level between public and private such as protected in Java which limits access to code to callers within the same modules.
As we will see with Java and Python, there are cultural differences between languages regarding the level of encapsulation. Statically typed languages such as Java and C tend to have much stricter access control than dynamically typed languages like Python.

Why is Encapsulation Important?

Because it gives you the ability to change implementations without affecting the rest of the system.
As your system grows, your classes and modules will have to change and adjust to changing requirements. You don’t want changes to a single class to ripple through the entire system and cause unintended side effects in other classes and modules. With proper encapsulation, you have the peace of mind that you can change anything you want within a class or module as long as you deliver the correct output to the external API.

Abstraction vs Encapsulation

Abstraction is the practice of isolating what an object does from how it does it. Encapsulation is the practice of hiding how an object does something from the outside world. Accordingly, abstraction and encapsulation are closely related but do not describe the same thing.

What is Encapsulation in Java?

Java distinguishes between 4 levels of protection that are implemented with access modifiers.

ModifierClassPackage/ModuleSubclassEveryone
publicYesYesYesYes
protectedYesYesYesNo
missing modifierYesYesNoNo
privateYesNoNoNo
Protection levels in Java

Java encapsulation entails relatively clear practices using these protection levels. You generally don’t make variables publicly accessible unless absolutely necessary. Instead, you create getter and setter methods. Here is an example using a class modeling a bike. The class contains the number of gears the bike has as well as its color.

public class Bike {
    private String color;
    private int gears;

    public Bike(String color, int gears){
        this.color = color;
        this.gears = gears;

    }

    public String getColor() {
        return color;
    }

    public int getGears() {
        return gears;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public void setGears(int gears) {
        this.gears = gears;
    }

As you can see, the color and gears are private, and instead, we access and modify them through dedicated methods.

Why Do We Use Getters and Setters in Java?


If you leave variables publicly accessible, you are violating the principle of encapsulation because any piece of code in your system could perform any operation on that variable. You are basically inviting unintended consequences as your codebase grows larger.

A core principle of clean object-oriented design is that every object should have a clearly defined API consisting of a set of methods. Every method should do exactly one thing. For example, a method should not change a variable and subsequently perform a calculation on another variable. If you have such methods in your code, unintended effects are likely to follow. A setter changes the private variable and nothing else. A getter retrieves the current value of the variable and nothing else. The method names clearly indicate what these methods do. You are explicitly defining what operations can be performed, and you can assume that any reasonable programmer will understand and properly use the API. If you have a lone variable that can be read, changed, overwritten, or set to null, all bets are off. Every programmer might do different things and think it is fine to alter its state. After a dozen functions have used the object, it is almost impossible to determine its current state.

Furthermore, setters allow you to check for illegal values and can throw an error in response. For example, if you cannot produce blue bikes, you can include a conditional statement that prevents the user from setting the color to blue (In a real program, you would have to add this check to the constructor and set an appropriate default value).

    public void setColor(String color) {
        
        if(color.equals("blue")) {
            System.out.println("Sorry, we don't have blue bikes. Please set another color");
            return;
        }
        this.color = color;
        
    }
encapsulation in java

As a general heuristic, you should always use the most restrictive access modifier while still being able to implement the logic you need.

Encapsulation in Python

Python has a different culture of access restriction when compared to Java that relies less on strict access controls. This begs the question of whether Python even has encapsulation.

Does Python Have Encapsulation?

Python has encapsulation, but it does not have explicit access modifiers such as private or protected. Instead, variables and methods can be made private by prefacing the method name with 2 underscores and protected by prefacing them with 1 underscore. Instance variables are not made private by default. Getters and setters can be created but doing so goes against the philosophy of Python, which values simplicity.

How to Use Encapsulation in Python?

Traditionally, you just create a class with instance variables like this:

class Bike:

    def __init__(self, color, current_gear):
        self.color = color
        self.gear = current_gear

As you can see, the constructor method is preceded by two underscores making it inaccessible for outside code.
The instance variables, however, remain publicly accessible. By default, you set and get them directly.

Encapsulation in Python

You can even delete the color directly on the bike instance.

But doesn’t this fly in the face of everything we discussed before on the reasons for using setters and getters in Java?
Well, the different philosophies of Java and Python are due to different purposes in the languages. Oracle created Java with the purpose of building large enterprise software systems.
Python was invented by a single guy on holiday who needed a simple solution for building utility tools for scientific computing.

While Python was created as a fully object-oriented language from the start, it was never intended as a replacement for Java or the C languages in enterprise software development. That being said, you can build software in Python, and there are ways to imitate the behavior of setters and getters to prevent anyone from setting the value of variables to anything. In Python, this can be done using properties.

First, we make our instance variables private by using double underscores.

    def __init__(self, color, current_gear):
        self.__color = color
        self.__gear = current_gear

Next, we can create getter and setter methods by using the @property and @setter annotations.

    @property
    def color(self):
        return self.__color

    @color.setter
    def color(self, color):
        self.__color = color

We can use the getter and the setter as if we were assigning directly to the instance variables.

what is encapsulation python

We can also check for illegal values and provide appropriate defaults. For example, ff the user sets blue as the color, we can inform him that this color is not possible and set red as default instead.

    @color.setter
    def color(self, color):
        if color == "blue":
            print("Sorry, we don't have blue bikes. Please set another color")
            self.__color = "red"
        else:
            self.__color = color

Running this code gives us the expected output.

python encapsulation


Sharing is caring