Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

How to Choose Between Interface and Abstract Classes in Java

DZone's Guide to

How to Choose Between Interface and Abstract Classes in Java

Get the answer to this frequently-asked core Java interview question.

· Java Zone ·
Free Resource

The CMS developers love. Open Source, API-first and Enterprise-grade. Try BloomReach CMS for free.

In Java, we have interfaces and abstract classes. When it comes to choosing which one, we give arguments like choosing interfaces that support multiple inheritances or choosing an abstract class that provides the implementation of a few methods in your parent class (though from Java 8 onward, we can give default method implementation in interface also). Visit when-to-use-abstract-class-and-interface for more details.

This is a famous and basic interview question related to core Java, and the explanation above holds true.

Why Do We Need a 100 Percent Abstract Class?

Now, this question is really important, because based on the above explanations, a 100 percent abstract class is not at all useful, because it doesn't provide a default implementation of methods nor does it support multiple inheritances.

So can we say that we should never create a 100% abstract class, or we are missing something here?

Let’s dive deeper to understand this better. We will take the example of creating a car and decide which interfaces and abstract classes are required.

What Is an Abstract Class?

Abstract means that something is not fully concrete — it’s merely an idea or gist of something. So when we talk about abstract classes, it means a class that does not have a concrete implementation in itself. This is just a structure or guideline created for other concrete classes. We can say that an abstract class is the soul of a concrete class. This is the reason we “extend” abstract classes. An abstract class should only have those properties and methods, without which a concrete class can't exist.

This is the reason Java does not support multiple inheritances for abstract classes. Because one concrete class can behave (or take all properties) of only one abstract class (and obviously, a body can’t have two souls).

For example, Man and Car have many common behaviors, like movement, creating sound, etc., but a Car class can only behave like a Vehicle, not as a human, and the Man class can only behave like a human, not a vehicle.

I agree that the above example is lame, but even in real life scenarios, if you are not sure which abstract class you should inherit or you think there is a need to inherit more than one abstract class, then this is a design smell, and you should revisit the design of your project.

Based on what we have discussed above, we need to create a Vehicle abstract class. This abstract class will have properties like Engine, Shape, etc. of Car and related methods. We added  Engine and Shape in the abstract class because no vehicle can exist without these two.

abstract class Vehicle {
  private String engine;
  abstract void startEngine();
  abstract void stopEngine();
}


What Is an Interface?

An interface is a behavioral contract between different systems. In Java interfaces, we define the behavior of a class, which will implement this interface. One class can have a number of different behaviors, that is why Java allows us to “implement” N number of interfaces. Interfaces are meant to provide only behaviors. This is why the Java naming convention suggests using adjectives as the name of an interface.

For example, a car can move, so we can create a movable interface and implement it in our Carclass. It is the same for drift and honk behavior. These are the behaviors of the Carmethod, not inbuilt properties. A Car will be car, even if it is not able to move.

interface Movable { 
  void move();
}


The sad thing is that we are habitual of using interfaces at the level where we nearly forget the power of abstract classes, their use, and the intention behind creating them.

Dummy Java Code Related to Car Class Creation

class Car extends Vehicle implements Movable {

  @Override
  void startEngine() {
    System.out.println("starting car's engine");
  }

  @Override
  void stopEngine() {
    System.out.println("stoping car's engine");
  }

  @Override
  public void move() {
    System.out.println("moving car");
  }
}


Summary

Key takeaways related to abstract class creation:

  • Create an abstract class when you are providing guidelines for a concrete class.
  • Abstract class creation is not at all related to whether you want to provide the implementation of any method or not.
  • Add only those properties and behaviors to the abstract class, without which your concrete class will lose its existence. For example, the Vehicle cannot exist without an engine.

Key takeaways related to interface creation:

  • Create interfaces that provide additional behavior to your concrete class. When we share these interfaces to the external system, then it becomes a contract, that is why we say that interfaces are behavioral contracts of the concrete class.
  • These behaviors should not be mandatory for your class. These behaviors should add more capabilities to your class. For example, a Car will be a Car, even if it cannot move.
  • Ask the question that, whenever a concrete class will implement your interface, will it require all behaviors mentioned in your interface, or only a few? Refactor your interfaces in multiple interfaces, until the answer to the above question is yes.

Thanks for reading!

BloomReach CMS: the API-first CMS of the future. Open-source & enterprise-grade. - As a Java developer, you will feel at home using Maven builds and your favorite IDE (e.g. Eclipse or IntelliJ) and continuous integration server (e.g. Jenkins). Manage your Java objects using Spring Framework, write your templates in JSP or Freemarker. Try for free.

Topics:
java ,interface ,abstract class ,interface classes ,interview question ,concrete class

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}