【JavaSE學習筆記03】介面
Chapter 6. 介面
介面(interface)技術,主要用來描述類具有什麼功能,而並不給出每個功能的具體實現。一個類可以實現(implement)一個或多個介面,並在需要介面的地方,隨時使用實現了相應介面的物件。
6.1 介面概述
在Java中,介面不是類,而是對類的一組需求描述,這些類要遵從介面描述的統一格式進行定義。重要的是,介面不能提供哪些功能,絕不能含有例項域,也不能在介面中實現方法、靜態程式碼塊、構造方法。提供例項域和方法實現的任務,應該由實現介面的那個類(可以看做為介面的子類)來完成,實現介面中所有的抽象方法,建立該類物件,就可以呼叫方法了,否則它必須是一個抽象類。
舉個例子,
Arrays
類中的sort
方法承諾可以對物件陣列進行排序,但要求滿足前提——物件所屬的類必須實現了Comparable
介面。
介面是一種引用資料型別,它的內部主要封裝了方法,包含抽象方法(JDK7以前),預設方法和靜態方法(JDK8),私有方法(JDK9)。
6.2 定義格式與基本實現
介面的定義格式:(使用interface
關鍵字)
public interface 介面名稱{
//抽象方法
//預設方法
//靜態方法
//私有方法
}
在使用IDEA建立
interface
時,應該新建interface
而不是class
。但是,換成關鍵字
interface
之後,.java
檔案編譯生成的位元組碼檔案仍然為.class
。
類與介面的關係為實現關係,即類實現介面,該類可以稱為介面的實現類,也可稱為介面的子類。實現使用implements
關鍵字(注意s
)
class 類名 implements 介面名{
//重寫介面中抽象方法(必須!)
//重寫介面中預設方法(可選)
}
6.2.1 含有抽象方法
抽象方法: 使用 abstract
關鍵字修飾,沒有方法體。該方法供子類實現使用。
定義介面:
public interface LiveAble{
public abstract void eat();//定義抽象方法
public abstract void sleep();
}
定義實現類:
public class Animal implements LiveAble{
@Override
public void eat(){
System.out.println("獲取食物");
}
@Override
public void sleep(){
System.out.println("地上睡覺");
}
}
TIPS:對於IDEA而言,滑鼠選中整個介面名稱,按
alt + Enter
鍵就能方便覆寫:
定義測試類:
public class InterfaceDemo{
public static void main(String[] args){
Animal a = new Animal(); //建立子類物件
a.eat(); a.sleep();
}
}
6.2.2 含有預設方法
預設方法:使用default
修飾,不可省略,供子類呼叫或者子類覆寫。
定義介面:
public interface LiveAble{
public default void fly(){
System.out.println("天上飛");
}
}
實現類可以繼承,可以重寫,二選一,但是隻能通過實現類的物件來呼叫。
-
繼承預設方法來定義實現類:
public class Animal implements LiveAble{ //繼承,什麼都不用寫,直接呼叫 }
-
重寫預設方法來定義實現類:
public class Animal implements LiveAble{ @Override public void fly(){ System.out.println("自由自在地飛"); } }
定義測試類:
public class InterfaceDemo{
public static void main(String[] args){
Animal a = new Animal(); //建立子類物件
a.fly(); //1 的輸出結果為:天上飛;2 的輸出結果為:自由自在地飛。
}
}
6.2.3 含有靜態方法
靜態方法:使用static
修飾,供介面直接呼叫。
定義介面:
public interface LiveAble{
public static void run(){
System.out.println("跑起來!");
}
}
靜態與.class
檔案相關,只能使用介面名呼叫,不可通過實現類的類名或者實現類的物件呼叫。
定義實現類:
public class Animal implements LiveAble{
//無法重寫靜態方法!
}
定義測試類:
public class InterfaceDemo{
public static void main(String[] args){
//Animal.run(); //錯誤寫法,無法繼承方法也不能呼叫。
LiveAble.run();
}
}
6.2.4 含有私有方法
若一個介面中有多個預設方法,且方法中有重複的內容,那麼可以抽取出來,封裝到私有方法中,供預設方法去呼叫。從設計的角度來講,私有的方法是對預設方法和靜態方法的輔助。
-
普通私有方法:只有預設方法可以呼叫。
private 返回值型別 方法名稱(引數列表){ 方法體 }
-
靜態私有方法:預設方法和靜態方法可以呼叫。
private static 返回值型別 方法名稱(引數列表){ 方法體 }
舉例定義介面:
public interface LiveAble{
public default void eat(){
System.out.println("Eat something...");
methodCommon();
}
public default void sleep(){
System.out.println("Go to sleep...");
methodCommon();
}
private void methodCommon(){ //該方法是專門為了上面兩個方法所抽取出來的,不應被實現類訪問。
System.out.println("AAA");
System.out.println("BBB");
System.out.println("CCC");
}
}
6.2.5 含有常量
介面當中其實也可以定義“成員變數”,但是必須使用public static final
三個關鍵字進行修飾,從效果上看就是介面的“常量”。
定義介面:
public interface LiveAble{
public static final int num = 233;
//public 說明介面內外部都可使用;static 使得num與物件無關;final 使得num不可變
}
注意,介面當中的常量必須進行賦值!
6.3 實現多個介面
6.3.1 介面與抽象類的比較
使用抽象類表示通用屬性會存在問題——每個類只能拓展於一個類。不同於C++的多繼承特性,為了避免將語言變得非常複雜或者效率降低,Java語言利用介面機制,來實現多繼承的大部分功能,由此每個類可以同時實現多個介面。
6.3.2 定義格式
public class 例項類名 implements 介面A, 介面B{
//覆蓋所有抽象方法
}
注意事項:
- 若實現類所實現的多個介面中,存在重複的抽象方法,那麼只需要覆蓋重寫一次即可。
- 若實現類所實現的多個介面中,存在重複的預設方法,那麼實現類一定要對衝突的預設方法進行覆寫。(也就說,不能直接繼承這些預設方法)
- 一個類中若直接父類當中的方法,與介面當中的預設方法產生了衝突,優先使用父類當中的方法。
6.4 介面之間的多繼承
類與類之間是單繼承的,而介面與介面之間是多繼承的。
介面的繼承也是使用extends
關鍵字。
定義父介面:
public interface A(){
public default void method(){
System.out.println("AAA");
}
}
public interface B(){
public default void method(){
System.out.println("BBB");
}
}
定義子介面:
public interface C extends A, B{
@Override
public default void method(){
System.out.println("23333");
}
}
注意事項:
- 如果父介面中的預設方法有重名的,那麼子介面需要重寫一次。
- 子介面重寫預設方法時,
default
關鍵字可以保留。但是,子類重寫預設方法時,default
關鍵字不可以保留。