Drawing, Blinking, and Interfaces

A Drawing that holds a list of polygons and draws them all, an animation that makes them blink, and then the problem: to draw anything other than a polygon the code must be generalised, but DrawablePolygon already extends Polygon. Interfaces are Java's answer, and polymorphism is the name for what has been happening all along. Follows Think Java 2e, Chapter 17 (Advanced Topics), Sections 17.5-17.7, pp. 283-290, cross-referenced against The Java Tutorials — Defining an Interface.

Subject: Java · 65 slides · code lesson

Open the interactive version of this deck

What this lesson covers

The lesson, slide by slide

1. Drawing, Blinking, and Interfaces

Title

Think Java 2e · Chapter 17 · Advanced Topics

Sections 17.5-17.7 · pp. 283-290

2. What you will be able to do

Objectives

This lesson follows Think Java 2e, Chapter 17 (Advanced Topics), Sections 17.5-17.7, pp. 283-290. Everything on these slides can be checked against those pages.

1. Build a canvas that holds a list of drawable objects and paints them all.

2. Define polymorphism and identify a polymorphic method and a polymorphic data structure.

3. Add per-object animation with a step method overridden in subclasses.

4. Explain what super.draw(g) does when the immediate superclass has no draw method.

5. Distinguish an interface from an abstract class.

6. Write a class that extends one class and implements an interface.

3. Retrieve before you read

Warm-up

Three facts, all about to become the chapter's argument.

Discussion prompt

From Lesson 14a: how many superclasses may a Java class extend, and why can a Hand be passed where a CardCollection is expected? And from Lesson 16: what is the difference between an abstract class and a concrete one?

Hint: Exactly one. And an abstract class cannot be instantiated.

Answer:

Classes may extend only one superclass. A Hand can be passed where a CardCollection is expected because a Hand is one. And an abstract class cannot be instantiated and may declare methods without bodies, while a concrete class implements all of its methods.

The first fact is the wall this lesson runs into. DrawablePolygon already extends Polygon, and classes can extend only one superclass — which is precisely the problem interfaces solve.

4. One list, many kinds of thing

Concept

A Drawing holds objects and draws them. The whole lesson is about widening what objects is allowed to mean.

Figure (svg): Three panels showing the Drawing list widening from polygons to any drawable actor

