How Does Java 8' New Default Interface Model Works (Incl. Diamond, Multiple Inheritance, and Precedence)

How does Java 8' new default interface model works (incl. diamond, multiple inheritance, and precedence)?

Here is a detailed explanation for Java 8' new interface model & the diamond problem of multiple inheritance.

As you might see in this examples, starting with JDK 8, Java
has introduced a kind of multiple inheritance as both, the
class and its interface might contain an
implementation of the same method (same name
& signature). To address the diamond
problem there is a precedence in which order an
implementation is used: only if the class implements all default / optional methods of its
interfaces, the code can be compiled and the implementations of this
class are used. Otherwise the compiler tries to patch the
missing implementation(s) with interface's default
implementation
. And if there are multiple default implementations
of a method, then the diamond
problem occurs and the compiler rejects the compilation.
Java 8' new interfaces model is the result of
approaching backwards compatibility, i. e. to keep
existing code that was written against pre Java 8 interfaces
compilable.

Multiple Inheritance Ambiguity with Interface

The diamond problem only applies to implementation inheritance (extends in all versions of Java prior to Java 8). It doesn't apply to API inheritance (implements in all versions of Java prior to Java 8).

Since interface methods with matching type signatures are compatible, there is no diamond problem if you inherit the same method signature twice: matching method signatures simply coalesce instead. (And if the type signatures aren't the same, then you don't have the diamond problem either.)

In Java 7 and below, the only way to inherit implementation code was via the extends keyword, which restricts to at most one parent. Therefore there is no multiple implementation inheritance and the diamond problem does not exist.

Java 8 adds a new wrinkle because it allows interfaces to have implementation code. It still escapes the diamond problem by simply falling back to the previous behavior (no implementation inheritance) when you're implementing multiple interfaces with methods that have matching signatures.

Doesn't Default in Java 8 destroy the whole idea of not allowing us to do multiple inheritance?

Can someone help me understand why they would add Default in Java 8 to
allow implementation to interfaces instead of just allowing us to have
multiple inheritance in abstract classes?

One important reason is super class state. For example;

class OpticalDrive {

}

class DVDDrive extends OpticalDrive {
protected int speed = 5;
}

class CDDrive extends OpticalDrive {
protected int speed = 10;
}

class ComboDrive extends DVDDrive, CDDrive {
ComboDrive() {
System.out.println(super.speed);
super.speed = 15;
}
}

In above hypothetical example speed state variable is multiple inherited and reading or modifying it creates ambiguity as to which one must be modified.

What exactly is the difference between just allowing us to extend
multiple classes verses allowing us to create Default methods in
interfaces?

Since interfaces can't have mutable state variables it is better to have default methods in interfaces rather than enabling multiple inheritance of abstract classes. Following example shows Java 8 default method in interface in action.

public interface DvdReader {
default public void read() {
System.out.println("DvdReader.read()");
}
}

public interface CdReader {
default public void read() {
System.out.println("CdReader.read()");
}
}

public class ComboReader implements CdReader, DvdReader {
public void read() {
CdReader.super.read();
DvdReader.super.read();
}

public static void main(String[] args) {
new ComboReader().read();
}
}

In the above scenario if you ignore overriding read method in ComboReader, the compiler will complain with the following error.

ComboReader.java:1: error: class ComboReader inherits unrelated defaults for read() from types CdReader and DvdReader
public class ComboReader implements CdReader, DvdReader {
^
1 error

Furthermore enabling multiple abstract class inheritance means the syntax of Java code has to change significantly causing java's ability to backward compatibility.

What happens, if two interfaces contain the same default method?

You cannot implement multiple interfaces having same signature of
Java 8 default methods (without overriding explicitly in child class)

. You can solve it by implementing the method E.g.

class MyClass implements alpha, beta {
void display() {
System.out.println("This is not default");
}

@Override
public void reset() {
//in order to call alpha's reset
alpha.super.reset();
//if you want to call beta's reset
beta.super.reset();

}
}

Why does Java not allow multiple inheritance but does allow conforming to multiple interfaces with default implementations

Things are not so simple.

If a class implements multiple interfaces that defines default methods with the same signature the compiler will force you to override this method for the class.

For example with these two interfaces :

public interface Foo {
default void doThat() {
// ...
}
}

public interface Bar {
default void doThat() {
// ...
}
}

It will not compile :

public class FooBar implements Foo, Bar{
}

You should define/override the method to remove the ambiguity.

You could for example delegate to the Bar implementation such as :

public class FooBar implements Foo, Bar{    
@Override
public void doThat() {
Bar.super.doThat();
}
}

or delegate to the Foo implementation such as : :

public class FooBar implements Foo, Bar {
@Override
public void doThat() {
Foo.super.doThat();
}
}

or still define another behavior :

public class FooBar implements Foo, Bar {
@Override
public void doThat() {
// ...
}
}

That constraint shows that Java doesn't allow multiple inheritancy even for interface default methods.


I think that we cannot apply the same logic for multiple inheritances because multiples issues could occur which the main are :

  • overriding/removing the ambiguity for a method in both inherited classes could introduce side effects and change the overall behavior of the inherited classes if they rely on this method internally. With default interfaces this risk is also around but it should be much less rare since default methods are not designed to introduce complex processings such as multiple internal invocations inside the class or to be stateful (indeed interfaces cannot host instance field).
  • how to inherit multiple fields ? And even if the language allowed it you would have exactly the same issue as this previously quoted : side effect in the behavior of the inherited class : a int foo field defined in a A and B class that you want to subclass doesn't have the same meaning and intention.

Multiple Inheritance :Java vs C++

Java (unlike C++) does not allow multiple inheritance of state and, therefore, does not suffer from a diamond problem.

It allows multiple inheritance of type through interfaces (a class can implement multiple interfaces).

Starting with Java 8 there is also multiple inheritance of behavior through default methods in interfaces.

Why interface methods have no body

Because Java, in contrast to languages like C++ or Eiffel, only has multiple inheritance of types (i.e. interfaces as well as one class), not multiple inheritance of state and behaviour. The latter of which add enormous complexity (especially state).

The Java designers (and C#, for that matter) opted to not include it as it presented C++ programmers often with very hard to debug issues. You can solve pretty much most problems that require true multiple inheritance with implementing multiple interfaces, so the tradeoff was deemed worth it.

Note that multiple inheritance of behaviour (not state) might come to Java 8 (unless they postpone it again like one of the many other things) in form of virtual extension methods where an interface can declare a method that delegates to one in another class, which then exists on all types that implement that interface.



Related Topics



Leave a reply



Submit