Encapsulation With Example And Benefits In Java & OOP

Object-oriented programming tries to model real-life objects into the programming world. This makes the programs easy to co-relate with real-world and understand. Encapsulation is one of the key concepts, which plays crucial role in this modelling along with Abstraction and Polymorphism.

For impatient readers, I will just define the encapsulation and then move on with the example.

  1. To encase in or as if in a capsule
  2. To express in a brief summary
Technical translation of encapsulation,
  1. Wrapping of data in a construct such that it hides its internal data
  2. Provide behaviour methods to control access of data in desired fashion

Analysing Real-life Objects

First of all, what do we expect from real-life objects is behaviour.

Take a car as an example. What are expectations from Car? Start the car. Accelerate the car. Brake. Move to reverse slowly. Stop. That’s it. To achieve these behaviour, you are provided with some of the mechanisms. Ignition to start and stop the car. Gearbox, accelerator and brake to increase or decrease the speed of car. You use these accelerator and brake to achieve the desired speed of the car.

How this relates with Encapsulation? Lets understand this with a vanilla version of Car in Java.

Warning: Use this version of class in your application at your own risk.

class Car{
  public float speed =0;
  public boolean isReverse = false;
  public boolean isStarted = false;
}

You believe that all your clients of Car class are sensible and will use it as shown below.

class Main{
  public static void main(args String[]){
    Car car = new Car();

    car.isStarted = true;

    car.setSpeed = 10;
    car.setSpeed = 20;
    car.setSpeed = 30;
    car.setSpeed = 20;
    car.setSpeed = 10;
    car.setSpeed = 0;
    car.isReverse = true;
    car.setSpeed = 10;
    car.setSpeed = 0;
    car.isStarted = false;
  }
}

How client code may will use it.

class Main{
  public static void main(args String[]){
    Car car = new Car();

    // No need to start??
    car.speed = 100; // Turbo mode directly to 100
    car.speed = 0; // Turbo brake
  }
}
class Main{
  public static void main(args String[]){
    Car car = new Car();

    car.isStarted = true;
    car.isReverse = true;
    car.setSpeed = 100;
  }
}

You see what is wrong here. Access to data of the Car is uncontrolled. However, real-life objects often impose constraints on the way objects can be used.

What can we do to make this Car class usable? In real-world, you get accelerator to speed up the car, brake to reduce speed of the car. Shouldn’t our objects reflect that fact as well? Therefore, here’s what we can do.

  1. Hide internal data(speed, isStarted, isReverse) from client
  2. Provide behaviour methods to provide controlled access to its data.

Encapsulation In Java

Java provides 4 different access modifiers to control visibility of internal data from outside world. private, protected, default(no access modifier) and public. Here is the quick reference of these modifiers for Java beginners.

private – Most restrictive, allows only class level access.
default – Package level access.
protected – Package level access + access to sub-classes.
public – Least restrictive, doesn’t impose any visibility constraint.

Let us see encapsulation of the car class to achieve desired behaviour.

class Car{

  private float speed =0;
  private boolean isReverse = false;
  private boolean isStarted = false;

  public void start(){
    if(isStarted()){
      // the car is already started
    }else{
      isStarted = true;
    }
  }

  public void accelerate(){
    if(isStarted){
      speed += 10;
    }else{
      // car is not started yet
    }
  }

  public void brake(){
    if(isStarted){
      speed -= 10;
    }else{
      // car is not started yet
    }
  }

  public void stop(){
    if(isStarted){
      isStarted = false;
    }else{
      // car is already stopped
    }
  }

}

Client of this Car class will look like below.

class Main{
  
  public static void main(args String[]){

    Car car = new Car();

    car.reverse(); // Display error or throw exception
    car.start();

    car.accelerate();
    car.accelerate();
    car.accelerate();
    
    car.brake();
    car.brake();
    car.brake();
    
    car.stop();
  }

}

Does’t that look more realistic? Hell yes!

Another example of the encapsulation is BankAccount. Clients cannot directly access balance of the account. The access to balance is controlled via methods like checkBalance(), deposit(), withdraw().

Benefits of Encapsulation

  1. If done rightly, modelled entities become closer to real-world. Therefore, making them easier to understand intuitively.
  2. Control the way data is accessed or modified.
  3. Makes the class easy to use for clients.
  4. Increase reusability.
  5. Aids to the flexibility of design. For instance, it is possible to add accelerationConfiguration field in the Car. This will enable you to have different acceleration behaviour of each car.

In summary, encapsulation wraps the data to hide internals from outside world. On top of that, it binds behaviours with the objects to provide controlled access of the data. This makes it easy to see your object as real-life entities making the class easy to understand, maintain, reuse for different purposes.

6 Comments
  • Reply Manish Kumar

    August 19, 2015, 7:30 am

    Hi, I have a doubt on points given about benefits of encapsulation, Now my question is .
    how can you justify, “encapsulation increase flexibility and increase re-usability” please justify each one , and thanks for your contribution to understand encapsulation and you have delivered such a nice example!.

    • Reply Vishal Shukla

      August 24, 2015, 5:37 pm

      Hi Manoj,

      Thanks for your warm feedback about the post.

      I would put it this way,

      Reusability:

      No encapsulation == No behaviour to objects
      No behaviours == conventional logic methods in outer layers

      A, B, C layers use component X with behaviour, then behaviour is at single place.
      A, B, C layers use component X without behaviour, they will their own, duplicated implemntations.

      Flexibility:

      Its all about low level – intelligent – components. Each one knowing just about themselves and very little about others, making them losely coupled. If you take the encapsulation out of the equation, you just can’t give intelligence to these low level components – as they would turn out to be dumb data objects. Hence pushing the intelligence to upper most level – a monolithic procedural-style method containing all the logic.

      I hope the explanation makes sense.

      Best Regards,
      Vishal Shukla

  • Reply Pinal Shah

    September 2, 2015, 3:36 pm

    Hi .. I really love your article…its amazing…now i want your permission to use some of your content in my book..i am planning to write a book on Java …again thank you..really a good post…Thank You

  • Reply santosh

    October 25, 2015, 11:49 am

    Hi Vishal,
    Thank you very much for elucidating this concept. I found it very much helpful.

  • Reply haribabu saladi

    October 24, 2016, 11:49 pm

    Hi vishal,

    This is very nice article.. but still i have one doubt.. we can access the private variables data via public setters and getter mothods right.. then how can we achieve control from client or outside world?

    Thanks
    Hari saladi

Write a comment