in

Abstract Class vs Interface in Java: An In-Depth Guide with Examples

Abstraction is a fundamental concept in object-oriented programming that refers to hiding implementation details and exposing only essential functionality. Java provides two primary mechanisms to achieve abstraction – abstract classes and interfaces. While both are used to define generic behaviors for subclasses/implementing classes, there are some notable differences between abstract classes and interfaces in Java.

In this comprehensive guide, we‘ll explore abstract classes and interfaces in depth with examples, see how they are similar and different, understand when to use each, and illustrate their usage with real-world examples. Whether you‘re a beginner learning Java abstractions or an experienced developer looking to deepen your knowledge, this guide will help you master abstract classes and interfaces in Java.

Abstract Classes in Java

An abstract class in Java is a class that cannot be instantiated directly and may contain abstract methods. Abstract methods only have a method signature and no body. Abstract classes are used to provide common implementations for subclasses to reuse while allowing subclasses to have different implementations through abstract methods.

Let‘s dig deeper into abstract classes in Java:

Declaring Abstract Classes

To declare a class abstract in Java, you simply use the abstract keyword before the class keyword:

public abstract class AbstractClass {
  // abstract class code
}

This prevents direct instantiation with new AbstractClass(). The class must be extended.

Abstract and Concrete Methods

An abstract class can contain both abstract and concrete (regular) methods:

public abstract class AbstractClass {

  // Concrete method
  public void concreteMethod() {
    System.out.println("Concrete method"); 
  }  

  // Abstract method
  public abstract void abstractMethod();

}

The abstract methods must be implemented in subclasses, while concrete methods can be inherited as-is.

Inheriting from Abstract Classes

Any subclass of an abstract class must implement all of its abstract methods, either by overriding them or by being declared abstract itself.

For example:

public abstract class AbstractClass {

  public abstract void abstractMethod1();

  public abstract void abstractMethod2();

}

public class ConcreteClass extends AbstractClass {

  @Override
  public void abstractMethod1() {
    // implementation 
  }

  @Override
  public void abstractMethod2() {
    // implementation
  }

}

Here ConcreteClass overrides both abstract methods, so it‘s concrete. But if it didn‘t implement them, it would also need to be declared abstract.

Characteristics of Abstract Classes

These are some key characteristics and capabilities of abstract classes in Java:

  • Cannot be instantiated directly
  • Can have constructors, static methods and static variables
  • Allowed to have final, non-final, static and non-static members
  • Can have implemented methods to share common code
  • Can implement interfaces and have access modifiers on members
  • Faster execution than interfaces

In summary, abstract classes allow defining generic behaviors through abstract methods while providing member variables and implemented methods for reuse in subclasses.

Abstract Class Example

Let‘s look at an example abstract class representing a geometric shape:

public abstract class Shape {

  private String color;

  public Shape(String color) {
    this.color = color; 
  }

  public abstract double area();

  public abstract double perimeter();

  public String getColor() {
    return color;
  }

}

Shape defines the common color attribute and enforces the area() and perimeter() behaviors through abstract methods. Subclasses like Circle and Rectangle can extend Shape and implement these methods based on their specific shape while reusing the color attribute and getter.

This enables polymorphic code like:

Shape shape = new Circle("Red");
System.out.println(shape.area()); 

The Shape reference allows working with different kinds of shapes generically.

Interfaces in Java

An interface in Java provides full abstraction and specifies behaviors that implementing classes must define. It‘s like a completely abstract class with no concrete members. Interfaces are useful for:

  • Defining APIs and contracts
  • Decoupling implementations from usages
  • Allowing classes to support multiple interfaces
  • Future proofing by allowing new interfaces

Let‘s explore Java interfaces more:

Declaring Interfaces

Interfaces are declared using the interface keyword:

public interface InterfaceExample {

  void abstractMethod1();

  void abstractMethod2();

}

Implementing Interfaces

A class uses the implements keyword to implement an interface:

public class ImplementingClass implements InterfaceExample {

  @Override
  public void abstractMethod1() {
    // implementation
  }

  @Override
  public void abstractMethod2() {
    // implementation 
  }

}

All interface methods must be implemented concretely.

Characteristics of Interfaces

These are some key properties of interfaces in Java:

  • Cannot be instantiated directly, just like abstract classes
  • Can only contain abstract method declarations, no concrete methods
  • Methods are implicitly public in interfaces
  • Can have static and final variables
  • Allows multiple inheritance – a class can implement multiple interfaces

Interface Example

Let‘s look at an example Driveable car interface:

public interface Driveable {

  void start();

