Let's learn Java8 (5) - interface default method

A new feature was added to Java 8 that allows a default implementation to be given in interface methods. The premise is to add a defaultkeyword in front of the method.

public interface InterfaceMethod {
	default void say() {
		System.out.println("hello");
	}
	
	default int getAge() {
		return 1;
	}
}

This design seems to be a bit against the principles of interface design, because it was stipulated that all methods in the interface are abstract methods, and subclasses are required to implement it.

However, in Java 8, this rule has to be broken, and Java designers also have difficulties. Considering such a situation, if a new method is to be added to the interface, those classes that have implemented it before must implement the new method. . If there are many interface implementation classes, it will be very painful to change. This behavior that affects the whole body is obviously not desirable.

So Java8 has the feature of interface default method, so that a default method is added to the interface, which is unaware of the implementation class below it.

There are many default methods of interfaces in the Java system. For example, some functional interfaces and collection interfaces have default methods that define them. The common ones are as follows

  • java.util.function.Predicate.and(Predicate<? super T>)
  • java.util.function.Function.compose(Function<? super V, ? extends T>)
  • java.util.Collection.stream()

interface implementation

After the interface already has a default method, its implementing class does not need to implement the default method

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

public class MyClass implements MyInterface {

}

Of course, you can also override this default method

public class MyClass implements MyInterface {
	@Override
	public void say() {
		System.out.println("goodbye");
	}
}

If you want to call the original default method in the overridden method, the format is as follows:

接口名字.super.方法名

如:MyInterface.super.say();

public class MyClass implements MyInterface {
	@Override
	public void say() {
		System.out.println("goodbye");
		// 调用默认方法
		MyInterface.super.say();
	}
	
	public static void main(String[] args) {
		new MyClass().say();
	}
}

Multiple inheritance problem

Parallel Multiple Inheritance

With the new feature of interface default method, it will bring some new problems. If two interfaces A and B have a unified default method void say(), what will happen if a class implements these two interfaces at the same time.

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

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

static class MyClass implements A,B {
    
}

Obviously, this situation is not allowed, and the compilation will report an error.

What happens if the method of interface B is changed to an abstract method?

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

interface B {
	void say();
}

static class MyClass implements A, B {

}

This compilation will also report an error, indicating that the method in interface B needs to be implemented

static class MyClass implements A, B {
    // 实现B
	@Override
	public void say() {
		System.out.println("myclass");
	}
}

At this time, if the say method is called, the implementation method in MyClass will be called

new MyClass().say();Output myclass, if you want to call the default method in interface A, you can write:

static class MyClass implements A, B {
	@Override
	public void say() {
		// 调用A接口中的默认方法
		A.super.say();
		System.out.println("myclass");
	}
	
	public static void main(String[] args) {
		new MyClass().say();
	}
}

indirect multiple inheritance

In the above example, if interface B is changed to inherit interface A, and then the say method is called, what will be printed?

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

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

static class MyClass implements A, B {
	public static void main(String[] args) {
		new MyClass().say();
	}
}

output B

Why is it B instead of A? Here Java lists three rules. In the case of this method conflict, you can refer to these three rules

  1. The methods in the class have the highest priority
  2. The sub-interface has the highest priority, and the default method interface with concrete implementation is preferred.
  3. Display overrides and call default methods of the specified interface.

In the above example, 规则2you can see that B inherits A, then the method in B has the highest priority, so B is printed.

So what does the third rule mean? Going back to the example mentioned at the beginning, side by side inheritance

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

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

static class MyClass implements A, B {

}

Here is a compilation error. The solution is to override the say method and specify which interface to call the default method:

static class MyClass implements A, B {
	@Override
	public void say() {
		A.super.say();
	}
}

diamond inheritance

Diamond inheritance is C++a problem encountered in the C++support of multiple inheritance, but there will be a problem.

There is a class A, there is a say method in A, B inherits A, C inherits A, and then MyClass inherits B and C, as follows

    A
 ╱    ╲   
B       C
 ╲    ╱
 MyClass

The inheritance graph is like a diamond, and an error myClass.say()willC++ be reported if the call is made at this time.request for member 'say' is ambiguous

So what will happen under Java8? Take a look at the following code:

public class RhombusTest {

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

    interface B extends A {}
    interface C extends A {}

    static class MyClass implements B,C {}

    public static void main(String[] args) {
        new MyClass().say();
    }
}

The above code will compile and print A.

According to 规则2:子接口的优先级最高,优先选择有具体实现的默认方法接口。B and C both have the default method of A, there is a specific implementation of the default method in A, and A will be selected in the end. At this point, if you add a same method to B

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

Then according to the principle of proximity, B is preferred. If the method in B is changed to an abstract method, it will compile an error, indicating that the method in B needs to be implemented, because B is selected, but there is no specific implementation.

interface B extends A {
    void say();
}

Summarize

This article mainly introduces the default methods of interfaces in Java 8 and the judgment rules of the Java system in the case of multiple inheritance.

Regularly share technical dry goods, learn together, and progress together!

{{o.name}}
{{m.name}}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324063727&siteId=291194637
Recommended