Downey & Mayfield, Think Java, 2nd edition (Green Tea Press / O'Reilly, 2020) — Think Java 2e, Chapter 17 (Advanced Topics), Sections 17.5-17.7, pp. 283-290 — Section 17.5 opens on printed page 283.

5. The Drawing class

Section

Section 17.5

6. A canvas with a list

Concept

Now that we have DrawablePolygon and RegularPolygon, let's take them for a test drive. We'll need a Canvas for drawing them, so we define a new class, Drawing, that extends Canvas.

public class Drawing extends Canvas {
    private ArrayList<DrawablePolygon> list;

    public Drawing(int width, int height) {
        setSize(width, height);
        setBackground(Color.WHITE);
        list = new ArrayList<DrawablePolygon>();
    }

    public void add(DrawablePolygon dp) {
        list.add(dp);
    }

    public void paint(Graphics g) {
        for (DrawablePolygon dp : list) {
            dp.draw(g);
        }
    }
}
memberdoes
extends Canvasinherits the drawing machinery
the ArrayListholds the objects to draw
the constructorsets the size and background, creates the empty list
add(dp)appends one polygon
paint(g)overrides Canvas's, and draws every element

The Drawing class has an ArrayList of DrawablePolygon objects. When we create a Drawing object, the list is initially empty. This is Lesson 15a's GridCanvas with a list instead of a grid — the same specialization of the same library class, for a different shape of data.

7. paint, one more time

Notation

The third paint override in three chapters, and by now the pattern should read at a glance.

Annotate

  • The window system calls paint; you never do — Lesson 15a's rule, unchanged.
  • The Graphics object arrives as a parameter and is passed straight down to each object's own draw.
  • Each object draws itself. Drawing does not know what a polygon looks like, only that it can draw.
  • The enhanced for loop is right here, because no index is needed — Lesson 15a's rule again.
  • GridCanvas.draw had exactly this shape: for each cell, draw the cell. One list instead of two nested loops is the only difference.

Delegating drawing to the objects is what makes the container reusable. Drawing would work unchanged if polygons were replaced by anything else that could draw itself — which is the observation Section 17.7 acts on.

8. Three polygons on a canvas

Worked example

Here is an example that creates three RegularPolygon objects and draws them.

public static void main(String[] args) {
    // create some regular polygons
    DrawablePolygon p1 = new RegularPolygon(3, 50, Color.GREEN);
    DrawablePolygon p2 = new RegularPolygon(6, 50, Color.ORANGE);
    DrawablePolygon p3 = new RegularPolygon(360, 50, Color.BLUE);

    // move them out of the corner
    p1.translate(100, 80);
    p2.translate(250, 120);
    p3.translate(400, 160);

    // create drawing, add polygons
    Drawing drawing = new Drawing(500, 250);
    drawing.add(p1);
    drawing.add(p2);
    drawing.add(p3);
}
polygonsidescolourmoved to
p13GREEN(100, 80)
p26ORANGE(250, 120)
p3360BLUE(400, 160)

Create the shapes.

Why: The first block of code creates RegularPolygon objects with 3, 6, and 360 sides.

Move them apart.

Why: The second block of code translates the polygons to different locations — they are all built at the origin.

Add them to the Drawing.

Why: The third block of code creates the Drawing and adds the polygons to it.

Show the window.

Why: And the fourth block of code creates a JFrame, adds the Drawing to it, and displays the result.

Verify: Look at the third shape: as you can see, a polygon with 360 sides is a pretty good approximation of a circle.

Why: Most of these pieces should be familiar, but one part of this program might surprise you. Look again at the declared types on the first three lines — the variables are DrawablePolygon and the objects are RegularPolygon.

9. Is this assignment legal?

Prediction

The variable is the superclass; the object is the subclass.

DrawablePolygon p1 = new RegularPolygon(3, 50, Color.GREEN);
RegularPolygon extendsso it is also
DrawablePolygon?

Predict first

Does it compile?

  • Yes — every RegularPolygon is also a DrawablePolygon
  • No — the types must match exactly
  • Only with a cast
  • Only if RegularPolygon overrides draw

Correct: Yes — every RegularPolygon is also a DrawablePolygon

Why: This is polymorphism: a language feature that allows objects to be assigned to variables of related types. The object genuinely has every DrawablePolygon method, so the variable's promise is kept — the same rule that let a Hand be passed where a CardCollection was expected in Lesson 14a.

10. Polymorphism

Concept

When we create the RegularPolygon objects, we assign them to DrawablePolygon variables. It might not be obvious why that's legal.

DrawablePolygon p1 = new RegularPolygon(3, 50, Color.GREEN);
is polymorphic because
Drawing.addthe parameter can be one of many types
the ArrayList in Drawingthe elements can be different types
the variable p1it refers to an object of a subclass

polymorphism — A language feature that allows objects to be assigned to variables of related types.

RegularPolygon extends DrawablePolygon, so every RegularPolygon object is also a DrawablePolygon. The parameter of Drawing.add has to be a DrawablePolygon, but it can be any type of DrawablePolygon. Polymorphism is a fancy word that means having many forms — and it is Lesson 14a's substitution rule, finally named.

11. Calling a subclass method through a superclass variable

Trap

The trap

The declared type limits what you can call.

DrawablePolygon p = new RegularPolygon(6, 50, Color.BLUE);

p.draw(g);           // fine - DrawablePolygon has draw
p.getNumSides();     // compile error, even though the object has it
declared typeactual object
pDrawablePolygonRegularPolygon
methods you may callDrawablePolygon's—
methods the object has—RegularPolygon's too

The object really is a RegularPolygon; the compiler just does not know it. It checks against the declared type, because at compile time that is all it can be sure of.

The fix

Declare the type you need to use.

// if you only need the shared behaviour:
DrawablePolygon p = new RegularPolygon(6, 50, Color.BLUE);

// if you need RegularPolygon's own methods:
RegularPolygon rp = new RegularPolygon(6, 50, Color.BLUE);
declare aswhen
the superclassyou only need shared behaviour — the usual case
the subclassyou need something only it provides
the loosest type that worksthe general rule

The book declares them as DrawablePolygon deliberately, because all it does is translate and add them — both DrawablePolygon operations. Declaring the general type documents what you actually depend on, which is Lesson 14a's ask for the least you need.

12. Which are polymorphic?

Definition probe

A method or a structure can be.

Sort into buckets

Sort each item.

polymorphic
Drawing.add(DrawablePolygon dp); the ArrayList inside Drawing
not
int nsides; Math.sqrt(double x)
poly
The parameter or the elements can be any of several related types — the subclass objects are accepted wherever the superclass is named.
no
The type is a primitive with no subclasses, so there is only ever one form it can take.

13. Paint every polygon

Fill the middle

Each object draws itself.

Fill in the blanks

public void paint(Graphics g) list}) draw}(g);
}
}

Why: Drawing overrides paint and delegates the actual drawing to each object, passing the Graphics along. The enhanced for loop is right because no index is needed — and the delegation is what will let the list hold something other than polygons in Section 17.7.

14. Why does the compiler check the declared type?

Socratic

The object really does have the method.

Discussion prompt

p.getNumSides() fails even though p refers to a RegularPolygon. Why does Java check the declared type rather than the actual object?

Hint: What can the compiler know for certain?

Answer:

Because at compile time the actual object is not knowable in general. p could be assigned a plain DrawablePolygon on the next line, or come from a method that returns one.

The declared type is a promise about every object the variable could ever hold, and the compiler checks against that promise.

Which is what makes polymorphism safe. A method taking a DrawablePolygon can rely on every DrawablePolygon method existing on whatever it receives — that guarantee is exactly what the restriction buys.

15. Animating the drawing

Section

Section 17.6

16. A step method, all the way down

Concept

At this point, we have a simple program that draws polygons; we can make it more fun by adding animation. Chapter 15 introduced the idea of simulating time steps.

while (true) {
    drawing.step();
    try {
        Thread.sleep(1000 / 30);
    } catch (InterruptedException e) {
        // do nothing
    }
}
linedoes
drawing.step()update every object, then repaint
Thread.sleep(1000 / 30)about 33 milliseconds
the effectroughly 30 frames per second

Each time through the loop, we call step to update the Drawing. Then we sleep with a delay calculated to update about 30 times per second. The same loop as Lesson 15b and Lesson 16 — the third appearance of update, repaint, sleep.

17. step cascades down the list

Picture it

One call at the top becomes one call per object, and then a repaint.

Figure (svg): A pipeline from the animation loop through Drawing step to each polygon's own step and a repaint

