Inheritance and interfaces
Share behaviour with extends and implements, and know when composition is the better tool.
- Use extends when one class is a more specific kind of another.
- Use implements to promise an interface is fully provided.
- Mark replaced methods with @Override so mistakes surface.
- Prefer composition for has-a relationships over deep inheritance.
In plain English
Java has two ways to share behaviour between types: inheritance and interfaces. Inheritance means one class extends another, so the child class inherits the parent fields and methods and can add or change them; the @Override annotation marks a method that replaces a parent method. An interface is a contract of method signatures with no state, and a class uses implements to promise it provides every method the interface lists. An abstract class is a class you cannot create an instance of directly, used to hold shared code that subclasses must finish. Composition means building a class out of other classes instead of inheriting from them, and it is usually the safer choice when the relationship is a has-a rather than an is-a.
Step by step
- 1Create an abstract class with shared fields and one abstract method.
- 2Create a concrete class that extends it and implements the abstract method.
- 3Define an interface and have a class implement it.
- 4Annotate every overridden method with @Override.
- 5Build a class that holds another class to show composition.
abstract class Lesson {
private final String title;
Lesson(String title) {
this.title = title;
}
public String title() {
return title;
}
public abstract int minutes();
}
interface Scored {
int maxScore();
}
final class Quiz extends Lesson implements Scored {
Quiz(String title) {
super(title);
}
@Override
public int minutes() {
return 10;
}
@Override
public int maxScore() {
return 100;
}
}
class Module {
private final Lesson lesson;
Module(Lesson lesson) {
this.lesson = lesson;
}
public String title() {
return lesson.title();
}
}Common mistakes
- Extending a class just to reuse a method creates a fragile is-a relationship that composition would avoid.
- Forgetting @Override does not stop compilation, but it hides a typo in a method signature that was meant to replace a parent method.
- Trying to instantiate an abstract class fails to compile, because abstract classes exist to be extended, not created directly.
- Implementing an interface without providing every method it lists fails to compile, since the class has not honoured the contract.
Implement a printable lesson
Define an interface Printable with one method String display(), then make a VideoLesson class implement it and return its title plus its minutes.
interface Printable {
String display();
}
class VideoLesson {
private final String title;
private final int minutes;
VideoLesson(String title, int minutes) {
this.title = title;
this.minutes = minutes;
}
}What is the difference between an abstract class and an interface?
Make it yours.
Keep a private note for this lesson, then turn the key ideas into flashcards you can revisit.
Lock in what you just learned.
Mark this lesson complete to save your place and move one step closer to the certificate.