Abstract Methods and Interfaces
A default method is declared inside an interface with the modifier default and carries a working implementation.
Predicting a Call to a Default Method
Until Java 8, an interface could only declare methods without bodies. Any class that implemented the interface had to supply a body for every one of them. The default method changed that rule. A default method is a method declared inside an interface that comes with its own working implementation. Before learning the rules, it helps to make a prediction about how one behaves.
What do you think happens?
An interface named Readable declares an abstract method readChar() and a default method readLine(). A class named FileSource implements Readable, provides a body for readChar(), and says nothing about readLine(). What happens when a caller invokes readLine() on a FileSource object?
Reveal answer
The default body of readLine() in Readable runs, and it calls the readChar() body that FileSource supplied.
FileSource inherits readLine() from the interface, so it does not need its own copy. The inherited body calls readChar(), which is abstract in the interface, so the call reaches the code FileSource wrote. The interface now carries working code, not only a promise of code.
Keep that surprise in mind. The rest of this article explains the rules behind it: how a default method is declared, how a class inherits or overrides it, why its body can reach abstract methods but not instance variables, and how several interfaces can contribute behavior to one class.
Tracing a Default Method Call Step by Step
The following interface and classes are an original example, not the Readable example from the source. The interface Scorable has one abstract method, points(), and one default method, grade(). The default method's body calls points(), which the implementing class must provide.
grade()is a default method: it has the default modifier and a bodypoints()has no body, so it is abstract and Student must supply it- Student stores pts itself; the interface never reads pts
Tracing s.grade() when pts is 72
Student s = new Student(72); then the program calls s.grade(). Trace what runs and what is returned.
- 1Step 1: find grade()
Student does not declare
grade(), so the call uses the version inherited from Scorable. - 2Step 2: run the default body
The body of
grade()starts. It needs a value, so it callspoints(). - 3Step 3: resolve points()
points()is abstract in Scorable, so the call runs Student's version, which returns pts, which is 72. - 4Step 4: test the condition
72 is at least 50, so the if statement returns "pass" and the body stops.
The program prints pass.
| Step | Which code runs | Value in play | Outcome |
|---|---|---|---|
| 1 | Caller invokes grade() on s | s is a Student with pts 72 | Search begins for grade() |
| 2 | Scorable default body of grade() | No local value yet | Calls points() |
| 3 | Student body of points() | pts is 72 | Returns 72 to grade() |
| 4 | Scorable default body continues | 72 compared with 50 | Returns "pass" |
Execution trace of s.grade() for a Student whose pts is 72
Declaring a Default Method
A default method is written in the body of an interface and follows a fixed pattern. The word default must appear in the declaration. This keyword is the element that separates a default method from an ordinary interface method. Without it, a method in an interface is abstract and has no body. The access modifier public is allowed but optional, because everything declared in an interface is automatically public. The return type, method name, and parameter list follow the same conventions as any other method, and the body is a block in braces that holds the implementation.
default return-type method-name(parameters) { implementation }points()ends with a semicolon and has no body, so it is abstractgrade()has the default modifier and a bodybonus()shows that public may be written explicitly without changing the meaning
Inheriting Versus Overriding a Default
A class that implements an interface with default methods has two choices for each default method. It can leave the method alone, in which case it inherits the interface's version, the same way a subclass receives an ordinary method from a parent class. Or it can write its own body, which overrides the interface's version. When the class writes its own version, the class's version takes priority. The class is never forced to write a default method, because the interface already supplies a body.
honours- Honours overrides
grade(), so the class's version takes priority points()is still required, and it is supplied here
What do you think happens?
Given Honours from the previous code, what does new Honours().grade() return?
Reveal answer
It returns "honours".
Honours declares its own grade(), so the flowchart takes the yes branch. The interface default body, which would have compared points() with 50, is not used.
Why a Default Method Can Call Abstract Methods
A default method is allowed to call the abstract methods declared in its own interface. In the Readable example, readLine() calls readChar(), which has no body in the interface. The call is valid because every concrete class that implements Readable must supply readChar(). That guarantee means the call always reaches real code at run time. The implementing class fills in the missing piece, and the default body supplies the rest.
The diagram shows the key point. The default body does not contain the code that reads a character. It calls readChar(), and the object's class supplies that code. This is why the interface can use abstract methods without knowing how they are implemented.
Mixing Behavior From Several Interfaces
Other languages offer a feature called a mixin, which lets a class take in functionality from another source. Default methods give Java a similar capability. Because a class can implement several interfaces, it can gather behavior from several separately defined sources. The result is not full multiple inheritance, because interfaces still store no instance variables. A class that inherits from several interfaces gains behavior but gains no additional stored fields from them.
In the diagram, Report receives a log() behavior from one interface and a save() behavior from another. Neither interface needs to know about the other, and Report does not have to write either body unless it wants a different one. Each interface contributes its own default body, and the class can override either of them independently.
Report instances can call log() and save() without writing either body.- Report's body is empty, yet it gains both behaviors
- The two interfaces do not refer to each other
A functional interface is an interface with a single abstract method. The source notes that it may also include default methods alongside that one abstract method. The abstract method is still the only one an implementer must supply, because default methods already have bodies. A functional interface can therefore offer helper behavior built on its single required method without making every implementer write that helper.
Mistakes With Default Methods
Common mistake Leaving out the default keyword on a method that has a body
What it looks likeinterface Scorable { String grade() { return "pass"; } }Why it failsWithout default, a method in an interface is abstract and cannot carry a body.
Do this insteadinterface Scorable { default String grade() { return "pass"; } }Common mistake Expecting a default method to read a field of the implementing class
Why it failsInterfaces have no instance variables, so a default body has no per-object field to read.
Do this insteadCall an abstract method such as points() and let the implementing class return its own value.
Common mistake Assuming the interface default always runs
What it looks likeHonours overrides grade(), then grade() is called on a Honours object.
Why it failsA class's own version takes priority over the inherited default.
Do this insteadCheck whether the class declares the method before predicting which body runs.
Common mistake Believing every class must write the default method because the method is in an interface
Practice Tracing an Override
Using the Scorable interface from the earlier example, a class Pass implements Scorable with points() returning 40 and no grade() method. Then a class Bonus implements Scorable with points() returning 40 and an overriding grade() that returns "bonus". Predict the output of new Pass().grade() and new Bonus().grade(), then trace each call through the flowchart.
Hints
- Check first whether the class declares
grade(). - If Pass has no
grade(), the interface body runs and callspoints(), which returns 40. - Compare 40 with 50 in the default body.
Key Takeaways
- A default method is declared in an interface with the default modifier and carries a working implementation; without default, an interface method is abstract and has no body.
- An implementing class inherits a default method unless it overrides it, and the class's own version takes priority when it does.
- A default method can call abstract methods in its interface because every concrete implementer must supply them, but it cannot use instance variables because interfaces hold none.
- Because a class can implement several interfaces, it can combine default behaviors defined separately, though this is not full multiple inheritance since no instance fields are gained.