THINK FIRST·CODE LATER

← Java Programming
Chapter 15 · Week 11–12

Polymorphism, Abstract Classes, and Interfaces

Before You Start: What You Must Be Able to Do

Before the questions, make sure you can: explain compile-time polymorphism (overloading) and run-time polymorphism (overriding with dynamic binding) and say which one a given piece of code uses; store a subclass object in a superclass variable and predict which method version runs; use instanceof and a downcast safely; declare an abstract class and an abstract method and state what each forbids; declare and implement an interface; and choose between an abstract class and an interface with a reason.

Two kinds of polymorphism

Compile-time (static) Run-time (dynamic)
Achieved by method overloading method overriding
Decided by the compiler, from the declared types of the arguments by the JVM, from the actual class of the object
Also called static binding, early binding dynamic binding, late binding

A superclass variable holding a subclass object

Shape s = new Circle(2.0);       // upcast: always safe, no cast operator needed
s.area();                        // Circle's area() runs: dynamic binding
s.radius();                      // COMPILE ERROR if radius() is declared only in Circle

The rule in one line: the declared type decides what you may call; the actual object decides which version runs. This is what makes the following work, and it is the whole point of polymorphism:

Shape[] shapes = { new Circle(1), new Square(2), new Triangle(3, 4) };
for (Shape sh : shapes) System.out.println(sh.area());   // three different area() methods

Adding a fourth shape does not change this loop at all — code that depends on the abstraction does not change when the implementations do.

Casting down, and instanceof

if (s instanceof Circle) {          // ask before you cast
    Circle c = (Circle) s;          // downcast: needed to reach Circle-only members
    System.out.println(c.getRadius());
}
Shape sh = new Square(2);
Circle c2 = (Circle) sh;            // compiles, but throws ClassCastException at run time

An upcast is implicit and always safe; a downcast must be written and is checked at run time.

Abstract classes

public abstract class Shape {
    private String name;
    public Shape(String name) { this.name = name; }   // abstract classes DO have constructors
    public abstract double area();                    // no body: subclasses must supply one
    public String getName() { return name; }          // ordinary inherited method
}
  • An abstract class cannot be instantiated: new Shape("x") is a compile error. It can still have constructors, fields and concrete methods, and its constructor runs through super(...) when a subclass object is created.
  • An abstract method has no body and ends with a semicolon. Any class containing one must itself be abstract.
  • A concrete subclass must implement every inherited abstract method, or be declared abstract in turn.
  • abstract and final are contradictory and cannot be combined; neither can abstract and private.

Interfaces

public interface Drawable {
    int MAX = 100;                       // implicitly public static final
    void draw();                         // implicitly public abstract
    default void describe() { System.out.println("drawable"); }   // Java 8+
}
public class Circle extends Shape implements Drawable, Comparable<Circle> {
    public void draw() { ... }           // must be public
    public int compareTo(Circle o) { ... }
}
Abstract class Interface
Keyword extends implements
How many one only as many as you like
Fields any, including mutable state constants only (public static final)
Methods abstract and concrete abstract, plus default and static since Java 8
Constructors yes no
Use it for shared state and partial implementation in an is-a hierarchy a capability that unrelated classes can offer

A class that implements an interface but does not define all its methods must be declared abstract. Interface methods are public by definition, so an implementation that forgets public reduces visibility and does not compile.

Polymorphism with parameters and return values

A method declared as void print(Shape s) accepts a Circle, a Square or anything else that is a Shape; a method may likewise return a Shape and hand back a Circle. This is how one method serves an entire family of types — and it is the reason to program to the abstraction rather than the concrete class.

Remember
  • Overloading is resolved at compile time, overriding at run time.
  • Declared type decides what you may call; the object decides which version runs.
  • instanceof before every downcast.
  • An abstract class cannot be instantiated but may have constructors and fields.
  • One extends, many implements.
  • Interface methods are public; interface fields are constants.
Common Pitfalls
  • Calling a subclass-only method through a superclass variable.
  • Downcasting without checking, and meeting ClassCastException.
  • Forgetting public on a method that implements an interface.
  • Expecting fields to behave polymorphically — they do not (Chapter 14).

Ready? Close the notes and practise.

37 questions. Predict the output before you check — that is the skill the exam measures.