用關鍵字interface,你可以從類的實現中抽象一個類的接口。也就是說,用interface,你可以指定一個類必須做什麼,而不是規定它如何去做。接口在語句構成上與類相似,但是它們缺少實例變量,而且它們定義的方法是不含方法體的。實際上,這意味着你可以定義不用假設它們怎樣實現的接口。一旦接口被定義,任何類成員可以實現一個接口。而且,一個類可以實現多個接口。
要實現一個接口,接口定義的類必須創建完整的一套方法。然而,每個類都可以自由的決定它們自己實現的細節。通過提供interface關鍵字,Java允許你充分利用多態性的“一個接口,多個方法”。
接口是爲支持運行時動態方法解決而設計的。通常,爲使一個方法可以在類間調用,兩個類都必須出現在編譯時間裏,以便Java編譯器可以檢查以確保方法特殊是兼容的。這個需求導致了一個靜態的不可擴展的類環境。在一個系統中不可避免會出現這類情況,函數在類層次中越堆越高以致該機制可以爲越來越多的子類可用。接口的設計避免了這個問題。它們把方法或方法系列的定義從類層次中分開。因爲接口是在和類不同的層次中,與類層次無關的類實現相同的接口是可行的。這是實現接口的真正原因所在。
注意:接口增添了很多應用程序所需的功能。在一種語言例如C++中這些應用程序通常藉助於多重繼承來完成。
4.8.1 接口定義
接口定義很像類定義。下面是一個接口的通用形式:
訪問類型 interface 接口名 { //定義抽象類
final 數據類型 成員名稱1 = 常量; //數據成員必須賦初值
abstract 返回值的數據類型 方法名稱(參數表); //注意抽象方法裏沒有處理的方式
}
這裏,“訪問類型”要麼是public,要麼就沒有用修飾符。當沒有訪問修飾符時,則是默認訪問範圍,而接口是包中定義的惟一的可以用於其他成員的東西。當它聲明爲public時,則接口可以被任何代碼使用。接口名可以是任何合法的標識符。注意定義的方法沒有方法體。它們以參數列表後面的分號作爲結束。它們本質上是抽象方法;在接口中指定的方法沒有默認的實現。每個包含接口的類必需實現所有的方法。
接口聲明中可以聲明變量。它們一般是final 和static型的,意思是它們的值不能通過實現類而改變。它們還必須以常量值初始化。如果接口本身定義成public ,所有方法和變量都是public的。
下面列舉一實例來說明接口定義的方式。假設定義了一個接口iShape2D,可以利用它來實現二維的幾何圖形CCircle與CRectangle。對二維的幾何形狀而言,面積是很重要的計算,因此,可以把計算面積的method聲明在接口裏,而計算圓面積的pi值是常量,所示可以把他聲明在接口的數據成員裏。依據這兩個概念,我們可以編寫出如下的接口。
interface iShape2D //定義接口
{
final double pi=3.14; //數據成員一定要初始化
abstract void area(); //抽象方法,不需要定義處理方式(類體)
}
如前所述,在上面的範例中,Java也許省略了final與abstract關鍵字,編程如下的程序代碼:
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接口、CCircle與Crectangle類的定義均與例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中可以不再實現(當然也可以實現)。