在JAVA里說接口,有兩個意思。廣義的意思:一個 類/軟件實體 對外提供的方法的集合,而狹義的意思就是關鍵字 interface 所代表的JAVA里特有的一種概念。如果您看到這里就明白了,那可以不用往下看了,我不想班門弄斧!

    何為“對外提供的方法的集合”?第一次看到這個廉潔時我也很納悶,不急!如果你有一些軟件工程的知識,那么下面的這些你一定不會陌生:一個軟件實體應盡可能滴做到“高內聚,低耦合”!而做到低耦合的一個方法就是向外界提供一個窄接口!OK!終于出現了“接口”二字。這個概念在軟件工程中,也就是要比JAVA還早一些就有了的東西,好了,先解釋清楚了它不是JAVA的“特產”!

    鑒于我對其它對象語言的完全無知,在此還是以JAVA說法。
    在JAVA里有四個訪問權限,分別由三個訪問修飾符和一個缺省修飾符確定。一般而言,一個類的成員變量都被用 private 修飾,而成員方法的修飾符多看設計者的意圖了( static 修改的是類××,而不是成員××,一般都是用 public 修飾)。那么我下面的這個說法應該是沒有問題的: private 是不向外提供的, protected 修飾的方法是對子類提供的訪問接口,不加修飾符的方法是對本包中其它類提供的訪問接口,而 public 修飾符的方法是對所有類提供的訪問接口。
    我想要是我的表達不是太次的話,那就把接口的第一個意思描述清楚了。且慢,我再多嘴兩句。
    看別人的代碼總是那么容易,但當你自己寫東西的時候一定要注意了,應該盡量少用 public 來修飾你寫的方法!能不用就不能,可以用 private 的時候就要堅決用它!舉一個很簡單的例子。在開發初期,你對此沒什么概念,生怕哪個方法別的類用不到,狂用 public ,等開發基本結束開始復審時,麻煩來了,你發現某一個工具類的一些方法不應該公開,但一開始時公開了,導致了一系列的地方對它引用了,試問,此時的你會選擇哪條路呢?把引用的地方一個個地改過來,還是讓這個惡性腫瘤繼續擴大?有一句老話是沒錯滴:病是早醫好!如果當初你就把牢給補上,那今天就不會有那么多的狼來偷你的羊了!

    好了,現在說 interface 。

    如果你的記性不差,那想想你看JAVA書時他是怎么說的。為了克服多重繼承帶來的麻煩,JAVA取消了C++里的多繼承,而用接口來代替。接口沒有消除多繼承的好處但去掉了多繼承帶來的壞處!似乎很神奇哦,但,別被它嚇到了。

    先看這一些代碼:

public abstract class Parent{
    
public void display(){
        System.
out.println("Parent.Display()");
    }

}

public class Child1 extends Parent{
    
public void display(){
        System.
out.println("Child1.Display()");
    }

}

public class Child2 extends Parent{
    
public void display(){
        System.
out.println("Child2.Display()");
    }

}

public class Client{
    
public static void main(String[] args){
        Parent obj; 
// 引用!只是一個引用! Parent 是 obj 的靜態類型。

        obj 
= new Child1(); // Child1 是 obj 的動態類型,實際類型。
        obj.diaplay(); // 按照多態,這里調用的是 Child1 里的方法

        obj 
= new Child2(); // 不多說了
        obj.diaplay(); // ..
    }

}

    這些代碼沒有涉及到接口,設計了一個抽象類用于被繼承,而這些代碼會輸出什么呢?只要你有一些多態的概念,這么簡單的問題絕對難不倒你的,呵呵。只是為了演示一下而以。
    而其實在這里呢, Parent 里的那個方法永遠調用不到,因為這是一個抽象類,不能被實例化,這個方法在這里是多此一舉了。
    不是說接口是用來克服“多繼承”帶來的壞處的嗎,這里沒有多繼承,但,用它來代替繼承一樣是沒有問題的。
    說做就做:
public interface Parent{
    
public void display();
}
    子類也很好辦:
public class Child1 implements Parent{
    
public void display(){
        System.
out.println("Child1.Display()");
    }

}

public class Child2 implements Parent{
    
public void display(){
        System.
out.println("Child2.Display()");
    }

}


    可以看到,只是簡單滴把 extends 改寫成 implements 就是了。而客戶端的代碼是完全一樣的。當然,運行的效果也是一樣的。
    說到這里,我想您大概會覺得好膚淺,其實,我想要的效果也就差不多是這樣了。

    如果你覺得不夠過癮,沒事,理解了就最好。這里還有個例子。我將向你展示接口的另一種理解方法。
    假設我們要實現一個從 1 加到 N 的程序,你會說, it's so easy. 于是

public class Sum{
    
public int sum(int n){
        
int sum = 0;
        
for(int i = 0; i <= n; i++)
            sum 
+= i;
        
return sum;
    }

}

    是這樣,沒錯,很簡單,這樣確實是實現了。但是,假如,萬一,你不是個“程序員”,你是管程序員的,你想你手下的某個程序員A 為你實現這個功能,但是,你還給了另外一個程序員B 其它的任務,而在 B 的任務里,就有用到 A 要實現的功能。而且你知道,A 目前在公司的地位不是很高,他想表現自己。也許,他會拿給你一些藝術代碼,可你想要的只是那個功能。現在,你怎么辦呢?
    辦法還是很簡單,你只要給 A 一個接口,并把功能說清楚就可以了。
public interface Sum{
    
public int sum(int m, int n);
}

    那么 B 那兒他也放心地寫了,因為他要的也只是一個功能,而不是具體的實現,A 也可以放開他想像的翅膀了。最后他給了你兩個代碼:
public class SumImp1{
    
public int sum(int m, int n){
        
int sum = 0;
        
for(int i = m; i <= n; i++)
            sum 
+= i;
        
return sum;
    }

}

public class SumImp2{
    
public int sum(int m, int n){
        
if(n >= m){
            
return sum(m, n - 1+ n;
        }
else{
            
return m - 1;
        }

    }

}


    其實他給的你什么代碼你并不會關心,你只是知道了,我要的功能有了,這就好了。接口,這就是它給你帶來的好處。
    那么,從這里,你是不是體會到了另一種理解接口的思路呢?

    接口,可以把它說成是一個協議,意思即:你要用我的東西,你就必須遵守我的規定!像上面那樣,B 要使用接口 Sum 的功能,他只有一個方法來調用它:

    Sum s = new SumImp1(); int sum = s.sum(1, 100);
        s = new SumImp2();     sum = s.sum(1, 100);

    接口的好處就在這里體現出來了。s 只是一個引用,它的靜態類型是 Sum ,而動態類型則可以被你支配!在這里,你可以調用 SumImp1 ,也可以用 SumImp2 ,隨你的高興就是了。但 s.xxx(),這里的 xxx() 一定是在 Sum 里定義的,而在 SumImp1 或者 SumImp2 里定義的其它一切對于 s 來說都是不可見的。所以,用接口可以很好地限制與外部的耦合,而且基本上是一勞永逸的做法,一開始定義好一個接口,以后沒有了一點擔心的必要!


    到這里,我算是說完了,朋友,你要是覺得我說得不差,那記住就行了。但如果你覺得沒明白,可以留言,我盡全力把我知道的都說出來,但愿我理解的不是錯的。
    如果你覺得我哪里說錯了,那請您把我錯在哪里指出來,相互討論自己的所好,于我而言,實在是人生一大樂事矣!