OCA Java SE 8 Class Design - Java Interface default Method








Java 8 introduced a new type of method to an interface, referred to as a default method.

A default method is a method defined within an interface with the default keyword in which a method body is provided.

A default method within an interface defines a method with a default implementation.

Classes have the option to override the default method if they need to, but they are not required to.

If the class doesn't override the method, the default implementation will be used.

The following is an example of a default method defined in an interface:

public interface Printable { 
  boolean hasScales(); 
  public default double getTemperature() { 
    return 10.0; 
  } 
}

The code above defines two interface methods, one is a normal abstract method and the other a default method.

Both methods are assumed to be public, as all methods of an interface are all public.

The first method is terminated with a semicolon and doesn't provide a body, whereas the second default method provides a body.

Any class that implements Printable may rely on the default implementation of getTemperature() or override the method and create its own version.

Because all methods within an interface are assumed to be public, the access modifier for a default method is therefore public.

A default method may only be declared within an interface and not within a class or abstract class.

A default method must be marked with the default keyword.

If a method is marked as default, it must provide a method body.

A default method is not assumed to be static, final, or abstract, as it may be used or overridden by a class that implements the interface.

A default method is assumed to be public and will not compile if marked as private or protected.

For example, the following code snippets will not compile:

public interface Printable { 
  public default void cutPaste();  // DOES NOT COMPILE 
  public int getPage() {  // DOES NOT COMPILE 
    return 13; 
  } 
} 

cutPaste() doesn't compile because it is marked as default but doesn't provide a method body.

getPage() doesn't compile because it provides a method body without the default keyword.





Note

The default methods cannot be marked as static and require an instance of the class implementing the interface.

They cannot be marked as final or abstract, because they are allowed to be overridden in subclasses but are not required to be overridden.

When an interface extends another interface with a default method, it may choose to ignore the default method, and the default implementation for the method will be used.

Or, the interface may override the definition of the default method with method overriding.

Finally, the interface may redeclare the method as abstract, requiring classes that implement the new interface to explicitly provide a method body.

For example, the following class overrides one default interface method and redeclares a second interface method as abstract:

public interface Printable { 
  public default int getPageNumber() { 
    return 4; 
  } 
  public default double getPageWidth() { 
    return 20.0; 
  } 
  public default boolean getPageScale() { 
    return true; 
  } 
} 

public interface WebPrintable extends Printable { 
  public default int getPageNumber() { 
    return 8; 
  } 
  public double getPageWidth(); 
  public boolean getPageScale() {  // DOES NOT COMPILE 
    return false; 
  } 
} 

Printable defines three default methods: getPageNumber(), getPageWidth(), and getPageScale().

The second interface, WebPrintable, extends Printable and overrides the default method getPageNumber() with a new method that returns a different value.

Next, the WebPrintable interface replaces the default method getPageWidth() with a new abstract method, forcing any class that implements the WebPrintable interface to provide an implementation of the method.

Finally, the WebPrintable interface overrides the getPageScale() method but doesn't mark the method as default.

Since interfaces may only contain methods with a body that are marked as default, the code will not compile.





Default Methods and Multiple Inheritance

What value would the following code output?

interface Walk { 
  public default int getSpeed() { 
    return 5; 
  } 
} 

interface Run { 
  public default int getSpeed() { 
    return 10; 
  } 
} 

class Cat implements Walk, Run {  // DOES NOT COMPILE 
  public static void main(String[] args) { 
    System.out.println(new Cat().getSpeed()); 
  } 
} 

If a class implements two interfaces that have default methods with the same name and signature, the compiler will throw an error.

If the subclass overrides the duplicate default methods, the code will compile without issue.

For example, the following modified implementation of Cat will compile and output 1:

public class Cat implements Walk, Run {   
  public int getSpeed() { 
    return 1; 
  } 

  public static void main(String[] args) { 
    System.out.println(new Cat().getSpeed()); 
  } 
} 

Static Interface Methods

Java 8 includes support for static methods within interfaces.

These methods are defined explicitly with the static keyword and function nearly identically to static methods defined in classes.

A static method defined in an interface is not inherited in any classes that implement the interface.

Like all methods in an interface, a static method is assumed to be public and will not compile if marked as private or protected.

To reference the static method, a reference to the name of the interface must be used.

The following is an example of a static method defined in an interface:

public interface Printable { 
  static int getHeight() { 
    return 8; 
  } 
} 

getHeight() works like a static method as defined in a class.

It can be accessed without an instance of the class using the Printable.getHeight() syntax.

The compiler will automatically insert the access modifier public since all methods in interfaces are assumed to be public.

The following is an example of a class Dog that implements Printable:

public class Dog implements Printable { 
  public void printDetails() { 
    System.out.println(getHeight()); // DOES NOT COMPILE 
  } 
} 

Without an explicit reference to the name of the interface the code will not compile, even though Dog implements Printable.

In this manner, the static interface methods are not inherited by a class implementing the interface.

The following modified version of the code resolves the issue with a reference to the interface name Printable:

public class Dog implements Printable { 
  public void printDetails() { 
    System.out.println(Printable.getHeight()); 
  } 
} 

A class that implements two interfaces containing static methods with the same signature will still compile at runtime, because the static methods are not inherited by the subclass and must be accessed with a reference to the interface name.