๐ŸŽ“ A1Learner
๐Ÿ”
0 of 40 lessons completed

Java Polymorphism in Depth

Polymorphism means one call takes many shapes, and each object answers in its own way. One loop over a list of shapes prints the area of each one.

One loop, many areas

The list holds circles and rectangles as shapes. One loop prints a different area for each one.

import java.util.ArrayList;
import java.util.List;
public class Main {
  public static void main(String[] args) {
    List<Shape> shapes = new ArrayList<>();
    shapes.add(new Circle(1));
    shapes.add(new Rectangle(3, 4));
    for (Shape shape : shapes) {
      System.out.println(shape.area());
    }
  }
}
abstract class Shape {
  abstract double area();
}
class Circle extends Shape {
  int radius;
  Circle(int radius) {
    this.radius = radius;
  }
  double area() {
    return Math.PI * radius * radius;
  }
}
class Rectangle extends Shape {
  int width;
  int height;
  Rectangle(int width, int height) {
    this.width = width;
    this.height = height;
  }
  double area() {
    return width * height;
  }
}

Check the kind before the cast

The check confirms the shape is a circle. Only then does the cast read its radius.

public class Main {
  public static void main(String[] args) {
    Shape shape = new Circle(2);
    if (shape instanceof Circle) {
      Circle circle = (Circle) shape;
      System.out.println(circle.radius);
    }
  }
}
abstract class Shape {
  abstract double area();
}
class Circle extends Shape {
  int radius;
  Circle(int radius) {
    this.radius = radius;
  }
  double area() {
    return Math.PI * radius * radius;
  }
}

Pattern binding casts in one step

The pattern names the bound variable inside the check. The radius doubles to a diameter.

public class Main {
  public static void main(String[] args) {
    Shape shape = new Circle(2);
    if (shape instanceof Circle circle) {
      System.out.println(circle.radius * 2);
    }
  }
}
abstract class Shape {
  abstract double area();
}
class Circle extends Shape {
  int radius;
  Circle(int radius) {
    this.radius = radius;
  }
  double area() {
    return Math.PI * radius * radius;
  }
}

A wrong cast fails at run time

The shape is a rectangle. Casting it to a circle fails when the program runs.

public class Main {
  public static void main(String[] args) {
    Shape shape = new Rectangle(3, 4);
    Circle circle = (Circle) shape;
    System.out.println(circle.radius);
  }
}
abstract class Shape {
  abstract double area();
}
class Circle extends Shape {
  int radius;
  Circle(int radius) {
    this.radius = radius;
  }
  double area() {
    return Math.PI * radius * radius;
  }
}
class Rectangle extends Shape {
  int width;
  int height;
  Rectangle(int width, int height) {
    this.width = width;
    this.height = height;
  }
  double area() {
    return width * height;
  }
}

Example

import java.util.ArrayList;
import java.util.List;
public class Main {
  public static void main(String[] args) {
    List<Shape> shapes = new ArrayList<>();
    shapes.add(new Circle(2));
    shapes.add(new Rectangle(2, 5));
    shapes.add(new Circle(1));
    for (Shape shape : shapes) {
      System.out.println(shape.area());
    }
    Shape first = shapes.get(0);
    if (first instanceof Circle circle) {
      System.out.println(circle.radius);
    }
  }
}
abstract class Shape {
  abstract double area();
}
class Circle extends Shape {
  int radius;
  Circle(int radius) {
    this.radius = radius;
  }
  double area() {
    return Math.PI * radius * radius;
  }
}
class Rectangle extends Shape {
  int width;
  int height;
  Rectangle(int width, int height) {
    this.width = width;
    this.height = height;
  }
  double area() {
    return width * height;
  }
}

Key points

  • One loop over a list of shapes calls the area method of each one.
  • An instanceof check tests a value kind before a cast.
  • A pattern instanceof check casts and binds the value in one step.
  • A cast to the wrong kind compiles and then fails at run time.
  • Check first, and cast once.

In this example, one loop prints the area of each shape, and pattern binding then reads the first circle radius.

Try it Yourself

Edit the code, then press Run.

Running is simulated

Exercise

What does instanceof Circle circle do in an if check?