  void stop();

  void accelerate();

}

A car class can implement this interface:

public class Car implements Driveable {

  @Override
  public void start() {
    // start engine
  }

  @Override
  public void stop() {
    // stop engine
  }

  @Override
  public void accelerate() {
    // accelerate car
  }

}

This enforces that Car must implement the driving capabilities defined in Driveable. And we can rely on that contract in our code.

Similarities between Abstract Classes and Interfaces

While abstract classes and interfaces have many differences, there are two core similarities between them:

No Instantiation

Firstly, neither abstract classes nor interfaces can be instantiated directly. They must be extended and implemented by concrete subclasses respectively.

Polymorphism

Secondly, they both support polymorphism in Java. You can use an abstract class or interface reference to point to concrete subclass/implementing class objects at runtime:

AbstractClass obj = new ConcreteClass(); 

InterfaceExample obj = new ImplementingClass();

This allows abstract types to define generic behaviors leveraged via polymorphism.

Differences between Abstract Classes and Interfaces

While abstract classes and interfaces have some similarities, there are also notable differences between the two. Let‘s compare them:

Criterion Abstract Class Interface
Inheritance Single inheritance only Multiple inheritance allowed
Member Variables Can have state and non-static members Only static and final variables
Member Methods Can have implemented concrete methods Cannot have any method bodies
Access Modifiers Has access modifiers on methods Interface methods are public by default
Constructors Can define constructors Cannot define constructors
Execution Faster execution Slower execution

Let‘s examine some key differences:

Inheritance

A class can only inherit from one abstract class in Java while a class can implement multiple interfaces. Interfaces promote greater flexibility and allow behaviors from multiple sources.

Member Variables

Abstract classes can have member variables that maintain state across instances. Interfaces can only have static and final variables that act more like constants.

Member Methods

Abstract classes allow defining implemented concrete methods that subclasses inherit. Interfaces can only have abstract method signatures with no implementation code.

Access Modifiers

Access modifiers like public, protected can be applied on abstract class methods. Interface methods are always implicitly public.

Constructors

Constructors defined in an abstract class are inherited in subclasses. But interfaces cannot define constructors since they cannot be instantiated.

Execution Speed

Abstract classes have faster execution speed than interfaces in Java. This is because interfaces use dynamic dispatch to invoke methods at runtime.

So in summary, there are many design differences between abstract classes and interfaces that impact how they are used for abstraction in Java.

When to Use Abstract Classes vs Interfaces

When should you use an abstract class and when should you use an interface in Java? Here are some guidelines:

Consider an Abstract Class when:

  • You need to share implementation between subclasses
  • You want to define reusable member variables and methods
  • You need to maintain state across the class hierarchy
  • You want to declare non-public members
  • You need to define constructors, static methods etc.

For example, abstract classes are commonly used to provide skeletal implementations for collections like AbstractList, AbstractSet, AbstractMap etc.

Consider an Interface when:

  • You expect unrelated classes to implement your interface
  • You want to define a functionality contract but don‘t care about implementation details
  • Your classes need to implement multiple interfaces
  • You want loose coupling between classes
  • You need to allow adding new interfaces in the future

For example, Java interfaces like Runnable, Serializable, Comparable define contracts without knowing about concrete classes.

Real-World Example

Let‘s look at a real-world example of choosing between an abstract class and interface from the Java Collections Framework:

List is defined as an interface while AbstractList provides a skeletal implementation as an abstract class:

public interface List<E> {
  // List methods  
}

public abstract class AbstractList<E> implements List<E> {
  // Implement common List methods
}

public class ArrayList<E> extends AbstractList<E> {
  // ArrayList implementation
}

This allows ArrayList to inherit common List functionality from AbstractList while also being able to implement other interfaces like Serializable.

Conclusion

We‘ve explored abstract classes and interfaces in depth and seen how they achieve abstraction in Java through commonalities and differences:

  • Use abstract classes to define reusable code templates for subclasses
  • Use interfaces to define contracts for unrelated classes to implement
  • Understand their inheritance, methods, variables, and performance trade-offs
  • Choose between them based on requirements like code reuse vs flexibility

Mastering abstraction with abstract classes and interfaces is critical for effective Java programming. Use this guide to make the right decisions in your designs and better leverage abstraction in your code.

I hope you found this guide helpful! Let me know if you have any other questions.

AlexisKestler

Written by Alexis Kestler

A female web designer and programmer - Now is a 36-year IT professional with over 15 years of experience living in NorCal. I enjoy keeping my feet wet in the world of technology through reading, working, and researching topics that pique my interest.