Java Interface v/s Abstract Class (Theoretical and Code-wise)

Introduction

In the previous two lectures, we have discussed two ways of achieving abstraction i.e Abstract class and Interfaces. This lecture is all about comparing both the approaches and understanding the significance of each.

Abstract class v/s Interface

Let us look into a few aspects where the difference actually lies.

  • Inheritance

    • The abstract class does not support multiple inheritances, whereas the interface supports multiple inheritances.
  • Methods

    • An abstract class can have both abstract and non-abstract methods, whereas the interface contains abstract methods. Interface after Java 8 can also have default and static methods.
  • Implementation

    • An abstract class may contain the implementation of an Interface, but vice versa is not possible.
  • Variable type

    • The variable type is can be final, non-final, static, and non-static in the case of an abstract class, but in the case of interface, it is only static and final.
  • Access Specifiers

    • The members of an abstract class can be public, private, protected, and default, but in case of an interface is public by default.
  • Abstraction level

    • The abstraction level can be partial in the case of an abstract class, but it is always 100 percent in the case of an interface.
  • Keywords

    • We use extends for abstract class, and implements for an interface.
  • Constructor

    • An abstract class can have a constructor, whereas an interface does not have a constructor.

Scenarios and what to opt

We can opt for any one of them, but several situations make it important to use a certain type. Let us look into a few and understand.

Scenario Opt for
The requirement of full abstraction Interface
Need non-static and non-final data member Abstract class
Need variation in access specifiers Abstract class
Need multiple inheritances Interface
Commonalities exist in child classes Abstract class

Let us now dive into situations and use both as per situation and understand.

Abstract Class

We would prefer an abstract class where we want to have non-static data members, customized access specifiers, and commonalities among the class that will extend it.

abstract class MyAbstractClass{
    //Need non-static non-final variables
    int myInt1;
    int myInt2;

    //Need Constructor
    MyAbstractClass(){
        this.myInt1=12;
        this.myInt2=15;
    }

     //Commonalities
    void commonMethod(){
        System.out.println("I am common among all extenders");
    }
    abstract void myAbstractMethod();
}



class Child1 extends MyAbstractClass{
    void myAbstractMethod(){
        System.out.println("I am implemented by Child1");
    }
}

class Child2 extends MyAbstractClass{
    void myAbstractMethod(){
        System.out.println("I am implemented by Child2");
    }
}

public class ClassMain{
  public static void main(String args[]){
    Child1 obj1 = new Child1();
    Child2 obj2 = new Child2();

    System.out.println("Child1 Object details");
    obj1.commonMethod();
    obj1.myAbstractMethod();

    System.out.println("\nChild2 Object details");
    obj2.commonMethod();
    obj2.myAbstractMethod();
} 
}

Output:

Child1 Object details
I am common among all extenders
I am implemented by Child1

Child2 Object details
I am common among all extenders
I am implemented by Child2

Interface

There are situations where there exist no commonalities between the implementers and each implementor has its own strategy regarding implementation, we opt for an interface.

interface MyInterface{
void myAbstractMethod();
}

class Child1 implements MyInterface{
    public void myAbstractMethod(){
        System.out.println("I am implemented by Child1");
    }
}

class Child2 implements MyInterface{
    public void myAbstractMethod(){
        System.out.println("I am implemented by Child2");
    }
}

public class ClassMain{
  public static void main(String args[]){
    Child1 obj1 = new Child1();
    Child2 obj2 = new Child2();

    System.out.println("Child1 Object details");
    obj1.myAbstractMethod();
    System.out.println("\nChild2 Object details");
    obj2.myAbstractMethod();
} 
}

Output:

Child1 Object details
I am implemented by Child1

Child2 Object details
I am implemented by Child2

This was a brief comparison between the two approaches of abstraction. It is expected to understand and opt for the approach depending upon the situation. We will discuss Java Packages in the next lecture.