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

JavaInheritanceInterfaceJava 8Abstract

Java Problem Overview


I am not asking this -> Why is there no multiple inheritance in Java, but implementing multiple interfaces is allowed?

In Java, multiple inheritance isn't allowed, but, after Java 8, Interfaces can have default methods (can implement methods itself), just like abstract classes. Within this context, it multiple inheritance should also be allowed.

interface TestInterface 
{ 
    // abstract method 
    public void square(int a); 
  
    // default method 
    default void show() 
    { 
      System.out.println("Default Method Executed"); 
    } 
} 

Java Solutions


Solution 1 - Java

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.

Solution 2 - Java

The language designers already thought about that, so these things are enforced by the compiler. So if you define:

interface First {
    default void go() {
    }
}

interface Second {
    default void go() {
    }
}

And you implement a class for both interfaces:

static class Impl implements First, Second {

}

you will get a compilation error; and you would need to override go to not create the ambiguity around it.

But you could be thinking that you can trick the compiler here, by doing:

interface First {
    public default void go() {
    }
}

static abstract class Second {
    abstract void go();
}

static class Impl extends Second implements First {
}

You could think that First::go already provides an implementation for Second::go and it should be fine. This is too taken care of, thus this does not compile either.

> JLS 9.4.1.3 : Similarly, when an abstract and a default method with matching signatures are inherited, we produce an error. In this case, it would be possible to give priority to one or the other - perhaps we would assume that the default method provides a reasonable implementation for the abstract method, too. But this is risky, since other than the coincidental name and signature, we have no reason to believe that the default method behaves consistently with the abstract method's contract - the default method may not have even existed when the subinterface was originally developed. It is safer in this situation to ask the user to actively assert that the default implementation is appropriate (via an overriding declaration).

The last point I would bring in, to solidify that multiple inheritance is not allowed even with new additions in java, is that static methods from interfaces are not inherited. static methods are inherited by default:

static class Bug {
    static void printIt() {
        System.out.println("Bug...");
    }
}

static class Spectre extends Bug {
    static void test() {
        printIt(); // this will work just fine
    }
}

But if we change that for an interface (and you can implement multiple interfaces, unlike classes):

interface Bug {
    static void printIt() {
        System.out.println("Bug...");
    }
}

static class Spectre implements Bug {
    static void test() {
        printIt(); // this will not compile
    }
}

Now, this is prohibited by the compiler and JLS too:

> JLS 8.4.8 : A class does not inherit static methods from its superinterfaces.

Solution 3 - Java

Java doesn't allow multiple inheritance for fields. This would be difficult to support in the JVM as you can only have references to the start of an object where the header is, not arbitrary memory locations.

In Oracle/Openjdk, objects have a header followed by the fields of the most super class, then the next most super class, etc. It would be a significant change to allow the fields of a class to appear at different offsets relative to the header of an object for different subclasses. Most likely object references would have to become a reference to the object header and a reference to the fields to support this.

Solution 4 - Java

default methods in interfaces pose a problem that :

> If both of the implemented interfaces define a default method with > same method signature, then the implementation class does not know > which default method to use.

The implementation class should define explicitly specify which default method to use or define it's own one.

Thus default methods in Java-8 do not facilitate multiple inheritance. The main motivation behind default methods is that if at some point we need to add a method to an existing interface, we can add a method without changing the existing implementation classes. In this way, the interface is still compatible with older versions. However, we should remember the motivation of using Default Methods and should keep the separation of interface and implementation.

Solution 5 - Java

That is mostly related to "diamonds problem" i think. Right now if you implement multiple interfaces with the same method, compiler forces you to override method the one you want to implement, because it don't know which on to use. I guess Java creators wanted to remove this problem back when interfaces couldn't use default methods. Now they came up with idea, that is good to be able to have methods with implementation in interfaces, as you can still use those as functional interfaces in streams / lambda expressions and utilize their default methods in processing. You cannot do that with classes but diamond problem still exist there. That is my guess :)

Solution 6 - Java

The main issues with multiple inheritance are ordering (for overriding and calls to super), fields and constructors; interfaces don't have fields or constructors, so they don't cause problems.

If you look at other languages they usually fall in two broad categories:

  1. Languages with multiple inheritance plus a few features to disambiguate special cases: virtual inheritance [C++], direct calls to all superconstructors in the most-derived class [C++], linearization of superclasses [Python], complex rules for super [Python], etc.

  2. Languages with a differente concept, usually called interfaces, traits, mixins, modules, etc. that impose some limitations such as: no constructors [Java] or no constructors with parameters [Scala until very recently], no mutable fields [Java], specific rules for overriding (e.g. mixins take precedence over base classes [Ruby] so you can include them when you need a bunch of utility methods), etc. Java has become a language like these.

Why just by disallowing fields and constructors you solve many issues related to multiple inheritance?

  • You can't have duplicated fields in duplicated base classes.
    • The main class hierarchy is still linear.
  • You can't construct your base objects the wrong way.
    • Imagine if Object had public/protected fields and all subclasses had constructors setting those fields. When you inherit from more than one class (all of them derived from Object), which one gets to set the fields? The last class? They become siblings in the hierarchy, so they know nothing about each other. Should you have multiple copies of Object to avoid this? Would all classes interoperate correctly?
  • Remember that fields in Java are not virtual (overridable), they are simply data storage.
    • You could make a language where fields behave like methods and could be overridden (the actual storage would be always private), but that would be a much bigger change and problably wouldn't be called Java anymore.
  • Interfaces can't be instantiated by themselves.
    • You should always combine them with a concrete class. That eliminates the need for constructors and makes the programmer's intent clearer too (that is, what is meant to be a concrete class and what's an accessory interface/mixin). This also provides a well-defined place to solve all ambiguities: the concrete class.

Solution 7 - Java

JAVA DOES SUPPORT MULTIPLE INHERITANCE. If you make a OVERALL COMPARISON OF THE PROGRAMMING LANGUAGE,JAVA,THEN YOU COME TO KNOW THAT I AM TRUE.

Java's topclass or the root class in the Ancestor Hierarchy is the Object class. This class is a Superclass of all other classes. Hence, each class in Java that we declare or is predefined in the API itself inherits this Object class.

Moreover, Java provides us to inherit one more class of our choice.

Hence, we can say that we are performing INTERLOCKED BUT MULTIPLE INHERITANCE.

2ND Way

Java supports Multiple Inheritance of Interfaces. So you can use as many interface implementations you want. But note, implementing an interface does not define IS A relationship as in case of Inheritance of Classes is possible.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAsankaView Question on Stackoverflow
Solution 1 - JavadavidxxxView Answer on Stackoverflow
Solution 2 - JavaEugeneView Answer on Stackoverflow
Solution 3 - JavaPeter LawreyView Answer on Stackoverflow
Solution 4 - JavaS.K.View Answer on Stackoverflow
Solution 5 - JavaMershelView Answer on Stackoverflow
Solution 6 - JavamarcusView Answer on Stackoverflow
Solution 7 - JavaKrish JaiswalView Answer on Stackoverflow