Abstract classes
Inheritance as you have it forces the superclass to implement everything, even methods that have no sensible parent version — and a wrong default is a trap: forget to override it and the program runs, silently producing nonsense. This lesson's two tools let a class demand behavior from its children instead of faking it, which is how libraries safely hand you half-finished machinery to complete.
In lesson 6-2, Shape.area() returned a meaningless 0.0. Better: declare that every Shape must have an area without pretending to know it. An abstract class can declare methods with no body:
abstract class Animal { abstract void speak(); // no body: subclasses must provide it void speakTwice() { // normal method, inherited as usual speak(); speak(); } }
You cannot write new Animal() anymore. Any concrete subclass must override speak(), or the compiler refuses it. Note speakTwice calls speak() before any subclass exists: polymorphism guarantees the right version runs later.
Code exercise · java
Run this. Duck must implement speak() (from the abstract class) and swim() (from the interface). speakTwice comes free from Animal.
Interfaces
An interface is a pure contract: a list of methods a class promises to provide.
interface Swimmer { void swim(); // implicitly public and abstract } class Duck extends Animal implements Swimmer { ... }
Why both tools?
| Abstract class | Interface | |
|---|---|---|
| Fields with state | yes | no (only constants) |
| Method bodies | yes | only default methods |
| How many can a class have | one (extends) | many (implements A, B) |
| Relationship | is-a | can-do |
Rule of thumb: shared state and code → abstract class. A capability many unrelated classes can have (Comparable, Swimmer, Serializable) → interface. Interface methods are public, so implementations must say public too.
Quiz
A class needs to inherit shared fields from Animal AND promise the capabilities Swimmer and Flyer. Which declaration works?
Code exercise · java
Your turn. Define an interface Instrument with one method play(). Piano prints `plink` and Drum prints `boom`. Loop over the Instrument[] and play each. This is polymorphism through an interface: the loop only knows the contract.