Abstract methods

Figure 483. Calculating a shape's area Slide presentation
public class Rectangle extents Shape {
  /**
   * Calculate the area.
   * @return The rectangle's area
   */
  public double getArea() {
    return width * height;
  } ...
public class Circle extents Shape {
  /**
   * Calculate the area.
   * @return The circle's area
   */
  public double getArea() {
    return PI * radius * radius;
  } ...

Figure 484. Desired: Polymorphic getArea() call Slide presentation
final Shape[] shapes  = {
    new Circle(1, 1, 2.) ,
    new Rectangle(1, -1, 2., 3.)};

for (final Shape s : shapes) {
  System.out.println(s.toString() + ": area = " + s.getArea()); 
}
Circle at (1.0|1.0), radius= 2.0: area = 12.566370614359172
Rectangle at (1.0|-1.0), width= 2.0, height=3.0: area = 6.0

An array of Shape references.

A Rectangle is a Shape and likewise is Circle. We can thus assign both Circle and Rectangle instances to variables (or array elements) of type Shape by means of upcasting.

Polymorphic dispatch: Depending on the object's type the Java runtime will automatically choose either Rectangle.toString()/ Rectangle.getArea() or Circle.getArea() / Circle.toString()/ Circle.getArea() respectively.


Figure 485. Problems: Slide presentation
  • No meaningful getArea() method in class Shape possible.

  • Meaningful implementations exist both in subclass Rectangle and Circle.

Solution: Abstract method getArea() in superclass Shape.


Figure 486. abstract method getArea() Slide presentation
abstract public class Shape {
  /**
   * Calculate the shape's area.
   * @return The shape's area
   */
  abstract public double getArea(); ...
public class Rectangle extends Shape {
  @Override
  public double getArea() {
    return width * height;
  }...
public class Circle ... {
 @Override
  public double getArea() {
    return Math.PI *
           radius * radius;
  } ...

Superclass Shape contains an abstract method and must thus itself be declared abstract as well.

Note

You cannot create instances of abstract classes. You may however create instances of derived non-abstract classes.

Method getArea() cannot be implemented in a meaningful way. Its abstract modifier is a promise that some concrete (= non-abstract) subclass will either offer an implementation of getArea() or will have an intermediate parent class doing so.

In other words: The abstract keyword requires a corresponding implementation in some derived non-abstract subclass.

An abstract method must not have an implementing body {...}.

Both Rectangle and Circle are concrete (=non-abstract) classes and are thus obliged to provide an implementation of double getArea().


Figure 487. abstract method getArea() Slide presentation

Figure 488. What's a shape anyway? Slide presentation
What's a “shape” anyway?

Figure 489. No instances of abstract classes. Slide presentation
final Shape s =
   new Shape(1., 2.); // 'Shape' is abstract; cannot be instantiated

Figure 490. Mandatory getArea() implementation. Slide presentation
// Error: Class 'Circle' must either be declared abstract or
//        implement abstract method 'getArea()' in 'Shape'
public class Circle extends Shape {

  public Circle(double x,double y, double radius) {
    super(x, y);
    this.radius = radius;
  }
  private double radius;
}

Figure 491. Facts about abstract fields, methods and classes. Slide presentation
  • A class containing an abstract method must itself be declared abstract.

  • abstract classes are allowed to host non-abstract methods.

  • A class may be declared abstract irrespective of purely containing non-abstract methods.