天天看點

Java Review (十四、面向對象----接口)接口概念Java8的接口接口的繼承接口使用接口與抽象類

文章目錄

抽象類是從多個類中抽象出來的模闆,如果将這種抽象進行得更徹底,則可以提煉出一種更加特殊的“抽象類”——接口(interface),接口裡不能包含普通方法,接口裡的所有方法都是抽象方法。Java 8 對接口進行了改進,允許在接口中定義預設方法,預設方法可以提供方法實作。

接口是從多個相似類中抽象出來的規範 , 接口不提供任何實作 。 接口展現的是規範和實作分離的設計哲學 。

讓規範和實作分離正是接口的好處 , 讓軟體系統的各元件之間面向接口稠合,是一種松藕合的設計 。例如主機闆上提供了 PCI 插槽,隻要一塊顯示卡遵守 PCI 接口規範,就可 以插入 PCI 插槽内 , 與該主機闆正常通信。至于這塊顯示卡是哪個廠家制造的 , 内部是如何實作的,主機闆無須關心 。

類似的,軟體系統的各子產品之間也應該采用這種面向接口的稿合,進而盡量降低各子產品之間 的耦合,為系統提供更好的可擴充性和可維護性。

是以,接口定義的是多個類共同的公共行為規範,這些行為是與外部交流的通道,這就意味着接口裡通常是定義一組公用方法。

使用interface可以聲明一個接口,

定義接口文法如下:

[修飾符] interface 接口名 extends 父接口 1 ,父接口 2. . .{
   零個到多個常量定義 .. .
   零個到多個抽象方法定義.. .
   零個到多個内部類、接口、枚舉定義.. .
   零個到多個私有方法、預設方法或類方法定義 .. .
}         

由于接口定義的是一種規範,是以接口裡不能包含構造器和初始化塊定義 。 接口裡可以包含成員變量(隻能是靜态常量)、方法(隻能是抽象執行個體方法、類方法、預設方法或私有方法)、内部類 (包括内部接口、枚舉)定義。

隻有在Java 8以上的版本中才允許在接口中定義預設方法、類方法

詳細說明:

  • 接口裡的所有成員,包括常量、 方法、内部類和内部枚舉都是public通路權限。定義接口成員時,可以省略通路控制修飾符,如果指定通路控制修飾符,則隻能使用public通路控制修飾符。
  • 接口裡的成員變量隻能是靜态常量,它是接口相關的,是以系統會自動為這些成員變量增加static 和final兩個修飾符。而且接口裡沒有構造器和初始化塊,是以接口裡定義的成員變量隻能在定義時指定預設值。
//系統自動為接口裡定義的成員變量增加 public static final 修飾符,
//下面兩行代碼結果是一樣的
int MAX SIZE = 50;
public static final int MAX S 工 ZE = 50 ;      
  • 接口裡定義的方法隻能是抽象方法、類方法、預設方法或私有方法,是以如果不是定義預設方法、類方法或私有方法,系統将自動為普通方法增加 abstract 修飾符;定義接口裡的普通方法時不管是否使用 public abstract 修飾符,接口裡的普通方法總是使用 public abstract 來修飾 。接口裡的普通方法不能有方法實作(方法體) ;但類方法、預設方法都必須有方法實作(方法體〉 。

接口執行個體

public interface Output{
   //接口裡定義的成員變量隻能是常量
   int MAX_CACHE_LINE = 50;
    //接口重凫義的曾通方法隻能是public的抽象方法
   void out();
   void getData(String msg);
  //在接口中定義預設方法,需要使用default修飾
  default void print(String... msgs)
   for (String msg : msgs){
    System.out.printin(msg);
    }
  }
  //在接口中定義預設方法,需要使用default修飾
  default void test(){
    System. out. printin (預設的 test ()方法”);
  }
  //在接口中定義類方法,需要使用static修飾
 static String staticTest(){
    return ”接口裡的類方方法";
  }
  
}      
在 Java SE 8 中,允許在接口中增加靜态方法。理論上講,沒有任何理由認為這是不合法的。隻是這有違于将接口作為抽象規範的初衷。

接口的繼承和類繼承不一樣,接口完全支援多繼承,即一個接口可以有多個直接父接口。和類繼承相似,子接口擴充某個父接口,将會獲得父接口裡定義的所有抽象方法、常量。

一個接口繼承多個父接口時,多個父接口排在extends關鍵字之後,多個父接口之間以英文逗号(,) 隔開。下面程式定義了三個接口,第三個接口繼承了前面兩個接口。

繼承接口執行個體

interface interfaceA {
    int PROP_A = 5;
    void testA();
}

interface interfaceB {
    int PROP_B = 6;

    void testB();
}

// 接口C繼承接口A和接口B
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);
    }

}      

接口不能用于建立執行個體,但接口可以用于聲明引用類型變量。當使用接口來聲明引用類型變量時, 這個引用類型變量必須引用到其實作類的對象。除此之外,接口的主要用途就是被實作類實作。歸納起來,接口主要有如下用途。

  • 定義變量,也可用于進行強制類型轉換。
  • 調用接口中定義的常量。
  • 被其他類實作。

