Defining and Implementing Interfaces
Java does not support multiple inheritance, a deliberate choice to keep the language reasonably simple.
A Class With Two Parents
Imagine you want one class to pick up behavior from two different parent classes at the same time. Many programmers expect a language to let you do this. Java does not. A class in Java cannot be built directly from more than one parent. This article explains why that restriction exists, and how Java still lets a class take on several sources of behavior through a separate feature called interfaces.
What do you think happens?
Can a single Java class extend two other classes directly?
Reveal answer
No, a class can extend only one other class
Java does not support multiple inheritance. A class in Java cannot be built directly from more than one parent. Interfaces are the mechanism Java provides to reach many of the same goals.
Why Java Left Out Multiple Inheritance
The restriction is a deliberate design choice. The designers of Java wanted to keep the language reasonably simple. They judged that the benefits of multiple inheritance were not worth the extra complexity it would add to the language as a whole. The source is careful to say this is a trade-off, not a claim that multiple inheritance is useless. A feature that is useful in some situations was left out because of what it would cost everywhere else.
Java's refusal of multiple inheritance is a judgment about trade-offs. The goal behind the feature is still valuable, which is why Java provides another route to it.
Keeping the Goals Without the Mechanism
Java does not give up on the goals behind multiple inheritance. Instead it provides a separate feature, interfaces, that can accomplish many of the same goals. Because an interface is a different mechanism from class inheritance, a program can work toward those goals without bringing back the full complexity the designers wanted to avoid. The key point is that the goal is preserved while the mechanism is different.
It helps to think of the two ideas as a starting point and a path. Multiple inheritance is the starting idea. Java rules out the direct version of it, but interfaces offer a route toward many of the same outcomes.
Tracing an Interface Gap Being Filled
An interface lists method headers without giving their bodies. That leaves a gap, and something has to fill it. The class that fills the gap is the one that implements the interface. The example below is an original illustration written for this article, not the source's own code. It shows a Strokeable interface with one method header and a Line class that fills that gap.
- The class header names the interface it promises to satisfy.
- The
stroke()method is the method the interface requires, and the class supplies its body.
Drawing a line of length 5What Happens When the Method Is Missing
What do you think happens?
Imagine a version of Line where stroke() is left out entirely. Would the class still count as a concrete class that implements Strokeable?
Reveal answer
No, the class does not meet the interface's requirements
The source is explicit that both the implements clause and the method implementations are required. Omitting the method means the class does not meet the interface's requirements. The method is a requirement, not an option.
public class Line implements Strokeable {
private int length;
}The header promises Strokeable, but the stroke() method is missing, so the class does not meet the interface.
public class Line implements Strokeable {
private int length;
@Override
public void stroke() {
System.out.println("Drawing a line");
}
}The header and the required method are both present, so the class satisfies the interface.
The Two Requirements a Class Must Meet
The source is explicit that writing the methods is not enough by itself. A class has to meet two separate conditions, and each condition does a different job. The two conditions are examined one at a time below.
Writing the Class Header
One Superclass, Many Interfaces
A class can extend one other class and implement any number of interfaces. The source gives the header FilledCircle extends Circle implements Strokeable, Fillable as a valid example. The diagram below shows which parts of the class come from which source. The superclass supplies one line of inheritance, and each interface contributes its own required methods.
Locating the Source of a Failure
When a class fails to compile against an interface, the fastest way to find the cause is to check the two requirements in order. The flowchart below follows that order. Start at the class header, then check the method definitions. The first check that fails tells you where to look.
Mistakes Beginners Make
Common mistake Assuming a class can extend two classes because it can implement two interfaces
What it looks likeclass FilledCircle extends Circle, Shape
Why it failsExtending is limited to one other class. Implementing is not limited in the same way.
Do this insteadExtend exactly one class and list the interfaces after implements.
Common mistake Writing the implements clause but leaving out the method
Why it failsThe source states that omitting either requirement means the class does not meet the interface.
Do this insteadDefine every instance method the interface declares.
Common mistake Writing the method without naming the interface in the header
Why it failsThe header is the promise. Without implements, the class does not state that it satisfies the interface.
Do this insteadAdd implements followed by the interface name to the class header.
Where Programmers Meet Interfaces
Interfaces appear in many places beyond code you write yourself. The source notes that interfaces can be much more complicated than a single method and that they have many uses, including important ones in Java's standard packages. You will often meet interfaces in library code and frameworks, where a class you did not write must implement a set of methods so that other code can call it.
Functional Interfaces as a Special Case
A functional interface specifies a single method. The source notes that you have already met one special kind of interface: functional interfaces were introduced earlier in connection with lambda expressions. The single-method requirement is what makes a functional interface the right shape to pair with a lambda, since a lambda expression can stand in for that one method.
A functional interface is a particular case, not the whole story. Every functional interface is an interface, but not every interface is functional. General interfaces can declare several methods.
Key Takeaways
- Java does not support multiple inheritance, a deliberate trade-off made to keep the language reasonably simple.
- Interfaces let Java pursue many of the same goals as multiple inheritance through a different mechanism.
- A class implements an interface by using implements in its header and by defining every instance method the interface declares; both requirements are needed.
- A class can extend one other class and implement any number of interfaces, and a failure can be traced by checking the header first and then the methods.
- A functional interface, with its single method, is one special case of the broader idea of an interface.