Skip to content

Classes and abstract methods

Definitions

An abstract class is a definition of a class that we cannot instantiate (like interface). To declare such a class, we should use the abstract keyword between the access modifier and the class name. Contrary to regular classes, an abstract class can additionally have abstract methods .

Abstract methods are methods that:

  • cannot have a body in an abstract class definition
  • body must be implemented in the class that inherits from such an abstract class
  • can be declared only in abstract classes and interfaces
  • require the use of the abstract keyword before the type returned in its [signature] (../javaBasics/ methods.md)

The following example shows the definition of an abstract class:

public abstract class Button { // class defined as abstract

    public String getComponentName() { // standart, non-abstract method
        return "Button";
    }

    public abstract void onClick(); // abstract method, does NOT have a body
}

NOTE: Abstract methods cannot be declared private.

Create an instance

Attempting to create an instance of the class defined above ends with a compilation error:

public static void main(String[] args) {
  Button button = new Button(); // ERROR
}

To create an instance of such a class, we must first extend it, e.g.

public class SimpleButton extends Button { // we inherit an abstract class like any other class

  @Override                                // We MUST implement ALL abstract methods
  void onClick() {
    System.out.println("Simple Button was clicked");
  }
}

Having already implemented such a class, we are able to create an instance of it, e.g .:

Button button = new SimpleButton();

Comparison with interfaces

Unlike interfaces, we can declare fields in abstract classes. Moreover, the methods defined in this class do not have any default keywords.

If we want to share some code among many related classes, then it is worth considering using an abstract class. If we just want to extract some abstraction that can be used for many unrelated classes, then we should use the interface.

An abstract class can implement interfaces without declaring the bodies of their methods. It does not change the fact that when creating a derived class, you should give the body to all abstract methods, regardless of whether they belong to an interface or an abstract class.

public interface ComponentClickListener {

    void onClick();
}
public abstract class AbstractButton implements ComponentClickListener {
    public static final String TAG = "Button";

    String componentName;

    String getComponentName() {
        return componentName;
    }

    abstract void click();
}

Sample class implementation extending the AbstractButton abstract class:

public class ButtonComponent extends AbstractButton {
  @Override 
  void click() { // required implementation -> abstract method abstract
    System.out.println("I just clicked a button! Amazing");
  }

  @Override
  public void onClick() { // required implementation -> abstract method of Component Click Listener interface
    System.out.println("I am an onClick handler");
  }
}

In addition, abstract classes can inherit other abstract classes. By defining an abstract class, which inherits from an abstract class, we may but we don't have to implement inherited abstract methods. The following example shows such a definition:

public abstract class TestTemplate {
  abstract public void run();
  protected abstract int getNumberOfIterations();
}

public abstract class PerformanceTestTemplate extends TestTemplate { // abstract class inheriting from abstract class
  @Override
  public void run() { // optionally, we decide to define an abstract method
    System.out.println("I should run test here");
  }
  // we do NOT implement getNumberOfIterations in this class (but we can do it)

  public abstract double getAverageExecutionTime();
}

public class SortListPerformanceTest extends PerformanceTestTemplate { // definition of a non-abstract class

  @Override // required - an abstract method with no implementation in the inheritance hierarchy
  public double getAverageExecutionTime() {
    // calculate value based on real scenario
    return 5.0;
  }

  @Override // required - an abstract method with no implementation in the inheritance hierarchy
  protected int getNumberOfIterations() {
    return 3;
  }
}