Interfaces
What you'll learn:
- describe an ability with an interface and implement it in classes with
implements; - explain when a
defaultmethod runs and choose between an interface and an abstract class; - create a fixed set of values with
enumand handle it in aswitch; - describe immutable data in one
recordline and compare records withequals.
Picture a job ad: "Courier wanted. Must be able to deliver a parcel." The ad does not say who the courier must be. A student on a bicycle can take the job, so can a van driver, and even a drone: anyone who can do what is listed fits.
The person who sends the parcel does not care who comes for it either. They tell the courier "deliver", and how to deliver is up to the courier.
Why does a program need this? In the previous theme, the common buttons of classes came from a parent. But a cyclist and a drone share nothing except the ability to deliver: no common fields, no common ancestor. Besides, a class can have only one parent. For an ability that quite different classes can have, Java has the interface:
public class Main {
public static void main(String[] args) {
Courier c = new Cyclist();
c.deliver("book"); // Cyclist brings book
}
}
interface Courier { void deliver(String parcel); }
class Cyclist implements Courier {
public void deliver(String parcel) {
System.out.println("Cyclist brings " + parcel);
}
}Let's go through the program step by step:
interface Courieris the job ad. Its braces hold only thedeliverheader, with a semicolon instead of a body: the interface says what to do, not how.class Cyclist implements Couriermeans the cyclist takes this job. The wordimplementspromises that the class has every method of the interface.- Inside
Cyclist, thedelivermethod is written in full, with a body. Courier c = new Cyclist();declares a variable of typeCourierand puts a reference to aCyclistobject into it.c.deliver("book")runs the cyclist's method and printsCyclist brings book.
Interfaces and implements
An interface is a type that lists methods but does not write their bodies. You have already met methods without a body in abstract classes: in an interface they are abstract too. A class implements an interface when it writes each of its methods, and it says so with the word implements.
What matters about an interface:
- a method without a body in an interface is always
public, even when the word is not written, so the class declares itpublictoo; - you cannot create an object of an interface: for
new Courier()the compiler answersCourier is abstract; cannot be instantiated; - the compiler checks that the class has written every method of the interface, and if even one is missing, the program does not compile.
Here is what javac says about a Cyclist class that forgot the deliver method:
error: Cyclist is not abstract and does not override abstract method deliver(String) in CourierThe start of the message, is not abstract, is no accident: an abstract class from the previous theme may leave a method to its subclasses. An ordinary class must write everything.
You can put @Override above such methods, as in the previous theme. Then the compiler checks that a method with that header really exists in the interface.
Several interfaces
One person can work both as a courier and as a photographer. In the same way, a class can implement any number of interfaces: you list them after implements, separated by commas. A drone can both deliver and take pictures from above:
interface Camera { String photo(); }
class Drone implements Courier, Camera {
public void deliver(String parcel) {
System.out.println("Drone drops " + parcel);
}
public String photo() {
return "view from above";
}
}A class still has only one parent through extends, and as many interfaces as it needs. When there are both, extends comes first and implements second: class Van extends Vehicle implements Courier, Camera.
Interviewers like to ask this: does Java have multiple inheritance? The answer: a class extends only one class but can implement several interfaces.
A variable of an interface type
The variable Courier c works like the universal remote from the previous theme: its type decides which buttons exist, and the object decides what they do. A variable of type Courier can hold an object of any class that implements Courier:
Courier first = new Cyclist();
Courier second = new Drone();
first.deliver("pizza"); // Cyclist brings pizza
second.deliver("pizza"); // Drone drops pizzaLet's go through it line by line:
firstholds a cyclist andsecondholds a drone, but both variables have the same type:Courier.first.deliver("pizza")runs the method of theCyclistclass.second.deliver("pizza")is written the same way, but another object does the work: the method of theDroneclass runs.
The Courier remote has one button, deliver. That is why second.photo() does not compile, even though second holds a drone: the compiler answers cannot find symbol. To take a photo, you need a variable of type Camera.
Here the job-ad picture is not exact. A real employer may hire someone who can do only half the work, hoping they will learn. The compiler does not do that: a class gets the job only if it can do everything listed.
Common mistake
The class forgot to write public before an interface method:
class Cyclist implements Courier {
void deliver(String parcel) { // ✗
System.out.println("Cyclist brings " + parcel);
}
}error: deliver(String) in Cyclist cannot implement deliver(String) in CourierThe program does not compile. The interface method is public, while a method with no modifier is seen only by the classes of its package. A class cannot narrow the access the interface promised. javac explains this on the next line: attempting to assign weaker access privileges; was public. Add public before void deliver.
Key points
- An interface lists methods without bodies, and a class implements it with
implementsand writes each method itself, aspublic. - If a class has not written even one method of the interface, the program does not compile.
- A class has one parent through
extends, but it can implement any number of interfaces. - A variable of an interface type takes an object of any class that implements it and lets you call only the interface's methods.