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 throughsuper(...)when a subclass object is created. - An
abstractmethod has no body and ends with a semicolon. Any class containing one must itself beabstract. - A concrete subclass must implement every inherited abstract method, or be declared abstract in turn.
abstractandfinalare contradictory and cannot be combined; neither canabstractandprivate.
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.
- Overloading is resolved at compile time, overriding at run time.
- Declared type decides what you may call; the object decides which version runs.
instanceofbefore every downcast.- An abstract class cannot be instantiated but may have constructors and fields.
- One
extends, manyimplements. - Interface methods are public; interface fields are constants.
- Calling a subclass-only method through a superclass variable.
- Downcasting without checking, and meeting
ClassCastException. - Forgetting
publicon 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.