It invokes step on each DrawablePolygon in the list and then repaints (clears and redraws) the canvas. Drawing knows when to update and nothing about what updating means — which is why the same container can animate a blinking polygon and a moving sprite.

18. A do-nothing step to override

Worked example

In order for this code to compile, we need DrawablePolygon to provide a step method. Here's a version that doesn't do anything; we'll override it in subclasses.

// in DrawablePolygon:
public void step() {
    // do nothing
}

// in Drawing:
public void step() {
    for (DrawablePolygon dp : list) {
        dp.step();
    }
    repaint();
}
classstep does
DrawablePolygonnothing
RegularPolygonnothing — inherited
BlinkingPolygoncounts, and toggles visibility

The loop calls dp.step().

Why: So the declared type must have a step method, or it will not compile.

DrawablePolygon supplies an empty one.

Why: A polygon that does not animate simply does nothing on a time step.

Subclasses override it.

Why: Which is what makes one shape blink while another sits still.

Compare with Lesson 16's abstract.

Why: There, an empty method was the wrong choice; here, doing nothing is a legitimate behaviour.

Verify: Ask why update in Automaton was abstract and step here is not.

Why: Because a static polygon genuinely has nothing to do, so the empty body is correct rather than a placeholder — whereas an Automaton with no update would be a broken simulation. **Abstract is for methods with no sensible default; an empty body is for methods whose default is nothing.**

19. Which draw does super.draw call?

Prediction

BlinkingPolygon extends RegularPolygon, which has no draw.

public class BlinkingPolygon extends RegularPolygon {
    public void draw(Graphics g) {
        if (visible) {
            super.draw(g);
        }
    }
}
classhas draw?
BlinkingPolygonyes — this one
RegularPolygonno
DrawablePolygonyes

Predict first

Whose draw method runs?

  • DrawablePolygon's — Java keeps looking up the chain
  • RegularPolygon's, which is empty
  • BlinkingPolygon's own — an infinite loop
  • A compile error, since RegularPolygon has no draw

Correct: DrawablePolygon's — Java keeps looking up the chain

Why: But the parent class is RegularPolygon, which does not provide a draw method. In this case, super invokes draw from the DrawablePolygon class. super means start looking in the superclass, not the immediate superclass must have it — the search continues upward until a definition is found.

20. The blinking polygon

Concept

Now let's design a new type of polygon that blinks. Two new attributes and two overridden methods.

public class BlinkingPolygon extends RegularPolygon {
    protected boolean visible;
    protected int count;

    public BlinkingPolygon(int nsides, int radius, Color c) {
        super(nsides, radius, c);
        visible = true;
        count = 0;
    }

    public void draw(Graphics g) {
        if (visible) {
            super.draw(g);
        }
    }

    public void step() {
        count++;
        if (count == 10) {
            visible = !visible;
            count = 0;
        }
    }
}
step numbercountvisible
1 to 91 to 9true
10reset to 0false — toggled
20reset to 0true — toggled back

The step method increments count. Every 10 time steps, it toggles visible and resets count to 0. At 30 frames per second that is a blink about three times a second — and visible = !visible is Lesson 5b's logical negation doing the toggling.

21. Forgetting super.draw and losing the drawing

Trap

The trap

An override that replaces instead of extending.

public void draw(Graphics g) {
    if (visible) {
        // now what? re-implement fillPolygon here?
    }
}
approachresult
nothing in the ifthe polygon is never drawn
copy DrawablePolygon's two linesduplicated code
call super.draw(g)correct

Overriding replaces the inherited method entirely. If the subclass wants to add a condition around the original behaviour, it has to call the original explicitly.

The fix

Guard the condition, then delegate upward.

public void draw(Graphics g) {
    if (visible) {
        super.draw(g);
    }
}
visiblewhat happens
truesuper.draw(g) runs — the polygon appears
falsenothing is drawn — it vanishes

The draw method draws the polygon only if it is visible. It uses super to call draw in the parent class. Adding a condition around inherited behaviour is one of the most common reasons to override — and super.method() is how you keep the behaviour you are wrapping.

22. How often does it blink?

Prediction

30 frames per second, toggling every 10 steps.

public void step() {
    count++;
    if (count == 10) {
        visible = !visible;
        count = 0;
    }
}
value
steps per second30
steps per toggle10

Predict first

How many times per second does visibility change?

  • 3
  • 10
  • 30
  • 300

Correct: 3

Why: Thirty steps a second divided by ten steps per toggle gives three toggles a second — so the polygon appears and disappears about one and a half times a second. Note the frame rate lives in the animation loop and the blink interval lives in the object, so the two can be tuned independently.

23. Toggle the visibility

Fill the middle

Count up, then flip.

Fill in the blanks

public void step() ++};
if (count == 10) !}visible;
count = 0;
}
}

Why: count++ is the increment from Lesson 6a; !visible is logical negation, which turns true into false and back. Resetting count to 0 is what makes the interval repeat rather than firing once at step ten and never again.

24. Why is step empty in DrawablePolygon?

Explain it to yourself

Lesson 16 made a similar method abstract.

Discussion prompt

Automaton declared update abstract; DrawablePolygon gives step an empty body. Why the different choice?

Hint: Is doing nothing a legitimate behaviour in each case?

Answer:

A static polygon genuinely has nothing to do on a time step, so an empty body is the correct behaviour rather than a missing one.

An Automaton with no update would be broken — a simulation that never simulates. There is no sensible default, so the compiler should demand one.

**The test: is do nothing a correct answer for some subclass?** If yes, an empty body is right; if no, make it abstract so a forgotten override fails to compile.

