接口

3.8 接口 上一節 本章開頭

  用關鍵字interface,你可以從類的實現中抽象一個類的接口。也就是說,用interface,你可以指定一個類必須做什麼,而不是規定它如何去做。接口在語句構成上與類相似,但是它們缺少實例變量,而且它們定義的方法是不含方法體的。實際上,這意味着你可以定義不用假設它們怎樣實現的接口。一旦接口被定義,任何類成員可以實現一個接口。而且,一個類可以實現多個接口。

  要實現一個接口,接口定義的類必須創建完整的一套方法。然而,每個類都可以自由的決定它們自己實現的細節。通過提供interface關鍵字,Java允許你充分利用多態性的“一個接口,多個方法”。

  接口是爲支持運行時動態方法解決而設計的。通常,爲使一個方法可以在類間調用,兩個類都必須出現在編譯時間裏,以便Java編譯器可以檢查以確保方法特殊是兼容的。這個需求導致了一個靜態的不可擴展的類環境。在一個系統中不可避免會出現這類情況,函數在類層次中越堆越高以致該機制可以爲越來越多的子類可用。接口的設計避免了這個問題。它們把方法或方法系列的定義從類層次中分開。因爲接口是在和類不同的層次中,與類層次無關的類實現相同的接口是可行的。這是實現接口的真正原因所在。

注意:接口增添了很多應用程序所需的功能。在一種語言例如C++中這些應用程序通常藉助於多重繼承來完成。

4.8.1 接口定義

  接口定義很像類定義。下面是一個接口的通用形式:

訪問類型 interface 接口名 { //定義抽象類

 final 數據類型 成員名稱1 = 常量; //數據成員必須賦初值

 abstract 返回值的數據類型 方法名稱(參數表); //注意抽象方法裏沒有處理的方式

}

  這裏,“訪問類型”要麼是public,要麼就沒有用修飾符。當沒有訪問修飾符時,則是默認訪問範圍,而接口是包中定義的惟一的可以用於其他成員的東西。當它聲明爲public時,則接口可以被任何代碼使用。接口名可以是任何合法的標識符。注意定義的方法沒有方法體。它們以參數列表後面的分號作爲結束。它們本質上是抽象方法;在接口中指定的方法沒有默認的實現。每個包含接口的類必需實現所有的方法。

  接口聲明中可以聲明變量。它們一般是final 和static型的,意思是它們的值不能通過實現類而改變。它們還必須以常量值初始化。如果接口本身定義成public ,所有方法和變量都是public的。

  下面列舉一實例來說明接口定義的方式。假設定義了一個接口iShape2D,可以利用它來實現二維的幾何圖形CCircleCRectangle。對二維的幾何形狀而言,面積是很重要的計算,因此,可以把計算面積的method聲明在接口裏,而計算圓面積的pi值是常量,所示可以把他聲明在接口的數據成員裏。依據這兩個概念,我們可以編寫出如下的接口。

interface iShape2D //定義接口 
{
  final double pi=3.14;  //數據成員一定要初始化
  abstract void area();  //抽象方法,不需要定義處理方式(類體)
}

  如前所述,在上面的範例中,Java也許省略了finalabstract關鍵字,編程如下的程序代碼:

interface iShape2D //定義接口 
{
  double pi=3.14;  //數據成員一定要初始化
  void area();  //抽象方法,不需要定義處理方式
}

  如此一來,每一個接口實現的類必須在類內部定義method的方法,且可自由地使用pi值。

  既然接口裏只有抽象方法,他只要聲明而不用定義處理方式,於是我們自然可以聯想到接口也沒有辦法像一般類一樣,用new運算符直接產生對象。相反地,我們必須利用接口的特性來打造一個新的類,在用它來創建對象。利用接口打造新的類的過程,我們稱之爲接口的實現

4.8.2 實現接口

  一旦接口被定義,一個或多個類可以實現該接口。爲實現一個接口,在類定義中包括implements 子句,然後創建接口定義的方法。一個包括implements 子句的類的一般形式如下:

訪問類型 class 類名 [extends 超類名] implements 接口名稱{

  // 類體

}

  這裏,訪問類型要麼是public的,要麼是沒有修飾符的。如果一個類實現多個接口,這些接口被逗號分隔。如果一個類實現兩個聲明瞭同樣方法的接口,那麼相同的方法將被其中任一個接口客戶使用。實現接口的方法必須聲明成public。而且,實現方法的類型必須嚴格與接口定義中指定的類型相匹配。

  就想你可以想象到的一樣,類可以使用接口,只是不用extends,而用implements(實現)

  下面是以iShape2D接口來實現CCircle類的範例:

class CCircle implements iShape2D  // 實現CCircle類

{

   double radius;

   public CCircle(double r){

      radius=r;

   }

   public void area(){    // 定義area()的處理方式

      System.out.println("area="+pi*radius*radius);     

   }

}

注意:當實現一個接口方法時,它必須聲明成public

  有了上面的理論基礎後,我們就可以開始編寫程序代碼了。exa4_19是以iShape2D接口實現CCircle與Crectangle兩個類的範例:

例4-19

// exa4_19, 接口的實現範例

interface iShape2D   //定義接口

{

   final double pi=3.14;

   abstract void area();

}

 

class CRectangle implements iShape2D    // 實現CRectangle類

{

   int width,height;

   public CRectangle(int w,int h){

      width=w;

      height=h;

   }

   public void area(){   // 定義area()的處理方式

      System.out.println("area="+width*height);     

   }

}

 

class CCircle implements iShape2D  // 實現CCircle類

{

   double radius;

   public CCircle(double r){

      radius=r;

   }

   public void area(){    // 定義area()的處理方式

      System.out.println("area="+pi*radius*radius);     

   }

}

 

public class exa4_19

{

   public static void main(String args[])

   {

      CRectangle rect=new CRectangle(5,10); 

      rect.area();   //調用CRectangle類裏的area() method

     

      CCircle cir=new CCircle(2.0); 

      cir.area();     // 調用CCircl類裏的area() method

   }

}

  由本範例的程序代碼可以看出,通過接口以及接口的實現在一起的類,我們可以編寫出更簡潔的程序代碼。

  前已述及,我們不能直接由接口來創建對象,而必須通過由接口實現的類來創建。雖然如此,我們還是可以聲明界面類型的變量(數組),並用它來訪問對象。例4_20是利用這個思路寫的,其中iShape2D接口、CCircleCrectangle類的定義均與例4-19相同,故將它們在例4-20中略去,因爲在同一目錄中,運行不會出現問題。

例4-20

// exa4_20.java, 通過接口類型的變量來訪問對象

class exa4_20

{

   public static void main(String args[])

   {

      iShape2D var1,var2;  // 聲明接口類型的變量

      var1=new CRectangle(5,10);  // 將接口類型的變量var1指向新建的對象

      var1.area();   // 通過接口var1調用area() method

     

      var2=new CCircle(2.0);  // 將接口類型的變量var2指向新建的對象

      var2.area();   // 通過接口var2調用area() method

   }

}

 

4-21,用一個類實現多個接口

 

//exa4_21.java

interface InterfaceExample1

{

       int i=4;

       void func1();

}

interface InterfaceExample2

{

       int k=5;

       void func2();

}

class Class3

{

       public void func2()

       {

              System.out.println("func2 in class3");

       }

}

public class exa4_21 extends Class3 implements InterfaceExample1,InterfaceExample2

       int j;

       public void func1()

       {

              System.out.println("func1 in exa4_21");

       }

       /*

       public void func2()

       {

              System.out.println("func2 in exa4_21");

       }

       */

       public static void main(String[] args)

       {

              exa4_21 c=new exa4_21();

           c.func1();

           c.func2();

       }

}

 

  程序中,exa4_21繼承了Class3類和兩個接口,那麼必須把類寫在前面,接口寫在後面,接口之間用逗號分開,另外注意,由於Class3類實現了func2方法,因此在exa4_21中可以不再實現(當然也可以實現)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章