Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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"); 
    } 
} 
like image 734
Asanka Avatar asked Oct 03 '18 06:10

Asanka


People also ask

Is multiple inheritance of implementation allowed in Java?

The Java programming language supports multiple inheritance of type, which is the ability of a class to implement more than one interface. An object can have multiple types: the type of its own class and the types of all the interfaces that the class implements.

Why does Java allow multiple inheritance for interfaces?

Java allows multiple inheritance using interfaces. Interfaces could only define abstract methods, that is, methods without any implementation. So if a class implemented multiple interfaces with the same method signature, it was not a problem. The implementing class eventually had just one method to implement.

Do you think implementing multiple interfaces in a way facilitates multiple inheritance in Java?

Java does not support "multiple inheritance" (a class can only inherit from one parent class). However, it can be achieved with help of interfaces, because the class can implement multiple interfaces.

Why does Java not support multiple inheritance explain the diamond problem?

But remember that Java does not support the multiple inheritance because of the diamond problem. As simple inheritance allows a child class to derive properties from one super-class. for example, if class B inherits properties from only one super-class A, then it is called simple inheritance, and Java supports them.


6 Answers

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.
like image 108
davidxxx Avatar answered Oct 18 '22 00:10

davidxxx


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.

like image 39
Eugene Avatar answered Oct 18 '22 00:10

Eugene


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.

like image 28
Peter Lawrey Avatar answered Oct 17 '22 22:10

Peter Lawrey


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.

like image 42
S.K. Avatar answered Oct 18 '22 00:10

S.K.


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 :)

like image 26
Mershel Avatar answered Oct 17 '22 22:10

Mershel


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.
like image 26
marcus Avatar answered Oct 17 '22 22:10

marcus