25. The problem with a superclass

Section

Section 17.7

26. Drawing does exactly three things

Concept

You might be getting tired of polygons at this point. Can't we draw anything else? Of course we can, but Drawing is currently based on DrawablePolygon. To draw other types of objects, we have to generalize the code.

// The Drawing class does essentially three things:
//   1. it maintains a LIST of objects
//   2. it invokes the DRAW method on each object
//   3. it invokes the STEP method on each object
what Drawing needswhat it does not need
draw(Graphics)npoints, xpoints, ypoints
step()translate, contains, intersects
nothing elsecolour, sides, radius

Two methods. Everything else about DrawablePolygon is irrelevant to Drawing — which means requiring the elements to be DrawablePolygons is asking for far more than is needed.

27. The obvious fix, and why it fails

Notation

So here's one way we could make the code more general — and the book proposes it before rejecting it.

Annotate

  • The plan is sound — it is exactly Chapter 16's generalization, applied to a different pair of methods.
  • Step 3 is where it breaks. DrawablePolygon extends Polygon already, and there is no second extends.
  • You cannot fix it by changing Polygon — it is a library class you did not write.
  • And the superclass would be empty anyway. Two methods that do nothing, existing only to be overridden.
  • Two problems, one solution. Java's answer removes the single-inheritance limit for this case and drops the pointless bodies at the same time.

Java provides another mechanism for inheritance that solves these problems. The constraint is real and the workaround is a language feature, which is a good sign the constraint was deliberate.

28. Actor as an interface

Worked example

We can define Actor as an interface instead of a class.

public interface Actor {
    void draw(Graphics g);
    void step();
}
classinterface
keywordclassinterface
method bodiesrequirednot allowed
how many can you inherit?oneas many as you like
keyword to inheritextendsimplements

An interface contains methods.

Why: Like a class definition, an interface definition contains methods.

But only their declarations.

Why: But it contains only the declarations of the methods, not their implementations.

Like an abstract class — almost.

Why: Like an abstract class, an interface specifies methods that must be provided by subclasses. The difference is that an abstract class can implement some methods; an interface cannot.

No public needed.

Why: All interface methods are public by default, since they are intended to be used by other classes.

Verify: Notice void draw(Graphics g); has no public and no body — just a signature and a semicolon.

Why: The semicolon is doing the same job as in an abstract method declaration. An interface is, in effect, a class where every method is abstract and there are no attributes — which is why Java can relax the one-superclass rule for it.

29. Why can't Actor be a superclass?

Prediction

DrawablePolygon would need to extend it.

public class DrawablePolygon extends Polygon { ... }
// and now it should also extend Actor?
ruleconsequence
one superclass per class?

Predict first

What is the obstacle?

  • DrawablePolygon already extends Polygon, and classes can extend only one superclass
  • Actor has no attributes
  • Polygon is a library class
  • Actor's methods are empty

Correct: DrawablePolygon already extends Polygon, and classes can extend only one superclass

Why: There's just one problem: DrawablePolygon already extends Polygon, and classes can extend only one superclass. The book also notes the Actor class seems pointless, since the methods it defines don't do anything — but that is a secondary complaint; the single-inheritance rule is what makes it impossible.

30. Interface against abstract class

Concept

They overlap enough to be confused and differ in exactly the ways that matter here.

abstract classinterface
can declare methods with no bodyyesyes — only that
can implement some methodsyesno
can have attributesyesno
how many can a class inheritonemany
keywordextendsimplements
exampleAutomatonActor

Automaton had to be an abstract class because it carried run and mainloop — real code the subclasses inherited. Actor can be an interface because it carries nothing but two signatures. The choice follows from whether there is shared implementation to give away.

31. Trying to extend two classes

Trap

The trap

Java has no multiple inheritance of classes.

public class DrawablePolygon extends Polygon, Actor {
    // compile error
}
attemptlegal?
extends one classyes
extends two classesno
extends one class, implements one interfaceyes
extends one class, implements several interfacesyes

Classes may extend only one superclass — Lesson 14a's rule, and the reason the whole Actor plan needed a different mechanism.

The fix

extends once; implements as often as you like.

public class DrawablePolygon extends Polygon implements Actor {
    // rest of the class omitted
}
clausegives
extends Polygonthe inherited attributes and methods
implements Actorthe obligation to provide draw and step
both togetherDrawablePolygon is a Polygon and an Actor

To inherit from an interface, you use the keyword implements instead of extends. So it inherits methods from Polygon, and it is required to provide the methods in Actor; namely draw and step — which it already had, so this change costs one line.

32. Interface or abstract class?

Definition probe

The deciding question is whether there is shared code.

Sort into buckets

Sort each requirement.

interface
specify methods with no implementation at all; be inherited alongside another superclass
abstract class
share a run and mainloop implementation; hold a protected attribute for subclasses
iface
An interface contains only declarations, and a class may implement as many as it needs — which is exactly what a class that already extends something requires.
abs
An abstract class can implement some methods and hold attributes, which an interface cannot — but a class may extend only one.

33. Declare and implement

Fill the middle

Two methods, no bodies.

Fill in the blanks

public interface Actor implements

public class DrawablePolygon extends Polygon ___ Actor ___

Why: An interface is declared with interface rather than class and contains only signatures — no bodies and no public, since interface methods are public by default. A class uses implements for an interface and extends for a superclass, and it can do both at once.

34. Is an interface always better?

Counterexample

