Using Final and Abstract in Java


Reading time: 30 minutes | Coding time: 10 minutes

In this article, the usage of the modifiers final and abstract will be discussed. In the context of Java Inheritance final and abstract are two important modifiers on deciding whether a class can take part in an inheritance relationship or not.

Final Classes and Final Methods

You can declare a class as final by adding the modifier final in the class header. If you declare a class as final, then that class cannot be subclassed. Make a class final only if you don't want that class to be subclassed. For example, see the below defined final class.

class final FinalClass{
    //code
}

Here FinalClass is not allowed to be subclassed.

When your requirement is to impose a restriction on reimplementation of class behaviors you can make that class as final. Then there would be one and only one implementation available to the behaviors of that class in the entire program. For example, standard Java library classes like String and all primitive wrapper classes are final. Since these classes are final we are not permitted to subclass them and give new implementations to any of the existing methods. You can think of a final class as a complete class that does not support creating an extended version of it.

You can make methods also final by adding final modifier to the method header. A final method is a method that is not allowed to be overridden in subclasses. You know that a final class cannot be subclassed and there is no point in having a final method in your final class. But when you have a nonfinal class and you need to restrict some of the methods from reimplementation you can make them as final methods. Take look at the below sample program.

class Test{
        public final void method1(){
            \\implementation
        }
        ...
}

Here class Test can be subclassed, but the method1() cannot be overrridden in the subclasses.

Final Class - Prevents inheritance
Final Method - Prevents method overriding

Abstract Class and Abstract Methods

Like the final class, we can declare a class as abstract by adding the modifier abstract to the class header. Unlike final class, abstract class can be subclassed, but cannot be instantiated. Let’s see when we need to make a class as an abstract class.

On watching an inheritance hierarchy you may notice that top-level classes are more general and abstract. Suppose we have a superclass Person and child classes Tutor and Student. We can put general attributes and behaviors inside the superclass and, attributes and behaviors specific to child classes we may put inside child classes.

class Person{
    String firstName;
    String LastName;
    int age;
    public void printPersonInfo(){
        System.out.println("name : "+ firstName+" "+lastName);
        System.out.println("age :" + age);
    }
}

class Tutor extends Person{
        public Tutor(String firstName, String lastName, int age){
            this.firstName = firstName;
            this.lastName = lastName;
            this.age = age;
        }
        
        public void printPersonInfo(){
        System.out.println("Tutor");
        System.out.println("name : "+ firstName+" "+lastName);
        System.out.println("age :" + age);
        }
}

class Student extends Person{

    public Student(String firstName, String lastName, int age){
            this.firstName = firstName;
            this.lastName = lastName;
            this.age = age;
    }
    public void printPersonInfo(){
        System.out.println("Student");
        System.out.println("name : "+ firstName+" "+lastName);
        System.out.println("age :" + age);
        }
}

Here you can see that Person class has got a method to print the Person info and the same method has been reimplemented in the subclasses with their own versions. We can consider the Person class as an abstract representation of Tutor and Student, and we can just put common behaviors inside the Person class. We may avoid the general implementation of a method inside the superclass if subclasses need their own reimplementation to the same method. This requirement can be achieved by making the general method as an abstract method by adding identifier abstract in the method header and by removing the method body.
Here in our example we can modify the printPersonInfo() method of Person class to an abstract method.

public abstract void printPersonInfo();

You can see that we have removed the implementation of the abstract method.

If a class contains an abstract method inside it, then the class must also be abstract.

Let’s modify the above Person class to an abstract class by adding the identifier abstract in the class header.

abstract class Person{
    String firstName;
    String LastName;
    int age;
    public abstract void printPersonInfo();
}

Now the class Person is an abstract class with an abstract method inside it. But it’s not mandatory to put an abstract method in an abstract class. An abstract class can have both abstract as well as concrete methods inside it. But as mentioned earlier, if there is an abstract method inside a class, then that class must be an abstract class.

As the final class, an abstract class is not a complete class; it can be subclassed. It is the top-level class in the inheritance heirarchy and just gives an abstract picture of the heirarchy, hiding the further implementation details of subclasses from the outside world. Abstract class is a template class for the subclasses. We may not be needing an object of the abstract class, since the detailed and more specific implementaion exists inside subclasses. That being said, abstract classes are restricted from being instantiated. We cannot create an object of an abstrct class.

By putting the abstract method inside an abstracat class, it is forcing the subclasses to reimplement the abstract method inside them, which means a subclass must give reimplementation to the superclass abstract methods.
If a the subclass does not give any implementation to abstract methods, then child class must also be declared as abstract. For example in our example, if the Tutor class does not give reimplementation to the printPersonInfo() method, then the Tutor class must be declared as abstract.

An abstract class is not useful unless it is subclassed. We can make references of abstract class type and, using that reference we can refer to subclass objects. For example, we can create a Person class reference to refer to Tutor and Student class object.

Person student = new Student("Eric","Jones", 20);
student.printPersonInfo();

Here we have created a Person class reference and assigned the newly created Student object to it.

Abstract class - Supports inheritance and cannot be instantiated.
Abstract method - Forces method overriding

Points to remember

  • A final class is a complete class which cannot be subclassed and, no restriction on creating objects of final class.
  • Abstract class is a noncomplete class which can be subclassed but cannot be instantiated.
  • Any classes can have a final methods, but cannot be overriden in subclasses.
  • Only abstract classes can have abstract methods, which must be overridden in subclasses.