一個類可以實作一個或多個接口,繼承使用extends關鍵字,實作則使用implements關鍵字。因為 一個類可以實作多個接口,這也是Java為單繼承靈活性不足所做的補充。類實作接口的文法格式如下:

[修飾符] class 類名 extends 父類 implements 接口 1 , 接口 2. . .{
     類體部分
}           
  • 一個類實作了一個或多個接口之後 , 這個類必須完全實作這些接口裡所定義的全部抽象方法(也就是重寫這些抽象方法) ; 否則,該類将保留從父接口那裡繼承到的抽象方法,該類也必須定義成抽象類 。
  • 一個類實作某個接口時 , 該類将會獲得接口中定義的常量 (成員變量)、方法等 , 是以可以把實作接口了解為一種特殊的繼承 , 相當于實作類繼承了 一個徹底抽象的類(相當于除預設方法外,所有方法都是抽象方法的類)。

實作接口執行個體

public class LearningJava implements SlamDunk,Crossover,Shot{
    public static void main(String arg[]) {
        LearningJava sxai=new LearningJava();
        sxai.crossover();
        sxai.slamdunk();
        sxai.shot();
         
    }
    public void slamdunk() {
        System.out.println("宋小艾東方翔38式旋轉戰斧劈扣詹姆斯");
    }
    public void crossover() {
        System.out.println("宋小艾瘋狂變向晃暈詹姆斯");
    }
    public void shot() {
        System.out.println("宋小艾幹拔怒草詹姆斯打成三加一");
    }
}
 
interface SlamDunk{
    void slamdunk();
}
interface Crossover{
    void crossover();
}
interface Shot{
    void shot();
}      
實作接口方法時 , 必須使用 public 通路 控制修飾符, 因為接口裡的方法都是 public的 , 而子類( 相當于 實作類 )重寫父類方法時通路權限隻能更大或者相等 , 是以實作類實作接口裡的方法時隻能使用 public 通路權限 。

接口不能顯式繼承任何類 , 但所有接口類型的引用變量都可以直接賦給 Object 類型的引用變量。這是利用向上轉型來實作 的,因為編譯器知道任何 Java 對象都必須是 Object 或其子類的執行個體 。

接口和抽象類具備相似的特征 :

  • 接口和抽象類都不能被執行個體化,它們都位于繼承樹的頂端,用于被其他類實作和繼承。
  • 接口和抽象類都可以包含抽象方法,實作接口或繼承抽象類的普通子類都必須實作這些抽象方法。

但實際上接口和抽象類之間的差别非常大,這種差别主要展現在二者設計目的上。

  • 接口作為系統與外界互動的視窗 , 展現的是一種規範 。 對于接口的實作者而言,接口規定了實作者必須向外提供哪些服務(以方法的形式來提供);對于接口的調用者而言 , 接口規定了調用者可以調用哪些服務,以及如何調用這些服務(就是如何來調用方法)。當在一個程式 中使用接口時,接口是多個子產品間的耦合标準 : 當在多個應用程式之間使用接口時 , 接口是多個程式之間的通信标準。

    從某種程度上來看,接口類似于整個系統的"總綱",它制定了系統各子產品應該遵循的标準,是以一個系統中的接口不應該經常改變 。一旦接口被改變 , 對整個系統甚至其他系統的影響将是輻射式的,導緻系統中大部分類都需要改寫 。

  • 抽象類則不一樣,抽象類作為系統中多個子類的共同父類 , 它所展現的是一種模闆式設計 。 抽象類作為多個子類的抽象父類,可以被當成系統實作過程中的中間産品 , 這個中間産品己經實作了系統的部分功能(那些己經提供實作的方法) ,但這個産品依然不能當成最終産品,必須有更進一步的完善 ,這種完善可能有幾種不同方式 。

接口和抽象類在用法上也存在如下差别 :

  • 接口裡隻能包含抽象方法、靜态方法、預設方法和私有方法,不能為普通方法提供方法實作;
  • 抽象類則完全可以包含普通方法。
  • 接口裡隻能定義靜态常量,不能定義普通成員變量
  • 抽象類裡則既可以定義普通成員變量,也可以定義靜态常量。
  • 接口裡不包含構造器;
  • 抽象類裡可以包含構造器,抽象類裡的構造器并不是用于建立對象,而

    是讓其子類調用這些構造器來完成屬于抽象類的初始化操作 。

  • 接口裡不能包含初始化塊;
  • 抽象類則完全可以包含初始化塊 。
  • 一個類最多隻能有一個直接父類,包括抽象類;
  • 一個類可以直接實作多個接口,通過實作多個接口可以彌補 Java 單繼承的不足。
  • 接口中的方法預設都是 public,abstract 類型的。
  • 抽象類可以定義私有化方法。(雖然沒有什麼實際意義)

參考:

【1】:《瘋狂Java講義》

【2】:《Java核心技術 卷一》

【3】:

https://www.liaoxuefeng.com/wiki/1252599548343744/1260456371027744

【4】:

http://blog.itmyhome.com/2015/08/difference-in-java-abstract-classes-and-interfaces

【5】:

https://www.2cto.com/database/201807/762348.html