It removes the one-superclass limit.

Discussion prompt

If interfaces can be implemented freely, why does Java still have abstract classes — and why was Automaton one?

Hint: What did Automaton give its subclasses?

Answer:

Because an interface cannot implement anything. Automaton gave Conway and Langton a working run and mainloop — dozens of lines of shared code that an interface could not carry.

It also held a protected attribute, grid. An interface has no attributes at all.

The two solve different problems. An abstract class shares implementation with a family of related classes; an interface states a capability that unrelated classes can each satisfy their own way. Actor is a capability — this thing can be drawn and stepped — which is why it is an interface.

35. Implementing an interface

Section

Section 17.7

36. One object, several types

Concept

In terms of inheritance, DrawablePolygon is both a Polygon and an Actor. So the following assignments are legal.

Polygon p1 = new DrawablePolygon();
Actor   a1 = new DrawablePolygon();

Polygon p2 = new RegularPolygon(5, 50, Color.YELLOW);
Actor   a2 = new RegularPolygon(5, 50, Color.YELLOW);
objectis a Polygon?is an Actor?is a DrawablePolygon?
new DrawablePolygon()yesyesyes
new RegularPolygon(...)yesyesyes
a plain Polygonyesnono

And the same is true for subclasses of DrawablePolygon. A RegularPolygon inherits both the extends and the implements — so it is an Actor without saying so, which is what lets Drawing hold one.

37. The type graph

Picture it

One chain of classes, and an interface cutting across it.

Figure (svg): A UML diagram showing DrawablePolygon extending Polygon and implementing the Actor interface

Classes may extend only one superclass, but they may implement as many interfaces as needed. Java library classes often implement multiple interfaces. That is why the class hierarchy is a tree while the type graph is not.

38. What changes in Drawing

Worked example

Generalising the container is now a search and replace.

// before
private ArrayList<DrawablePolygon> list;
public void add(DrawablePolygon dp) { list.add(dp); }

// after
private ArrayList<Actor> list;
public void add(Actor a) { list.add(a); }
what Drawing can now holdrequirement
DrawablePolygonimplements Actor
RegularPolygoninherits the implements
BlinkingPolygoninherits it too
Sprite — Lesson 17cimplements Actor itself
anything at allwith a draw and a step

Replace the element type.

Why: In the Drawing class, replace DrawablePolygon with Actor.

The loops do not change.

Why: dp.draw(g) and dp.step() are exactly the two methods Actor declares.

Nothing else needs editing.

Why: Drawing never used any other DrawablePolygon method — which is why this works.

The list is now polymorphic across unrelated classes.

Why: Interfaces are another example of polymorphism.

Verify: Check that Drawing never calls translate, addPoint or anything else polygon-specific.

Why: That check is what made the generalization possible. Had Drawing used one polygon method, Actor would have needed to declare it — and a sprite would have had to fake it. Depending only on what you use is what leaves the door open.

39. Is a RegularPolygon an Actor?

Prediction

Only DrawablePolygon says implements.

public class DrawablePolygon extends Polygon implements Actor { }
public class RegularPolygon extends DrawablePolygon { }

Actor a = new RegularPolygon(5, 50, Color.YELLOW);
classdeclares implements Actor?
DrawablePolygonyes
RegularPolygonno

Predict first

Does the assignment compile?

  • Yes — RegularPolygon inherits the interface along with everything else
  • No — it must declare implements Actor itself
  • Only with a cast
  • Only if it overrides draw and step

Correct: Yes — RegularPolygon inherits the interface along with everything else

Why: And the same is true for subclasses of DrawablePolygon; these assignments are legal too. A subclass inherits its superclass's interfaces as well as its methods, so every RegularPolygon is an Actor without saying so — which is what lets Drawing hold one.

40. Interfaces are polymorphism too

Concept

a1 and a2 are the same type of variable, but they refer to objects with different types. And similarly with p1 and p2.

Actor a1 = new DrawablePolygon();
Actor a2 = new RegularPolygon(5, 50, Color.YELLOW);

// and in Lesson 17c:
Actor a3 = new Sprite("face-smile.png", 25, 150);
inheritance polymorphisminterface polymorphism
related howa shared superclassa shared capability
the classesmust be in one hierarchycan be unrelated
Sprite and RegularPolygonshare only Objectboth are Actors

Sprite and RegularPolygon have nothing in common — one wraps an image file, the other computes vertices with trigonometry. Yet both can sit in the same list, because an interface describes what a thing can do rather than what it is descended from.

41. Implementing an interface without all its methods

Trap

The trap

A concrete class must supply every declared method.

public class Sprite implements Actor {
    public void draw(Graphics g) { ... }
    // no step method
}

// error: Sprite is not abstract and does not override
//        abstract method step() in Actor
Actor declaresSprite provides
draw(Graphics)yes
step()no — compile error

Like an abstract class, an interface specifies methods that must be provided by subclasses. The compiler enforces it exactly as it enforced Lesson 16's abstract method — same message, same reason.

The fix

Provide them all, even the ones that do nothing.

public class Sprite implements Actor {
    public void draw(Graphics g) { ... }
    public void step() { ... }
}

// and where a method genuinely has nothing to do:
public void keyTyped(KeyEvent e) {
    // do nothing
}
situationwhat to write
the method mattersthe real implementation
it does not applyan empty body with a comment
you cannot implement it yetdeclare the class abstract

The middle row is common and Lesson 17c meets it head on: keyTyped is required by KeyListener and unwanted by Sprite, so it gets an empty body. An interface is all-or-nothing — which is the price of the guarantee it gives callers.

