Abstraction in Java helps minimize complexity. It involves hiding unnecessary details and only exposing the functionalities intended for user interaction. In other words, data abstraction is the process of reducing Java objects to their essence so that only they reveal characteristics necessary to the users.

For instance, when sending an email, you’re only required to input the receiver’s email address, the subject, and the body. On the user’s side, the application exposes what you need to use to accomplish the task. However, other implementations occur behind the scenes, such as connecting to the server, formatting the email, and encrypting it, among other tasks. These processes are hidden from a user by using abstraction.

This article defines abstraction in the context of Java, how abstraction works in Java and works through an example of how to use abstraction.

Download Now: An Introduction to Java & JavaScript

How Does Abstraction Work?

Before exploring abstraction in Java, let’s discuss how data abstraction works. In Java, you can have abstract classes and abstract methods.

Abstract Classes

Because Java is an object-oriented programming (OOP) language, abstraction is essential in Java. OOP focuses on creating objects that contain data and methods. Each object belongs to a class, meaning each object in Java belongs to a class.

For example, you could work with a class called fruit, and a banana could be an object within that class. In Java, objects are defined by their behavior (methods), interfaces (how they communicate with other objects), and properties (attributes).

You identify an abstract class with the keyword abstract in a class definition, as shown in the code snippet below:

 
abstract class Name {
/*the body of the class*/
}

In Java, abstract classes allow for partial to complete abstraction. Partial abstraction is achieved by having implementations with concrete methods. Full abstraction is achieved using interfaces with abstract types that specify a class’ behavior.

Here are some important rules to keep in mind while working with abstract classes:

  • They can contain abstract methods (methods without a body).
  • A class with an abstract method must be declared an abstract class.
  • A class declared as abstract cannot be instantiated.
  • A class can’t contain static or final methods in its body.
  • A class that inherits an abstract class must also implement all its abstract methods.

Abstract Method

Abstract methods are methods without a body or an actual implementation. They are used when you want to add a method to a class and leave the determination of its implementation to child classes.

You declare an abstract method by using the abstract keyword. It follows the signature of a method but doesn’t contain a body. Instead of adding curly braces at the end, you add a semicolon:

 
/*abstract class*/
public abstract class ParentClass{
    /*abstract method*/
    public abstract double MethodA();
}

Only abstract classes can contain abstract methods. A class that inherits an abstract class has to implement all its abstract methods. For instance, if a class inherited the abstract class in the example above, it would look like this:

 
/*inheriting the abstract class*/
public class ChildClass extends ParentClass {
    /*implementing the abstract method from the abstract class*/
    public double MethodA() {
    }
}

Data Abstraction and Control Abstraction

There are two types of abstractions in Java: data abstraction and control abstraction.

Data abstraction enables you to create complex data types, such as HashMap or HashSet, and hide how they get implemented from your users. The furthest you'd go with HashMaps and HashSets is knowing how to structure your data using them.

Control abstraction is the process of consolidating all statements that are similar and repeatedly used into a single unit. This abstraction is used to create functions to perform a defined task.

Data Abstraction Versus Data Encapsulation

Data encapsulation is a Java mechanism for combining data/variables with the method that acts on this data. It involves restricting access to the information within a class from outside of that class. In Java, encapsulated data is marked using the term private in the class definition and is exposed using a get or set method.

Data encapsulation and data abstraction are both fundamental concepts of OOP. They’re similar in that they hide essential components from other code users to improve security. They both allow limited access to their respective components without revealing the underlying details.

The difference between the two is that data encapsulation focuses on hiding the data while data abstraction focuses on obscuring the implementation process.

Why Use Data Abstraction?

In application development, abstraction provides several benefits:

  • It effectively simplifies complex processes that a user interacts with.
  • The loose coupling that abstraction promotes eases the debugging burden because the implementation and the functionalities are separated.
  • Abstraction helps in creating efficient code by allowing for code reuse.
  • Abstraction increases security by hiding core implementation details.

Example of Abstraction in Java

