在Java中,接口里只能寫方法的聲明,而不能寫方法的具體實現,方法的實現要在實現接口的類中編寫。但在JDK1.8中,接口可以對方法的聲明寫具體實現,個人覺得這有點違背接口的設計初衷。
下面我們來具體看一下:
1、JDK8之前的寫法:
1)首先定義兩個接口:IEat,IWalk
public interface IEat { void eat(); } public interface IWalk { void walk(); }
2)再定義一個Dog類,實現IEat和IWalk接口,此時則必須要實現walk(),eat()方法。
public class Dog implements IWalk,IEat { @Override public void walk() { System.out.println("dog walk!"); } @Override public void eat() { System.out.println("dog eat!"); } }
3)定義一個Test類,運行一下,看看結果
public class Test { public static void main(String[] args) { Dog dog = new Dog(); dog.walk(); dog.eat(); } }
此時的運行結果為:
dog walk!
dog eat!
以上是JDK8之前的版本的寫法。
2、接下來可以將1)中的IWalk接口定義修改一下:
public interface IWalk { default void walk(){ System.out.println("IWalk walk"); } }
在JDK8中,可以在接口的方法聲明前加上default關鍵字,這樣就可以給walk()方法添加具體的實現,此種寫法稱之為默認方法實現。
接下來我們將Dog類中的walk()方法實現刪除,只保留eat()方法的實現:
public class Dog implements IWalk,IEat { @Override public void eat() { System.out.println("dog eat!"); } }
再次運行Test類,運行結果為:
IWalk walk
dog eat!
我們可以看到在調用dog.walk()方法時,打印出的是IWalk接口中的默認方法實現。
3、那么問題來了,如果Dog類繼承自一個Animal的父類,Animal類也實現了IWalk方法,並且已經有了方法的實現,那此時會出現什么情況呢?
public class Animal implements IWalk,IEat { @Override public void eat() { System.out.println("Animal eat!");
}
@Override public void walk() {
System.out.println("Animal walk!");
}
}
public class Dog extends Animal implements IWalk,IEat { @Override public void eat() { System.out.println("dog eat!"); } }
此時,再次運行Test類,運行結果為:
Animal walk!
dog eat!
從結果我們可以看出,同時有父類和接口都有同一個方法的實現時,優先調用的是父類的實現,而不是接口中的默認實現。
4、另外,接口的默認方法除了可以聲明為default之外,還可以聲明為static,此時,調用默認方法時,則需要用類名.方法名來調用,和調用靜態方法的方式是一樣的。
5、總結
以上則是JDK8中對接口中方法的定義的變化,不知道JAVA的工程師們為什么要做這樣一個變化,個人覺得這樣違背了接口的設計初衷,把接口變成了抽象類了,甚至可以說是一個普通的父類了。在網上搜索到的一些答案,有的說是因為JDK中的某些接口需要新定義方法,但之前的項目中的某些類如果實現了這個接口,則需要重新在接口中添加方法的實現,如果給接口添加默認方法,則不需要再進行這些類的維護工作,這也可以說算是一個方案吧。但個人感覺這個方案還是不夠好,因為它破壞了接口的性質和意義。