42. How many can you have?

Definition probe

The rules differ for the two mechanisms.

Sort into buckets

Sort each statement.

superclasses
extends at most one; a class hierarchy is a tree
interfaces
implements as many as needed; a class can satisfy several unrelated capabilities
cls
Classes may extend only one superclass, so every class has exactly one parent chain ending at Object.
if
Classes may implement as many interfaces as needed — Java library classes often implement several.

43. Match the keyword to what follows it

Matching

Four declarations from this lesson.

Match the pairs

  • a. extends Polygon
  • b. implements Actor
  • c. public interface Actor
  • d. public abstract class Automaton
  • r1. inherit a superclass's attributes and methods
  • r2. promise to provide an interface's methods
  • r3. declare methods with no implementations at all
  • r4. declare some methods and implement others

Why: The last two are the pair worth keeping straight: an interface can only declare, while an abstract class can declare and implement — which is why Automaton could carry run and mainloop while Actor carries nothing.

44. Why does Java forbid multiple inheritance of classes?

Real world

Interfaces can be inherited freely; classes cannot.

Discussion prompt

If a class could extend two superclasses, what problem would arise — and why does the same problem not arise for interfaces?

Hint: What if both parents have a method with the same name?

Answer:

Ambiguity. If both superclasses define draw, which one does the subclass inherit? And if both have a field called count, are there two, or one?

Interfaces have no bodies and no fields, so there is nothing to conflict. Two interfaces both declaring draw is fine — the class supplies one implementation that satisfies both.

Java traded a feature for a simpler rule, and then gave back most of the usefulness through interfaces. That is why implements has no limit while extends has one — the restriction exists exactly where the ambiguity would.

45. Designing to a capability

Section

Sections 17.5-17.7 together

46. The whole lesson in one substitution

Concept

Drawing began holding polygons and ends holding anything that can draw and step. Nothing inside it changed except one type name.

// before: a container of a particular class
private ArrayList<DrawablePolygon> list;

// after: a container of a capability
private ArrayList<Actor> list;
beforeafter
what can go inpolygonsanything with draw and step
what Drawing knowsthe same two methodsthe same two methods
lines changed—two
what made it possible—Drawing used only those two methods

The generalization was cheap because the coupling was already loose. Drawing never called a polygon method — which was not an accident but the consequence of letting each object draw itself.

47. Three ways of saying *these things are alike*

Notation

Chapters 14, 16 and 17 each added a mechanism, and they are not interchangeable.

Annotate

  • A plain superclass gives everything and demands nothing — subclasses can override, but need not.
  • An abstract class gives some and demands some. It is the middle of the range, and Automaton is the example.
  • An interface gives nothing and demands everything it declares. No bodies, no fields.
  • Only the interface can be combined freely. That is the deciding factor whenever the class already extends something.
  • All three produce polymorphism, in the sense that a variable of the general type can hold objects of several specific types.

Choose by what you have to give away. Shared code means a class; a bare capability means an interface; both means an abstract class.

48. Reading a declaration with both

Worked example

public class DrawablePolygon extends Polygon implements Actor says three things at once.

public class DrawablePolygon extends Polygon implements Actor {
    // rest of the class omitted
}
clausegivesdemands
extends Polygonnpoints, addPoint, translate, containsnothing
implements Actornothingdraw and step
the class bodycolor, draw, step—

extends comes first, and there is one.

Why: Java's syntax requires that order.

implements may list several.

Why: Separated by commas — Lesson 17c's Sprite implements two.

The class must satisfy the interface.

Why: Here it already did, since draw and step were written in Section 17.2 and 17.6.

And it gains a second type.

Why: DrawablePolygon is both a Polygon and an Actor.

Verify: Count the types a RegularPolygon object belongs to: RegularPolygon, DrawablePolygon, Polygon, Actor, Object.

Why: Five types for one object, and a variable of any of them can hold it. That is what polymorphism means in practice — and the reason a method should declare the loosest of the five that does its job.

49. Which mechanism?

Definition probe

Superclass, abstract class, or interface.

Sort into buckets

Sort each situation.

a superclass
two classes share thirty lines of identical code
an abstract class
share code and require one method to be overridden
an interface
unrelated classes must each provide a draw method; the class already extends a library class
cls
There is shared implementation to give and nothing to demand, so an ordinary superclass fits.
abs
Some methods can be implemented and at least one must be supplied by each subclass — the abstract class's exact range.
if
There is nothing to give and only a capability to require — and an interface is the only one that can be combined with an existing extends.

50. What Lesson 17c does with this

Concept

The interface was introduced to make room for something that is not a polygon at all.

classwhat it isimplements
DrawablePolygona shape with verticesActor
Spritean image read from a fileActor, KeyListener
what they sharenothingthe ability to draw and step

Now that our Drawing is based on Actor instead of DrawablePolygon, we can draw other types of graphics. Sprite implements two interfaces, which is where the as many as needed rule stops being theoretical.

51. Putting a method in the interface that only some implementers need

Trap

The trap

Every implementer must provide every method.

public interface Actor {
    void draw(Graphics g);
    void step();
    void translate(int dx, int dy);   // polygons have this
    Color getColor();                  // sprites do not
}
implementertranslategetColor
DrawablePolygoninherited from Polygonnatural
Spritewould have to invent onemeaningless
result—empty methods everywhere