To see how abstraction works, take a look at the following example. Let’s say you’re working for a car rental business and want to send an invoice to clients. You also want the application to compute the total amount the client owes.

To prepare this invoice, you start by creating an abstract class:

 
    public abstract class Car {
    private String name;
    private String regNumber;
    private int number;
    public Car(String regNumber, String name) {
        this.name = name;
        this.regNumber = regNumber;
    }
    public void mailInvoice() {
        System.out.println("Mailing an invoice for: " + this.name + " Registration: " + this.regNumber);
    }
    public String toString() {
        return name + " " + regNumber;
    }
    public String getName() {
        return name;
    }
    public String getRegNumber() {
        return regNumber;
    }
    /*Creating an abstract method to be implemented by child classes*/
    public abstract void computeCost();
}

Then, you need to inherit the abstract class. You do so by creating a concrete class and adding the term extend after the class name, followed by the abstract class you’re inheriting:

 
public class RentalCost extends Car {
     /* cost of the vehicle per hour*/
     private double costPerHour;
     private double hours; /* number of hours spent with the vehicle*/
     private double cost;/* Total amount due*/
     public RentalCost(String regNumber, String name, double                   costPerHour, double hours) {
          super(regNumber, name);
          setCost(costPerHour, hours);
    }
    public void mailInvoice() {
        System.out.println("Mailing invoice for " + getName() + " with amount due as " + cost);
     }
     public double getCostPerHour() {
         return costPerHour;
    }
    public double getHours() {
        return hours;
    }
    public void setCost(double newCost, double newHours) {
        if(newCost >= 0.0 && newHours>=0.0) {
            costPerHour = newCost;
            hours = newHours;
            cost = costPerHour * hours;
        }
    }
/*Implementing the abstract method from the inherited abstract Car class*/
    public void computeCost() {
        System.out.println("Total cost for:" + getName() + " is " + cost);
    }
}

Note that you can’t instantiate the Car class. However, you can instantiate the Cost class and access all methods inside the Car class, as shown in the code below:

 
public class Invoice {
    public static void main(String [] args) {
        RentalCost a = new RentalCost("11DA", "Honda CRV", 50.00, 4.5);
        System.out.println("mailInvoice() called using Cost as reference");
a.mailInvoice();
        System.out.println("\n\nCalling method computeCost() from abstract 'Car class' that's implemented in concrete 'Cost class'");
        a.computeCost();
    }
}

The output you get after running this application is as follows:

 
mailInvoice() called using Cost as reference
Mailing invoice for Honda CRV with amount due as 225.0
Calling method computeCost() from abstract 'Car class' that's implemented in concrete 'Cost class'
Total cost for:Honda CRV is 225.0

Abstraction Example: Abstract Class Versus Interface

Abstraction in Java is achieved using either an abstract class or an interface.

An interface in Java represents the blueprint of a class and contains abstract methods and static constants. Interfaces are similar to abstract classes in that neither can be instantiated and can handle at least one method declared without any implementations.

Unlike an interface that can only specify the methods, a class must implement, an abstract class may contain data and concrete methods. Additionally, with an interface, it’s possible to restrict the number of abstract methods to be declared. This isn’t possible with an abstract class.

This example used an abstract class because the abstractions needs could be achieved with single inheritance. Additionally, this example used class abstraction to hide how the cost computation and invoice processing happens. Therefore, the user is only exposed to what is required for an invoice to be generated.

Getting Started Using Java Abstraction

Abstraction in Java is very effective in helping you limit what you share with your users, and you can choose the level of abstraction that you want to deploy in an application. You can use concrete methods in abstract classes to get partial abstraction and interfaces to achieve complete abstraction.

Abstract methods are essential when you leave the task of determining the implementation to a child class.

As an OOP language, Java benefits from data abstraction. In addition to providing your users with only the information they need, it helps reduce the complexity and effort required for programming applications.

java

 javascript

Originally published Aug 1, 2022 7:00:00 AM, updated August 01 2022