What is the default method?
After the release of Java 8, new methods can be added to the interface, but the interface will still remain compatible with its implementation class. This is important because the library you develop may be widely used by multiple developers. Before Java 8, after an interface was published in a class library, if a new method was added to the interface, applications that implemented this interface would be in danger of crashing using the new version of the interface.
With Java 8, is there no such danger? The answer is no.
Adding default methods to an interface may make some implementation classes unavailable.
First, let's look at the details of the default method.
In Java 8, methods in interfaces can be implemented (static methods in Java 8 can also be implemented in interfaces, but that's another topic). The method implemented in the interface is called the default method, which is identified with the keyword default as a modifier. When a class implements an interface, it can implement methods that are already implemented in the interface, but this is not required. This class will inherit the default method. This is why when the interface changes, the implementation class does not need to be changed.
What about multiple inheritances?
When a class implements more than one (such as two) interfaces, and these interfaces have the same default method, things become very complicated. Which default method does the class inherit? Neither! In this case, the class itself (either directly or a class higher up the inheritance tree) must implement the default method.
The same is true when one interface implements the default method and another interface declares the default method as abstract. Java 8 tries to avoid ambiguity and maintain rigor. If a method is declared in multiple interfaces, then none of the default implementations will be inherited and you will get a compile-time error.
However, if you have compiled your class, there will be no compile-time errors. At this point, Java 8 is inconsistent. It has its own reasons, and there are various reasons. I don’t want to explain it in detail or discuss it in depth here (because: the version has been released, the discussion time is too long, and this platform has never had such a discussion).
1. Suppose you have two interfaces and an implementation class.
2. One of the interfaces implements a default method m().
3. Compile the interface and implementation class together.
4. Modify the interface that does not contain the m() method and declare the m() method as abstract.
5. Recompile the modified interface separately.
6. Run the implementation class.
1. Modify the interface containing abstract method m() and create a default implementation.
2. Compile the modified interface
3. Run class: Failed.
When two interfaces provide a default implementation for the same method, this method cannot be called unless the implementation class also implements the default method (either directly or by a higher-level class in the inheritance tree). ).
Example code:
In order to demonstrate the above example, I created a test directory for C.java, and there are 3 subdirectories under it for storing I1.java and I2.java. The test directory contains the source code C.java of class C. The base directory contains the version of the interface that can be compiled and run. I1 contains the m() method with default implementation, and I2 does not contain any methods.
The implementation class contains the main method so we can execute it in our tests. It will check whether there are command line parameters, so that we can easily perform tests calling m() and not calling m().
Copy the code code as follows:
~/github/test$ cat C.java
public class C implements I1, I2 {
public static void main(String[] args) {
C c = new C();
if(args.length == 0){
cm();
}
}
}
~/github/test$ cat base/I1.java
public interface I1 {
default void m(){
System.out.println("hello interface 1");
}
}
~/github/test$ cat base/I2.java
public interface I2 {
}
Use the following command line to compile and run:
Copy the code as follows:~/github/test$ javac -cp .:base C.java
~/github/test$ java -cp .:base C
hello interface 1
The compatible directory contains the I2 interface with abstract method m(), and the unmodified I1 interface.
Copy the code as follows:~/github/test$ cat compatible/I2.java
public interface I2 {
void m();
}
This cannot be used to compile class C:
Copy the code as follows:~/github/test$ javac -cp .:compatible C.java
C.java:1: error: C is not abstract and does not override abstract method m() in I2
public class C implements I1, I2 {
^
1 error
The error message is very precise. Because we have the C.class obtained in the previous compilation, if we compile the interfaces in the compatible directory, we will still get two interfaces that can run the implementation class:
Copy the code code as follows:
~/github/test$ javac compatible/I*.java
~/github/test$ java -cp .:compatible C
hello interface 1
The third directory called wrong contains the I2 interface that also defines the m() method:
Copy the code code as follows:
~/github/test$ cat wrong/I2.java
public interface I2 {
default void m(){
System.out.println("hello interface 2");
}
}
We should take the trouble to compile it. Although the m() method is defined twice, the implementation class can still run as long as it does not call the method defined multiple times. However, as long as we call the m() method, it will fail immediately. Here are the command line parameters we use:
Copy the code code as follows:
~/github/test$ javac wrong/*.java
~/github/test$ java -cp .:wrong C
Exception in thread "main" java.lang.IncompatibleClassChangeError: Conflicting
default methods: I1.m I2.m
at Cm(C.java)
at C.main(C.java:5)
~/github/test$ java -cp .:wrong C x
~/github/test$
in conclusion
When you port a class library that adds a default implementation to an interface to the Java 8 environment, there will generally be no problem. At least that's what Java8 class library developers thought when they added default methods to collection classes. Applications that use your library still rely on Java 7 libraries that do not have default methods. When using and modifying multiple different class libraries, there is a small chance that conflicts will occur. How can this be avoided?
Design your class library as before. Don't take it lightly when relying on the default method. Do not use as a last resort. Choose method names wisely to avoid conflicts with other interfaces. We will learn how to use this feature for development in Java programming.