A Sprite has no colour, so getColor would return null or grey and mean nothing. An interface that demands more than every implementer can honestly provide forces its implementers to lie.

The fix

Declare only what every implementer genuinely does.

public interface Actor {
    void draw(Graphics g);
    void step();
}
methoddoes every actor do it?
drawyes — that is what it is for
stepyes — even if the step does nothing
translateno
getColorno

Two methods, because Drawing needs two. An interface is a contract, and a small contract is easier to satisfy honestly — which is the same argument as Lesson 11a's small public surface, applied to a type rather than a class.

52. How many types does a BlinkingPolygon have?

Prediction

Count the whole chain, plus the interface.

class BlinkingPolygon extends RegularPolygon
class RegularPolygon extends DrawablePolygon
class DrawablePolygon extends Polygon implements Actor
typefrom
BlinkingPolygonitself
RegularPolygonextends
Actorinherited implements

Predict first

Which variable types can hold a BlinkingPolygon?

  • BlinkingPolygon, RegularPolygon, DrawablePolygon, Polygon, Actor and Object
  • Only BlinkingPolygon
  • BlinkingPolygon and Actor
  • Only the classes, not the interface

Correct: BlinkingPolygon, RegularPolygon, DrawablePolygon, Polygon, Actor and Object

Why: An object belongs to its own class, every class above it, every interface those classes implement, and Object at the top. Six types for one object — and a method should declare whichever of them is the loosest that still lets it do its job.

53. Generalise the container

Fill the middle

Depend on the capability, not the class.

Fill in the blanks

private ArrayList<Actor> list;

public void add(Actor a) ___

Why: Replacing DrawablePolygon with Actor is the entire generalisation, because Drawing only ever called draw and step — the two methods the interface declares. Anything that implements Actor now fits, including classes with no relationship to polygons at all.

54. Why is Actor the right size?

Explain it to yourself

Two methods, no more.

Discussion prompt

Actor declares exactly draw and step. What decided that number, and what would go wrong if it were larger?

Hint: What does Drawing actually call?

Answer:

Drawing calls exactly two methods, so those are the two the interface must declare. The size of the contract was determined by the consumer, not by the implementers.

A larger interface would exclude implementers. A Sprite has no colour and no vertices, so any method about those would force it into a meaningless implementation.

Declare what the caller needs, not what the implementers happen to have. A small interface is easy to satisfy honestly, and every method you add narrows the set of classes that can implement it.

55. Three ways to share a type

Comparison

Fill the blanks.

Comparison matrix

superclassabstract classinterface
can implement methodsyes, allyes, someno
can have attributesyesyesno
can be instantiatedyesnono
how many per classoneoneas many as needed
keyword to inheritextendsextendsimplements

The fourth row is the one that decided this chapter. DrawablePolygon had already spent its one extends on Polygon, so only an interface could add the Actor type on top.

56. The pattern to carry away

Pattern

Depend on a capability, not a class — then anything that has the capability fits.

// 1. name the capability the consumer needs
public interface Actor {
    void draw(Graphics g);
    void step();
}

// 2. the consumer holds the interface, not a concrete class
public class Drawing extends Canvas {
    private ArrayList<Actor> list;
    public void add(Actor a) { list.add(a); }
    public void paint(Graphics g) {
        for (Actor a : list) { a.draw(g); }
    }
}

// 3. anything at all can implement it
public class DrawablePolygon extends Polygon implements Actor { }
public class Sprite implements Actor, KeyListener { }
rulereason
declare only what the consumer callsa small contract is easy to satisfy
extends once, implements freelyonly interfaces can be combined
a subclass inherits its parent's interfacesRegularPolygon is an Actor for free
a concrete class must supply every methodeven if the body is empty
super.method() searches upwardnot just the immediate parent

57. Check: super through a gap

Check

Work it out before you click.

class DrawablePolygon { public void draw(Graphics g) { ... } }
class RegularPolygon extends DrawablePolygon { /* no draw */ }
class BlinkingPolygon extends RegularPolygon {
    public void draw(Graphics g) {
        if (visible) { super.draw(g); }
    }
}
classdefines draw?
RegularPolygonno
DrawablePolygonyes

Check your understanding

Which draw does super.draw(g) invoke?

  • A. DrawablePolygon's — Java searches up the chain until it finds one (correct)
  • B. A compile error, since RegularPolygon has no draw
  • C. BlinkingPolygon's own, causing infinite recursion
  • D. Object's draw method

Answer: A

Why: But the parent class is RegularPolygon, which does not provide a draw method. In this case, super invokes draw from the DrawablePolygon class. super means begin the search in the superclass, and the search continues upward — the same lookup that lets an inherited method be called without qualification.

Why B tempts people
A missing method in the immediate parent is not an error; the search simply continues.
Why C tempts people
super. explicitly skips the current class, which is what prevents recursion.
Why D tempts people
java.lang.Object has no draw method; the search would fail there, not succeed.

58. Check: interface against abstract class

Check

Work it out before you click.

public interface Actor {
    void draw(Graphics g);
    void step();
}
featureinterface
method bodies?
attributes?

Check your understanding

What is the difference from an abstract class?

  • A. An abstract class can implement some methods and hold attributes; an interface can do neither, but a class may implement many (correct)
  • B. An interface can be instantiated
  • C. An abstract class cannot declare methods without bodies
  • D. There is no difference

Answer: A

Why: Like an abstract class, an interface specifies methods that must be provided by subclasses. The difference is that an abstract class can implement some methods; an interface cannot. That is why Automaton had to be an abstract class — it carried run and mainloop — while Actor can be an interface, and why only Actor could be added to a class that already extended Polygon.

