Unit 6: Abstract Classes

Table of Contents

  1. Abstract Classes
  2. Abstract Methods
    1. Abstract vs Concrete
  3. Applications in FTC
  4. Notes on Abstract Classes

Abstract Classes

So far we have learned about regular classes. Abstract classes are even more generalized versions of classes that allow for greater flexibility when designing classes.

An abstract class is declared as follows, using the abstract keyword:

modifier(s) abstract class ClassName {
    // class body here
}

For example, I could declare an abstract GeometricObject like so (fields and methods are omitted for brevity):

public abstract class GeometricObject {
    ...
}

Note: On a UML diagram, abstract class names are italicized.

Abstract Methods

The cool thing about abstract classes is that they can have abstract methods. Abstract methods simply include the method signature and do not have a method body (no implementation). Thus, rather than having curly braces, you simply end the abstract method declaration with a semicolon, like so:

modifier(s) abstract returnType methodName(parameterType parameterName, ...)

For example, since all GeometricObjects have an area and perimeter, I can define the getArea and getPerimeter methods as abstract in the GeometricObject class. This makes sense because superclasses are supposed to include common fields and methods for all of its subclasses.

It also helps us avoid the need to cast objects to their subclasses when calling methods on elements in a superclass array (see Polymorphism). Additionally, it gives us flexibility to customize how the method is implemented in subclasses. This is because you don’t have one definitive formula to calculate the area or perimeter for all GeometricObjects. However, once we get to a more specific subclass, like Circle or Rectangle, we do have area and perimeter formulas.

Some fields and methods are omitted for brevity.

public abstract class GeometricObject {
    ...

    public abstract double getArea();

    public abstract double getPerimeter();
}

So how exactly do we implement the getArea method? We need to override it in a subclass of the abstract class. For example, let’s override the getArea method in the Circle and Rectangle classes. (Some fields and methods are omitted for brevity.)

Circle

public class Circle extends GeometricObject {
    private double radius;

    ...

    public double getDiameter() {
        return 2 * radius;
    }

    @Override
    public double getArea() {
        return Math.PI * radius * radius;
    }

    @Override
    public double getPerimeter() {
        return Math.PI * getDiameter();
    }

    ...
}

Rectangle

public class Rectangle extends GeometricObject {
    private double length;
    private double width;

    ...

    @Override
    public double getArea() {
        return length * width;
    }

    @Override
    public double getPerimeter() {
        return 2 * (length + width);
    }

    ...
}

Note: On a UML diagram, abstract methods are italicized.

Abstract vs Concrete

Since abstract classes are abstract, you cannot create an instance of an abstract class. (This is because abstract classes may contain abstract methods, which do not have an implementation yet.) You can, however, create an instance of a concrete class which extends an abstract class. That object is considered both an instance of the concrete class and the abstract class (see Polymorphism). To put it in simple terms, you can’t create an instance of an abstract class using new, but you can use it as a data type.

Applications in FTC

In the FTC SDK, there are some abstract classes that you will use often, such as OpMode and LinearOpMode. When you create your own opmodes to control your robot during auto or teleop, you extend one of those abstract classes. This forces you to implement methods like init(), loop(), or runOpMode(), which are executed in varying stages of the game.

See Unit 8 for more on the FTC SDK.

You can view OpMode and LinearOpMode documentation here and here, respectively.

Notes on Abstract Classes

This section is an excerpt from Ch. 13.2.2 Interesting Points about Abstract Classes in Introduction to Java Programming (Comprehensive), 10th ed. by Y. Daniel Liang

The following points about abstract classes are worth noting:

  • An abstract method cannot be contained in a nonabstract class. If a subclass of an abstract superclass does not implement all the abstract methods, the subclass must be defined as abstract. In other words, in a nonabstract subclass extended from an abstract class, all the abstract methods must be implemented. Also note that abstract methods are nonstatic.

  • An abstract class cannot be instantiated using the new operator, but you can still define its constructors, which are invoked in the constructors of its subclasses. For instance, the constructors of GeometricObject are invoked in the Circle class and the Rectangle class.

  • A class that contains abstract methods must be abstract. However, it is possible to define an abstract class that doesn’t contain any abstract methods. In this case, you cannot create instances of the class using the new operator. This class is used as a base class for defining subclasses.

  • A subclass can override a method from its superclass to define it as abstract. This is very unusual, but it is useful when the implementation of the method in the superclass becomes invalid in the subclass. In this case, the subclass must be defined as abstract.

  • A subclass can be abstract even if its superclass is concrete. For example, the Object class is concrete, but its subclasses, such as GeometricObject, may be abstract.

  • You cannot create an instance from an abstract class using the new operator, but an abstract class can be used as a data type. Therefore, the following statement, which creates an array whose elements are of the GeometricObject type, is correct.

GeometricObject[] objects = new GeometricObject[10];

You can then create an instance of GeometricObject and assign its reference to the array like this:

objects[0] = new Circle();