Encapsulation in Java

Encapsulation is a concept of protecting data and behavior of an object. It's very close related to another aspect of OOP: abstraction. Encapsulation enables a programmer to implement the desired level of abstraction, to hide information details. These two concepts makes OOP “safer” and easier to use.

Private No Public

Private Sign

In Java, encapsulation is done using classes, interfaces, setters and getters, and access modifiers.

  • A class or an interface encapsulated the set of features that are common to all objects of one type.
  • Setters and getters to control how variables are accessed and updated in the proper manner .
  • Access modifiers to restrict the scope of a class, constructor, variables, methods or other data members.

Java supports the following access modifiers:

  • private
  • public
  • protected
  • default

private

private access modifier allows a class to hide its member variables and member functions from another class. Only functions in the same class can access its private members. Even a subclass cannot access private members of the base class.

public

public access modifier allows a class to expose its member variables and member functions to another class. Any public members can be accessed from outside the class.

Let's check our example below.

Rectangle.java
public class Rectangle {
    
    // member variables are private, 
    // then we implement setter & getter
    private double height;
    private double width;

    /**
     * @return the height
     */
    public double getHeight() {
        return height;
    }

    /**
     * @param height the height to set
     */
    public void setHeight(double height) {
        this.height = height;
    }

    /**
     * @return the width
     */
    public double getWidth() {
        return width;
    }

    /**
     * @param width the width to set
     */
    public void setWidth(double width) {
        this.width = width;
    }
    
    public double getArea() {
        return this.height * this.width;
    }

    public void display() {
        System.out.println("Height: " + this.height);
        System.out.println("Width: " + this.width);
        System.out.println("Area: " +  getArea());
    }
}
                    

RectangleApp.java
public class RectangleApp {
    
    public static void main(String[] args) {
        Rectangle r = new Rectangle();
        r.setHeight(2.4);
        r.setWidth(4.9);
        r.display();
    }
}

/* 
Output:
------    
Height: 2.4
Width: 4.9
Area: 11.76
*/
                    

Class Rectangle has 2 private members, height & weight. To access height and weight, another class must go through class Rectangle's setter and getter. So code below:

public static void main(String[] args) {
        Rectangle r = new Rectangle();
        r.height = 2.4;
        r.width = 4.9;
        r.display();
 }
                    

will resulting compilation error:

RectangleApp.java:[5,10] height has private access in Rectangle RectangleApp.java:[6,10] width has private access in Rectangle

The member functions getArea() and display() in Class Rectangle can access these variables. In the example, since function display() is declared public, it can be accessed from main() using an instance of the Rectangle class, named r.

protected

protected access modifier allows a subclass to access "non private" member variables and member functions of its base class. This way it helps in implementing inheritance. Please read here for Inheritance in Java.

Let's check example codes below:

Rectangle.java
public class Rectangle {
    
    // member variables are protected
    protected double height;
    protected double width;
    
    protected double getArea() {
        return this.height * this.width;
    }
}
                    

Square.java
public class Square extends Rectangle {
    
    public String checkSquare() {
        if (this.width == this.height) {
            return "a square";
        }
        else {
            return "not a square";
        }
    }
    
    public static void main(String[] args) {
        Square s1 = new Square();
        s1.height = 10;
        s1.width = 12;
        System.out.print("s1 is " + s1.checkSquare());
        System.out.println (" with area: " + s1.getArea());
        
        Square s2 = new Square();
        s2.height = 7;
        s2.width = 7;
        System.out.print("s2 is " + s2.checkSquare());
        System.out.println (" with area: " + s2.getArea());
    }
}

/*
Output:
------  
s1 is not a square with area: 120.0
s2 is a square with area: 49.0
*/
                    

Since height and width are declared as protected in Rectangle, Square as a subclass able to access it directly without the need of helper functions like setter and getter.

default

If we never mention any access modifier above (public, private, and protected), then it becomes default. The members that having this modifier is only accessible by classes (or interfaces) in the same package as the source class. default members would not be visible in the class of another package.

Let's check example below:

Polygon.java
package com.dariawan.codes.oop;

public class Polygon {
    
    void draw() {
        System.out.println("Drawing Polygon");
    }
}
                    

What happen if we have Circle class but in different packages?

Circle.java
package com.dariawan.codes.shapes;

import com.dariawan.codes.oop.Polygon;

public class Circle extends Polygon {
    
    @Override
    public void draw() {
        System.out.println("Drawing Circle");
        super.draw();
    }
}
                    

We will encounter compilation error:

com/dariawan/codes/shapes/Circle.java:[7,5] method does not override or implement a method from a supertype com/dariawan/codes/shapes/Circle.java:[10,14] draw() is not public in com.dariawan.codes.oop.Polygon; cannot be accessed from outside package

draw() method in the Polygon class has no access modifier, which means that it is implicitly assigned the default / package access modifier. Since Circle class is in different package, it'll raise compilation error.

OK, now we know the problem, we need to correct it:

Circle.java
package com.dariawan.codes.oop;

public class Circle extends Polygon {
    
    @Override
    public void draw() {
        System.out.println("Drawing Circle");
        super.draw();
    }
}
                    

In Summary

If you cannot remember everything, just remember these summary of Java four access modifiers:

  • private - only code in the same class can access this member
  • public - any class in any package can access this member
  • protected - sub classes in any package can access this member (as well as code in the same class)
  • default - only code in the same package can access this member

And here the matrix in table mode from the most restrictive (private) to least restrictive (public):

classsame
package
subclass
(same package)
subclass
(different package)
other class
privateYNNNN
default
(no modifier)
YYYNN
protectedYYYYN
publicYYYYY