Why B tempts people
Neither can be instantiated; that is one thing they share.
Why C tempts people
Declaring a method without a body is exactly what abstract allows in a class.
Why D tempts people
The differences are what made this chapter's design possible.

59. Check: polymorphism

Check

Work it out before you click.

DrawablePolygon p = new RegularPolygon(6, 50, Color.BLUE);
drawing.add(p);
// public void add(DrawablePolygon dp)
type
the variableDrawablePolygon
the objectRegularPolygon

Check your understanding

What makes this legal?

  • A. Polymorphism — every RegularPolygon is also a DrawablePolygon, so it can be assigned to a variable of that type (correct)
  • B. Java converts the object to a DrawablePolygon
  • C. The two classes have the same methods
  • D. add is overloaded for both types

Answer: A

Why: Polymorphism: a language feature that allows objects to be assigned to variables of related types. Nothing is converted — the object genuinely has every DrawablePolygon method, because it inherited them. Drawing.add is a polymorphic method for the same reason: the parameter can be one of many types.

Why B tempts people
No conversion happens; the object is unchanged and keeps all its own methods.
Why C tempts people
RegularPolygon has more methods than DrawablePolygon; the relationship is inheritance, not coincidence.
Why D tempts people
There is one add method, taking the superclass.

60. Interfaces are how libraries stay open

Real world

Drawing can display objects whose classes did not exist when Drawing was written.

Discussion prompt

Where else does a program have to work with types its author never saw — and how does an interface make that possible?

Hint: Every plugin, every callback, every sort.

Answer:

Anywhere a library calls your code. Arrays.sort compares objects it has never seen by requiring them to implement Comparable — the same idea as Actor, with compareTo instead of draw.

And every plugin system: the host declares an interface, and anyone can write a class that implements it. The host was compiled long before the plugin existed.

Lesson 17c is the next example — KeyListener is an interface the window system defines and your class implements, so that the system can call you when a key is pressed. An interface is how code you have not written yet gets to participate.

61. How sure are you?

Commit first

Commit to an answer and to your confidence.

Predict first

Why did Actor have to be an interface rather than a superclass?

  • DrawablePolygon already extends Polygon, and a class may extend only one superclass
  • Because Actor's methods are empty
  • Because interfaces are faster
  • Because Polygon is abstract

Correct: DrawablePolygon already extends Polygon, and a class may extend only one superclass

Why: There's just one problem: DrawablePolygon already extends Polygon, and classes can extend only one superclass. The book raises a second objection too — the Actor class seems pointless, since the methods it defines don't do anything — but that one is a matter of taste; the single-inheritance rule makes the superclass approach impossible outright. Since classes may implement as many interfaces as needed, extends Polygon implements Actor costs one clause and no restructuring — and Sprite in Lesson 17c goes further, implementing two interfaces at once.

62. Explain it to someone else

Explain it

Two minutes, out loud.

Discussion prompt

A classmate asks when to use an interface and when to use an abstract class. Give them the rule and one example of each from this course.

Hint: What do you have to give away?

Answer:

Ask what you have to give the subclasses. If there is real shared code, you need a class — Automaton gave Conway and Langton a working run and mainloop, which an interface could not carry.

If there is nothing to give and only methods to require, use an interface — Actor just says a thing can draw and step, and carries no code and no fields.

And there is a hard constraint: a class can extend only one superclass but implement any number of interfaces. So if the class already extends something, the interface is your only option. That constraint decides more designs than the philosophy does.

63. Exit ticket

Exit ticket

One question before you close the deck.

Predict first

What is polymorphism?

  • A language feature that allows objects to be assigned to variables of related types
  • Defining several methods with the same name
  • A class that cannot be instantiated
  • Extracting shared code into a superclass

Correct: A language feature that allows objects to be assigned to variables of related types

Why: Polymorphism: a fancy word that means having many forms. A RegularPolygon can be held in a DrawablePolygon variable, an Actor variable, or a Polygon variable — one object, several types. That is what makes Drawing.add a polymorphic method (the parameter can be one of many types) and its ArrayList a polymorphic data structure (the elements can be different types). The second option describes overloading, the third an abstract class, and the fourth generalization — three different ideas that are easy to confuse with this one.

64. Draw the whole lesson

Connect it up

One page, from memory.

Draw it

Draw the type graph: Polygon, DrawablePolygon, RegularPolygon, BlinkingPolygon in a chain, with Actor off to the side and a second arrow from DrawablePolygon to it. Beside each class write only what it adds. Then list the six types a BlinkingPolygon object belongs to. Below that, write out the three-column comparison of superclass, abstract class and interface — can implement, can hold attributes, how many per class — and circle the row that forced Actor to be an interface.

65. Recap

Recap

Three sections that build a container, animate it, and then widen what it can contain.

if you remember one thingit is this
about polymorphismone object, several types
about interfacesa capability, not an ancestry
about designdepend on what you call, not on what you were given

Sources

  1. Downey & Mayfield, Think Java, 2nd edition (Green Tea Press / O'Reilly, 2020) — Think Java 2e, Chapter 17 (Advanced Topics), Sections 17.5-17.7, pp. 283-290
  2. The Java Tutorials — Defining an Interface
  3. Think Java 2e — free online edition and source code

Want this taught 1-on-1? Alexander tutors Java — $55/session, free consultation.

Book on Wyzant · Text (657) 465-8108