Abstract Class: An Idea to Implement Abstraction in Java

In Java, abstract classes and interfaces are used to implement abstraction. Abstract classes are similar to regular classes, but they are declared using the abstract keyword and cannot be instantiated. On the other hand, interfaces do not have any implementation code and only contain method declarations.

What is abstract class in Java?

In Java, it is common to use abstract classes as a base for other classes. For example, suppose you are creating a program that includes various animals. In that case, you might start by creating an abstract class called Animal that contains common attributes such as sound and colour and common behaviours such as running and eating. All the specific animal classes, such as Lion, Dog, and Rabbit, would then extend the Animal class and override any necessary methods.

It's important to note that abstract classes cannot be instantiated on their own, so you would not be able to create an instance of the Animal class directly. Instead, you would create an instance of one of the specific animal classes that extends the Animal class.

class Animal {
    public int legCount;
    public String name;

    // constructor to initialize instance variables
    public Animal() {
        // Implementation code
    }

    // methods
    public String run() {
        // Implementation code
    }

    public String makeSound() { 
        // Implementation code
    }
}

class Lion extends Animal {
    // body of class including overriding methods of Animal
}

class Dog extends Animal {
    // body of class including overriding methods of Animal
}

Now we can instantiate animal classes by either using a reference variable of Animal type or their own. Consider the following example:

Lion lionObject = new Lion();
//lionObject is a type of Lion

//or we can use Animal type reference which will make the program more poylmorphic.
Animal lionObject = new Lion();
//lionObject is a type of Animal because it inherits Animal class.

These instantiations make sense. But what if we instantiate Animal class:

Animal animalObject = new Animal();

Here Animal class does not provide specific implementations for its methods, such as sound(). Therefore, it does not make sense to create an instance of the Animal class because it does not have meaningful values for its instance variables or functional implementations for its methods. Abstract classes are meant to be used as a blueprint for other classes rather than instantiated independently.

Abstract Methods in Java

An abstract method is a method that is declared in an abstract class and does not have an implementation. It is declared using the abstract keyword and does not include a method body or curly braces.

  • Abstract methods are used when a superclass wants to define a method that its subclasses will implement. In other words, It is the responsibility of the subclass to provide an implementation for the abstract method by overriding it.
  • A class containing one or more abstract methods must also be declared abstract. On the other hand, an abstract class may or may not contain abstract methods.
abstract class Animal {
    public abstract void makeSound();
}

class Lion extends Animal {
    @Override
    public void makeSound() {
        System.out.println("Roar!");
    }
}

In this example, the Animal class is an abstract class that contains an abstract method called makeSound(). The Lion class extends the Animal class and provides an implementation for the makeSound() method by overriding it.

Defining Abstract class

The body of an abstract class can contain any type of method or variable that a regular class can, including static and final methods, constructors, and even the main() method. An abstract class may or may not contain abstract methods, which are methods that are declared but do not have an implementation.

abstract class Animal {
    public int legCount;
    public String name;

    // constructor
    public Animal(int legCount, String name) {
        this.legCount = legCount;
        this.name = name;
    }

    // abstract method
    public abstract void makeSound();

    // regular method
    public void run() {
        System.out.println("Running!");
    }
}

In this example, the Animal class is an abstract class that has an instance variable called legCount and a method called makeSound() that is declared as abstract. It also has a regular method called run() that has an implementation.

Extending the Abstract class

To create concrete classes that represent actual animals, such as lions and dogs, you can extend the abstract Animal class and provide implementations for the abstract methods. To extend an abstract class, you use the extends clause and specify the name of the abstract class.

class Lion extends Animal {
    public Lion(int legCount, String name) {
        super(legCount, name);
    }

    @Override
    public void makeSound() {
        System.out.println("Roar!");
    }
}

class Dog extends Animal {
    public Dog(int legCount, String name) {
        super(legCount, name);
    }

    @Override
    public void makeSound() {
        System.out.println("Bark!");
    }
}

In this example, the Lion and Dog classes are concrete classes that extend the Animal class. They provide implementations for the abstract makeSound() method by using the @Override annotation and specifying the desired behavior. The Lion class prints "Roar!" when the makeSound() method is called, and the Dog class prints "Bark!".

Overriding methods in concrete class

If a class extends an abstract class and does not override all of its abstract methods, it is also considered an abstract class. This means that in order to use the Lion and Dog classes as concrete classes, you must override all of the abstract methods in the Animal class.

It is important to note that you can also override non-abstract, non-static, and non-final methods in an abstract class. This can be useful if you want to change the behavior of a method that is inherited from the abstract class.

abstract class Animal {
    public int legCount;
    public String name;

    // constructor
    public Animal(int legCount, String name) {
        this.legCount = legCount;
        this.name = name;
    }

    // abstract method
    public abstract void makeSound();

    // regular method
    public void run() {
        System.out.println("Running!");
    }
}

class Lion extends Animal {
    public Lion(int legCount, String name) {
        super(legCount, name);
    }

    @Override
    public void makeSound() {
        System.out.println("Roar!");
    }

    @Override
    public void run() {
        System.out.println("Lions are fast runners!");
    }
}

In this example, the Lion class extends the Animal class and overrides both the abstract makeSound() method and the non-abstract run() method. The run() method in the Lion class has a different implementation than the one in the Animal class. Note: We are calling parent class constructor from the base class constructor by using the super keyword. This involve the idea of constructor chaining.

You can then create an instance of the Lion class and call its methods as follows:

Lion lion = new Lion(4, "Lion");
lion.makeSound(); // prints "Roar!"
lion.run(); // prints "Lions are fast runners!"

Key points to remember

  • An abstract class can not be instantiated.
  • An abstract class may or may have abstract methods and it can have constructors.
  • An abstract class can have final and static methods, but an abstract method cannot be declared final or static.
  • If a class contains one or more abstract methods, it must be declared as abstract. A child class does not need to implement all abstract methods (although it can).
  • An abstract class can be extended by another abstract class. This implies, that the child's abstract class does not need to implement all the abstract methods (although it can).
  • Suppose a child class cannot provide an implementation for all of the abstract methods in its parent class. In that case, it should be declared abstract so that the next level of child classes can implement the remaining abstract methods.

Examples of Abstract Classes in JDK

  • AbstractMap : Provides a skeletal implementation of Map interface.
  • AbstractSet : Provides a skeletal implementation of the Set interface. 
  • AbstractCollection : Provides a skeletal implementation of Collection interface.

Enjoy learning, Enjoy OOPS!

Share feedback with us

More blogs to explore

Our weekly newsletter

Subscribe to get weekly content on data structure and algorithms, machine learning, system design and oops.

© 2022 Code Algorithms Pvt. Ltd.

All rights reserved.