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

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

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

    好了,現(xiàn)在說(shuō) interface 。

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

    先看這一些代碼:

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; 
// 引用!只是一個(gè)引用! Parent 是 obj 的靜態(tài)類(lèi)型。

        obj 
= new Child1(); // Child1 是 obj 的動(dòng)態(tài)類(lèi)型,實(shí)際類(lèi)型。
        obj.diaplay(); // 按照多態(tài),這里調(diào)用的是 Child1 里的方法

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

}

    這些代碼沒(méi)有涉及到接口,設(shè)計(jì)了一個(gè)抽象類(lèi)用于被繼承,而這些代碼會(huì)輸出什么呢?只要你有一些多態(tài)的概念,這么簡(jiǎn)單的問(wèn)題絕對(duì)難不倒你的,呵呵。只是為了演示一下而以。
    而其實(shí)在這里呢, Parent 里的那個(gè)方法永遠(yuǎn)調(diào)用不到,因?yàn)檫@是一個(gè)抽象類(lèi),不能被實(shí)例化,這個(gè)方法在這里是多此一舉了。
    不是說(shuō)接口是用來(lái)克服“多繼承”帶來(lái)的壞處的嗎,這里沒(méi)有多繼承,但,用它來(lái)代替繼承一樣是沒(méi)有問(wèn)題的。
    說(shuō)做就做:
public interface Parent{
    
public void display();
}
    子類(lèi)也很好辦:
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()");
    }

}


    可以看到,只是簡(jiǎn)單滴把 extends 改寫(xiě)成 implements 就是了。而客戶端的代碼是完全一樣的。當(dāng)然,運(yùn)行的效果也是一樣的。
    說(shuō)到這里,我想您大概會(huì)覺(jué)得好膚淺,其實(shí),我想要的效果也就差不多是這樣了。

    如果你覺(jué)得不夠過(guò)癮,沒(méi)事,理解了就最好。這里還有個(gè)例子。我將向你展示接口的另一種理解方法。
    假設(shè)我們要實(shí)現(xiàn)一個(gè)從 1 加到 N 的程序,你會(huì)說(shuō), 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;
    }

}

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

    那么 B 那兒他也放心地寫(xiě)了,因?yàn)樗囊仓皇且粋€(gè)功能,而不是具體的實(shí)現(xiàn),A 也可以放開(kāi)他想像的翅膀了。最后他給了你兩個(gè)代碼:
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;
        }

    }

}


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

    接口,可以把它說(shuō)成是一個(gè)協(xié)議,意思即:你要用我的東西,你就必須遵守我的規(guī)定!像上面那樣,B 要使用接口 Sum 的功能,他只有一個(gè)方法來(lái)調(diào)用它:

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

    接口的好處就在這里體現(xiàn)出來(lái)了。s 只是一個(gè)引用,它的靜態(tài)類(lèi)型是 Sum ,而動(dòng)態(tài)類(lèi)型則可以被你支配!在這里,你可以調(diào)用 SumImp1 ,也可以用 SumImp2 ,隨你的高興就是了。但 s.xxx(),這里的 xxx() 一定是在 Sum 里定義的,而在 SumImp1 或者 SumImp2 里定義的其它一切對(duì)于 s 來(lái)說(shuō)都是不可見(jiàn)的。所以,用接口可以很好地限制與外部的耦合,而且基本上是一勞永逸的做法,一開(kāi)始定義好一個(gè)接口,以后沒(méi)有了一點(diǎn)擔(dān)心的必要!


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