The "abstract" keyword - Abstract classes & Methods

Share on:

Overview

We'll look at abstract keyword and see why we need it.

Introduction

Consider the following class design: Vehicle design We can notice that we are using inheritance in this class design to avoid code duplicity. We also notice that we are overriding some methods in TwoWheeler class & FourWheeler class; we also override some methods in Bicycle, Scooter, Hatchback, SUV, Sedan classes respectively. We can create an object of say class Sedan like the following:

1Sedan sedan = new Sedan();
We can also change the type of our reference variable to any of the superclass of Sedan, making use of Subtyping polymorphism (read more here). So something like the following is also completely valid:
1/*
2Both of the following statements are completely valid 
3because FourWheeler & Vehicle are superclasses of Sedan class
4*/
5FourWheeler sedan = new Sedan();
6Vehicle sedan = new Sedan();
So far so good. But can we do the following:
1Vehicle vehicle = new Vehicle();
We surely can, there's nothing stopping us. But does it make sense? Is Vehicle a real world entity for which we'll like to create an object. Surely classes like Bicycle, Sedan, etc. are real world entities and should have objects. But we cannot argue the same about class Vehicle.
Let's look at another example of class design:
Shape design We can see that we have Triangle and Rectangle classes which extends a Shape class. These two subclasses override area() method to give their specific implementations. Triangle will define area() method so that it'll give area of a Triangle and Rectangle class will define area() so that it'll give area of a Rectangle. But what will the area() method of Shape class say, probably nothing: just an empty declaration. Will it make sense to create an object of Shape class?

Sometimes there are classes in our design that are only used to give an overall blueprint for it's subclasses. There's no "real world entity" for such classes and such classes should be avoided from getting instantiated i.e. we should not be able to create an object for such a class. Such classes are only useful when they are extended.

"abstract" class

We can use abstract keyword at class level and declare an abstract class.

Abstract Class cannot be instantiated. We cannot create objects of abstract classes and are only useful when extended.

As discussed above, there might be some classes in our design for which we want to disable instantiation. How to do it? Mark the class with "abstract" keyword. Let's see an example:

1abstract class A {
2
3    public void func() {
4
5        System.out.println("inside func()");
6    }
7}
1class Helper {
2
3    public static void main(String[] args) {
4        
5        //trying to instantiate class A
6        A a = new A();
7    }
8}
If we compile the above program we'll get the following error:
1Helper.java:6: error: A is abstract; cannot be instantiated
2        A a = new A();
3              ^
41 error
The compiler error clearly states that we are trying to create an object of an abstract class which is not allowed.

Abstract class v/s Concrete Class

Simply put, classes which are not abstract are called concrete classes. Concrete classes are the one for which having a real world object makes sense. In our examples above, it makes sense to have objects of class Triangle and Rectangle, hence these are concrete classes.
Note: As a general practice, leaf-classes in UML diagrams are made concrete. Non-leaf classes are made abstract. Though it's not a generalization.

"abstract" Methods

Like classes we can also mark methods with abstract keyword. How to create an abstract method? Here's a very simple example:

1abstract class A {
2
3    public abstract void func();
4}
We've created an abstract method func() by using "abstract" keyword.
Few Important points on abstract methods:

  1. If a class contains abstract method that class must also be marked abstract. For example:

    1//A contains an abstract method so we should mark A as abstract as well.
    2abstract class A {
    3
    4    public abstract void func();
    5}
    Something like this will cause compilation error:
    1//A is not abstract even though it contain a abstract method, should give error
    2class A {
    3
    4    public abstract void func();
    5}
    Error:
    1./A.java:1: error: A is not abstract and does not override abstract method func() in A
    2class A {
    3^
    41 error

  2. abstract methods have no body and must end with a semicolon (;). For example:

    1class A {
    2
    3    public abstract void func();    //ends with a semicolon
    4}

  3. An abstract class can have non-abstract methods as well.

     1abstract class A {
     2
     3    public abstract void func();
     4
     5    // a non-abstract method in abstract class
     6    public void foo() {
     7
     8        System.out.println("inside foo()");
     9    }
    10}

  4. Reverse is not true, abstract methods cannot be in non-abstract class (as already seen in point 1). If a class contains abstract methods, the class must be marked abstract as well.

  5. If a subclass extends a abstract class, the subclass should override all the abstract methods of the superclass.

    1abstract class A {
    2
    3    public abstract void func();
    4
    5    public void foo() {
    6
    7        System.out.println("inside foo()");
    8    }
    9}
    1class B extends A {
    2
    3    public void func() {
    4
    5        System.out.println("inside B's func()");
    6    }
    7}
    1class Helper {
    2
    3    public static void main(String[] args) {
    4        
    5        B b = new B();
    6        b.func();
    7        b.foo();
    8    }
    9}
    Output:
    1inside B's func()
    2inside foo()
    Class B overrides func() from class A and everything works fine. But if change class B to something like this:
    1class B extends A {
    2
    3}
    we'll get the following error:
    1./B.java:1: error: B is not abstract and does not override abstract method func() in A
    2class B extends A {
    3^
    41 error
    stating that we must override abstract methods of our superclass.

Need for abstract methods?

As with abstract classes we understood that they are the classes that have no significance in the real world and that they are just the blueprint for their subclasses.
Abstract methods are just the same. Abstract methods work like a "contract" for subclasses saying that each subclass should definitely override me. Consider the following design again: Shape design Triangle and Rectangle both override area() method. But what if in Rectangle class we forgot to override area()? To avoid such a thing and to be sure that every subclass of Shape must have it's own implementation of area() method, we can declare area() in Shape as a abstract method. By doing this compiler will ensure that each subclass of Shape will override area() method.

Let's think why

  1. Why do you think abstract methods cannot have a body?
  2. Why do you think classes with abstract methods should also be marked abstract? Write your answers in comments and let's see if you get these right

Takeaways

  • Use of abstract classes and abstract methods
  • abstract keyword

Acknowledgements

  • Head First Java (2nd Edition)
  • Java The Complete Reference (9th Edition)
comments powered by Disqus