One oft-talked advantage of Java over c++ is the lack of multiple inheritance in Java. Because subclasses in Java can only extend a single parent class, and although they can implement multiple interfaces, there are only abstract methods in the interface, the method body is empty, and there is no concrete method implementation, so there is no problem with method collisions.

Those are ancient terms, but with the release of Java 8 this year, you can define default Methods in interfaces as well. The reason to break the previous design and add concrete methods to the interface is to add new functionality to the thousands of classes in the Existing Java class library without having to redesign those classes. For example, simply add default Stream

Stream () to the Collection interface, and the corresponding Set and List interfaces and their subclasses contain this method. You don’t have to re-copy the method for each subclass.

This is a compromise design, with the problem of introducing multiple inheritance into Java. We know that interfaces can inherit interfaces, and classes can inherit classes and implement interfaces. What happens once the inherited class and the implemented interface have methods with the same signature? This article explores multiple inheritance in various cases so that you can clearly understand Java’s rules for multiple inheritance.

1. The interface inherits multiple parent interfaces

Suppose there are three interfaces: Interface A, Interface B, and Interface C. The inheritance relationship is as follows:

+---------------+         +------------+
|  Interface A  |         |Interface B |
+-----------^---+         +---^--------+
            |                 |         
            |                 |         
            |                 |         
            +-+------------+--+         
              | Interface C|            
              +------------+
Copy the code

A and B have the same signature as the default String say(String name) method. If interface C does not override the method, the compilation fails.

interface A {
	default String say(String name) {
		return "hello "+ name; }}interface B {
	default String say(String name) {
		return "hi, "+ name; }}interface C extends A.B{}Copy the code

Error when compiling:

hxr-mac:interfacemutil houxiurong$ javac -J-Duser.country=US MultipleInheritance.java 
MultipleInheritance.java:23: error: interface C inherits unrelated defaults for say(String) from types A and B
    interface C extends A.B{^1 error
hxr-mac:interfacemutil houxiurong$ javac MultipleInheritance.java 
MultipleInheritance.java:23Error: Interface C inherits an unrelated default value for say(String) from types A and Binterface C extends A.B{^1A mistakeCopy the code

Interface C reminds that the override say(String name) method is required to compile. We can override override in subinterface C and compile without error:

interface C extends A.B {
        @Override
        default String say(String name) {
            return "greet"+ name; }}Copy the code

Note that the method signature does not include the return value of the method, that is, the signature of two methods that only return different values is the same. The following code compiles without error because the default methods of A and B are different, and C implicitly inherits the two default methods.

interface A {
	default void say(int name) {
		
	}
}
interface B {
	default void say(String name) {
		
	}
}
interface C extends A,B{
	
}
Copy the code

But in some cases, it is difficult to distinguish even the methods of different signatures:

interface A {
        default void say(int name) {
            System.out.println("A=" + name);
        }
    }

    interface B {
        default String say(short name) {
            System.out.println("B=" + name);
            return "hi, " + name;
        }
    }

    interface C extends A, B {
        default String say(String name) {
            System.out.println("C=" + name);
            return "hi, " + name;
        }
    }

    static class D implements C {

    }

    public static void main(String[] args) {
        D d = new D();
        byte a = 1;
        d.say(a);

        d.say("hoxiurong");
    }
Copy the code

The result is as follows:

B=1
C=hoxiurong
Copy the code

Java selects the most appropriate method. See the Java specification 15.12.2.5 on the Oracle website

2. Multi-level interface inheritance

Let’s look at the problem of multi-level inheritance. The inheritance relationship is as follows: A2 inherits A1, and C inherits A2.

+---------------+ 
|  Interface A1 | 
+--------+------+ 
         |        
         |              
+--------+------+ 
|  Interface A2 | 
+-------+-------+ 
        |         
        |                 
+-------+--------+
|   Interface C  |
+----------------+
Copy the code

Based on our previous knowledge of class inheritance, it is easy to know that C inherits A2’s default methods, including directly defined default methods, overridden default methods, and default methods that implicitly inherit from A1 interfaces.

interface A {
        default void say(int a) {
            System.out.println("A");
        }

        default void run() {
            System.out.println("A.run");
        }
    }

    interface B extends A {
        default void say(int a) {
            System.out.println("B");
        }

        default void play() {
            System.out.println("B.play");
        }
    }

    interface C extends A, B {

    }

    static class D implements C {

    }

    public static void main(String[] args) {
        D d = new D();
        d.run();
        d.play();
    }
Copy the code

3. Multiple layers of inheritance

The above example is still a single inheritance example. What about multiple inheritance as shown below?

+---------------+                          
|  Interface A1 |                          
+--------+------+                          
         |                                 
         |                                 
         |                                 
+--------+------+    +---------------+
|  Interface A2 |    |  Interface B  |
+-----------+---+    +--+------------+
            |           |     
            |           |                          
            |           |                          
        +-------+-------++                         
        |   Interface C  |                         
        +----------------+
Copy the code

If A2 and B have methods with the same signature, this is the same as in the first example. If you don’t want compilation errors, you can override the default method of the parent interface, and you can also call the default method of the specified parent interface:

interface A1 {
    default void sayHello(int a) {
        System.out.println("A1");
    }
}

interface A2 extends A1 {

}

interface B {
    default void sayHello(int a) {
        System.out.println("B"); } } interface C extends A2, B { default void sayHello(int a) { B.super.sayHello(a); }}Copy the code

4. More complex multi-level multiple inheritance

+--------------+              
 | Interface A1 |^+-----+          
 +------+------++       |      
        |               |
        |               |      
+-------+-------+       |      
|  Interface A2 |       |      
+------------+--+       |      
             ^---+      |      
                 |      |      
              +--+------+-----+
              |  Interface C  |
              +---------------+
Copy the code

Interface A2 inherits from A1, and interface C inherits from A2 and A1. The code is as follows,

interface A1 {
    default void say() {
        System.out.println("hello,A1");
    }
}

interface A2 extends A1 {

    @Override
    default void say() {
        System.out.println("hello,A2");
    }
}

interface C extends A2, A1 {

}

static class D implements C {

}

public static void main(String[] args) {
    D d = new D();
    d.say();
}
Copy the code

The output of the execution program is as follows:

hello,A2
Process finished with exit code 0
Copy the code

The above code will compile without error, run the program output hello,A2. As you can see, interface C implicitly inherits the methods of the subinterface, which is the default method of subinterface A2.

5. Class hierarchies

If the inheritance relationship types are all classes, there is no problem with multiple inheritance because the class is still single inheritance.

6. Classes and interfaces are mixed

Let’s see what happens when we replace one of the interfaces in the first example with a class.

+-------------+ +-----------+ | Interface A | | Class B | +-----------+-+ +-+---------+ | | | | +---+----+-+ | Class C |  +----------+Copy the code

The following code compiles without error:

interface A {
    default void say() {
        System.out.println("hello,A");
    }
}

static class B {
    public void say() {
        System.out.println("hello,B");
    }
}

static class C extends B implements A {

}

public static void main(String[] args) {
    C c = new C();
    c.say(); //hello,B
}
Copy the code

The result is hello,B. If the parent class does not have a method with the same signature, the default method of the interface is inherited.

7. To summarize

More complex inheritance relationships can be simplified to the inheritance relationships above. From the above examples, the following conclusions can be drawn:

^1. Classes take precedence over interfaces. If a subclass inherits a parent class and an interface that have the same method implementation. So subclasses inherit the methods of their parent class.

^2. Methods in subtypes take precedence over methods in parent types.

^3. If none of the above conditions are met, the override must be displayedoverrideOr implementationimplementsIts method, or declaration ofabstract.

The main idea of the article is reprinted from: Bird’s Nest