Concepts / Abstract Methods and Interfaces

Abstract Methods and Interfaces

A default method is declared inside an interface with the modifier default and carries a working implementation.

  • Programming

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?

  • Compilation fails because FileSource did not write readLine()

  • The default body of readLine() in Readable runs, and it calls the readChar() body that FileSource supplied

  • readLine() does nothing and returns nothing

Reveal answer
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.

java
Notes on the code
  • grade() is a default method: it has the default modifier and a body
  • points() has no body, so it is abstract and Student must supply it
  • Student stores pts itself; the interface never reads pts
Worked example

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.

  1. 1
    Step 1: find grade()

    Student does not declare grade(), so the call uses the version inherited from Scorable.

  2. 2
    Step 2: run the default body

    The body of grade() starts. It needs a value, so it calls points().

  3. 3
    Step 3: resolve points()

    points() is abstract in Scorable, so the call runs Student's version, which returns pts, which is 72.

  4. 4
    Step 4: test the condition

    72 is at least 50, so the if statement returns "pass" and the body stops.

Result

The program prints pass.

StepWhich code runsValue in playOutcome
1Caller invokes grade() on ss is a Student with pts 72Search begins for grade()
2Scorable default body of grade()No local value yetCalls points()
3Student body of points()pts is 72Returns 72 to grade()
4Scorable default body continues72 compared with 50Returns "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.

Pattern
default return-type method-name(parameters) { implementation }
java
Notes on the code
  • points() ends with a semicolon and has no body, so it is abstract
  • grade() has the default modifier and a body
  • bonus() 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.

obj.grade() callDoes the classdeclare grade()?Run the class's owngrade()Run the interfacedefault bodyyesno
When a method is called on an object, does Java run the interface's default body or the class's own override?
java
Output
honours
Notes on the code
  • 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
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.

CallerFileSource objectreadLine default bodyFileSource readCharbody1. readLine()2. runs inherited default3. readChar()4. returns character
When a default method calls an abstract method, which class's implementation actually executes at runtime?

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.

Report classLoggable interface:log()Savable interface:save()implementsimplements
How do the default methods from several interfaces combine on one class?

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.

java
Output
Report instances can call log() and save() without writing either body.
Notes on the code
  • 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 like
    interface Scorable { String grade() { return "pass"; } }
    Why it fails

    Without default, a method in an interface is abstract and cannot carry a body.

    Do this instead
    interface Scorable { default String grade() { return "pass"; } }
  • Common mistake

    Expecting a default method to read a field of the implementing class

    Why it fails

    Interfaces have no instance variables, so a default body has no per-object field to read.

    Do this instead

    Call 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 like

    Honours overrides grade(), then grade() is called on a Honours object.

    Why it fails

    A class's own version takes priority over the inherited default.

    Do this instead

    Check 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

MEDIUM

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 calls points(), 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.