Java 8 之前,介面裡面只能寫抽象方法,不能寫實現方法
Java 8 開始是可以有方法實現的,可以在介面中新增預設方法和靜態方法
預設方法用 default
修飾,只能用在介面中,靜態方法用 static
修飾,並且介面中的預設方法、靜態方法可以同時有多個。
為什麼要用介面預設方法
舉一個很現實的例子:
我們的介面老早就寫好了,後面因為各種業務問題,避免不了要修改介面。
在 Java 8 之前,比如要在一個介面中新增一個抽象方法,那所有的介面實現類都要去實現這個方法,不然就會編譯錯誤,
而某些實現類根本就不需要實現這個方法也被迫要寫一個空實現,改動會非常大。
所以,介面預設方法就是為了解決這個問題,只要在一個介面新增了一個預設方法,所有的實現類就自動繼承,不需要改動任何實現類,也不會影響業務;
另外,介面預設方法可以被介面實現類重寫。
為什麼要有介面靜態方法?
介面靜態方法和預設方法類似,只是介面靜態方法不可以被介面實現類重寫。
介面靜態方法只可以直接通過靜態方法所在的 介面名
.靜態方法名
來呼叫。
介面預設方法多繼承衝突問題
因為介面預設方法可以被繼承並重寫,如果繼承的多個介面都存在相同的預設方法,那就存在衝突問題。
衝突一
interface People {
default void eat() {
System.out.println("人吃飯。");
}
}
interface Man {
default void eat() {
System.out.println("男人吃飯。");
}
}
//Boy 同時繼承了 People 和 Man,此時在 IDEA 編輯器中就會報錯
interface Boy extends People, Man {
}
//這就是介面多繼承帶來的衝突問題,Boy 不知道該繼承誰的,
//這顯然也是個問題,IDEA 也會提示,需要重寫這個方法才能解決問題:
interface Boy extends People, Man {
@Override
default void eat() {
People.super.eat(); //在方法裡面還能直接呼叫指定父介面的預設方法
Man.super.eat(); //在方法裡面還能直接呼叫指定父介面的預設方法
System.out.println("男孩吃飯。");
}
}
用實現類測試一下
class Student implements Boy {
public static void main(String[] args) {
Student student = new Student();
student.eat();
}
}
//result
//人吃飯。
//男人吃飯。
//男孩吃飯。
衝突二
我們再換一種寫法,把 Man
繼承 People
,然後 Man
重寫 People
中的預設方法
此時,編輯器不報錯了,而 People
的預設方法置灰了,提示沒有被用到。
再執行一下上面的示例,輸出:
interface People {
default void eat() {
System.out.println("人吃飯。");
}
}
interface Man extends People{
default void eat() {
System.out.println("男人吃飯。");
}
}
interface Boy extends People, Man {
}
//result
//男人吃飯
因為 Man
繼承 People
,Man
又重定了預設方法。很顯然,這個時候,Boy
知道該繼承誰的預設方法了。
注意,此時,如果用 People
通過 super
呼叫父類的 eat
方法會報錯,因為調不到了
interface Boy extends People, Man {
@Override
default void eat() {
People.super.eat(); //People報錯
System.out.println("男孩吃飯");
}
}
衝突三
在 Man
介面中新增一個方法:say
,然後在 Boy
介面中新增一個預設方法:say
。
interface Man extends People{
default void eat() {
System.out.println("男人吃飯。");
}
void say(); //IDEA提示,say方法變灰,沒有被使用
}
這時候,Man
中的抽象方法居然被忽略了,IDEA
都提示說沒用到,這顯然是預設方法優先於抽象方法。
總結
介紹了 Java 8 的預設方法和靜態方法,以及預設方法的衝突問題解決方案。
如果以後還說介面不能寫實現方法,那就太OUT
了。