java8改進的介面,java8改進介面
java8對介面進行了改進,允許在介面中定義預設方法,預設方法可以提供方法實現。
5.6.1 介面的概念
類是一種具體實作類別,而介面定義了一種規範,介面定義了某一批類所需要遵守的規範,介面不關心這些類的內部狀態資料,也不關心這些類裡方法的實現細節,它只規定這批類裡必須提供某些方法,提供這些方法的類就可滿足實際需要。
介面是從多個類中抽象出來的規範,介面不提供任何實現。介面體現的是規範和實現分離的設計哲學。
5.6.2 java中介面的定義
樣本:[修飾符]interface 介面名 extends 父介面1,父介面2…{ }
介面名通常能夠使用形容詞
不管是否使用public static final修飾符,介面裡的成員變數總是使用這三個修飾符來修飾。
介面裡定義的內部類、內部介面、內部枚舉預設都採用public static 兩個修飾符,系統會自動使用public static來對他們進行修飾
Output.java
package code;public interface Output{ //介面裡定義的成員變數只能是常量 int MAX_CACHE_LINE = 50; //介面裡定義的普通方法只能是public的抽象方法 void out(); void getDate(String msg); //在介面中定義的預設方法,需要使用default修飾 default void print(String ... msgs){ for(String msg : msgs){ System.out.println(msg); } } //在介面中定義的預設方法,需要使用default修飾 default void test(){ System.out.println("預設的test()方法"); } //在介面中定義類方法,需要使用static修飾 static String staticTest(){ return "介面裡的類方法"; }}
default與存取控制符的default不同
java8允許在介面中定義預設方法,預設方法必須使用default修飾,該方法不能使用static修飾,預設方法會自動使用public修飾(必須使用)。由於預設方法並沒有static修飾,因此不能直接使用介面來調用預設方法,需要使用介面的實作類別的執行個體來調用這些預設方法。
在介面中定義類方法,必須使用static修飾,不能使用default修飾,而且自動為類添加public(必須使用)。類方法可以直接使用介面來調用
package code;public class OutputFieldTest{ public static void main(String[]args){ System.out.println(code.Output.MAX_CACHE_LINE); //code.Output.MAX_CACHE_LINE = 20; System.out.println(code.Output.staticTest()); }}
介面裡的成員變數預設是使用public static final修飾的,不同包下也可以通過介面來提供者裡的成員變數。
5.6.3 介面的繼承
介面支援多繼承,
package code;interface interfaceA{ int PROP_A = 5; void testA();}interface interfaceB{ int PROP_B = 6; void testB();}interface interfaceC extends interfaceA,interfaceB{ int PROP_C = 7; void testC();}public class InterfaceExtendsTest{ public static void main(String []args){ System.out.println(interfaceC.PROP_A); System.out.println(interfaceC.PROP_B); System.out.println(interfaceC.PROP_C); }}
5
6
7
5.6.4 使用介面
歸納:介面有如下用途:
- 定義變數,也可用於進行強制類型轉換
- 調用介面中定義的常量
- 被其他類實現
樣本:[修飾符]class 類名 extends 父類 implements 介面1,介面2…{ 類體部分}
implements必須放在extends部分之後
一個類實現了一個或多個介面後,這個類必須完全實現這些介面裡所定義的全部抽象方法(也就是重寫這些抽象方法),否則將保留從父介面那裡繼承到的抽象方法, 該類也必須定義成抽象類別。
Printer.java
package code;interface Product{ int getProduceTime();}public class Printer implements Output,Product{ private String[] printData = new String[MAX_CACHE_LINE]; private int dataNum = 0; public void out(){ while(dataNum > 0){ System.out.println("印表機列印:" + printData[0]); System.arraycopy(printData,1,printData,0 ,1); --dataNum; } } public void getData(String msg){ if(dataNum >= MAX_CACHE_LINE){ System.out.println("輸出隊列已滿,添加失敗"); } else{ printData[dataNum++] = msg; } } public int getProduceTime(){ return 45; } public static void main(String[]args){ Output o = new Printer(); o.getData("輕量級JavaEE公司專屬應用程式實戰"); o.getData("瘋狂Java講義"); o.out(); o.getData("瘋狂Android講義"); o.getData("瘋狂Ajax講義"); o.out(); o.print("孫悟空","豬八戒","白骨精"); o.test(); Product p = new Printer(); System.out.println(p.getProduceTime()); Object obj = p ; }}
印表機列印:輕量級JavaEE公司專屬應用程式實戰
印表機列印:瘋狂Java講義
印表機列印:瘋狂Android講義
印表機列印:瘋狂Ajax講義
孫悟空
豬八戒
白骨精
預設的test()方法
45
上面程式看出:Printer類實現了Output介面和Product介面,因此Printer對象既可直接賦給Output變數,也可直接賦給Product變數,彷彿Printer類既是Output類的子類,也是Product類的子類,這就是java提供的類比多繼承
Printer實現Output介面,即可獲得Output介面中定義的print()和test()兩個預設方法,因此Printer執行個體可以直接調用這兩個預設的方法。
介面不能顯式繼承類,但所有介面類型的引用變數都可以直接賦給Object類型的引用變數。
5.6.5 介面和抽象類別
共同特徵:
- 都不能被執行個體化,都位於繼承樹的頂端,用於被實現和繼承
- 都可以包含抽象方法,實作類別和介面必須實現這些抽象方法
差別:
介面類似於整個系統的“總綱”,制定了系統各模組應該遵循的標準,因此一個系統中的介面不應該經常改變,一旦介面被改變,對整個系統甚至其他系統的影響都是輻射式的,導致大部分類都需要重新改寫。
抽象類別所體現的是模組式的設計,它作為多個子類的抽象父類,可以被當成系統實現過程中的中間產品。這個中間產品已經實現了系統的部分功能(那些已經提供實現的方法),但是需要完善。
| 區 別 |
介面 |
抽象類別 |
| 1 |
只能包含抽象方法和預設方法,不能為普通方法提供方法的實現 |
完全可以包含普通方法 |
| 2 |
不能定義靜態方法 |
可以定義靜態方法 |
| 3 |
只能定義靜態變數,不能定義普通成員變數 |
既可以定義普通成員變數,也可以定義靜態變數 |
| 4 |
不包含構造器 |
可以包含構造器,抽象類別的構造器並不是用於建立對象,而是讓其子類調用這些構造器來完成屬於抽象類別的初始化操作 |
| 5 |
不能包含初始化塊 |
完全可以包含初始化塊 |
| 6 |
一個類可以直接實現多個介面,通過實現多個介面可以彌補Java單繼承的不足 |
一個類最多隻能有一個直接父類,包括抽象類別 |