程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA編程入門知識 >> java 接口學習

java 接口學習

編輯:JAVA編程入門知識

你應該知道接口是一種契約,它與實現方式無關

但是類,即使是抽象類,你都能自定義成員變量,而成員變量往往就與實現方式有關。

這一點的實際意義不大。

但是有一點,類會暴露太多不必要,甚至不能暴露的東西,你看一下java.util中,大部分的數據結構,都被設計成了接口-抽象類-最後實際類

例如Collection-List
L-AbstractCollection
L-AbstractList
L-ArrayList

但是有一個,由於歷史原因,被設計成了類,比如Stack extends Vector,
你應該知道Stack的數據訪問模式,就只能是LIFO,但是Vector是一個List,可以隨機訪問,可以任意增減。

結果Stack s = new Stack();

不光能夠pop/push/peer還能add,get,set,remove

如果你用一個接口IStack 裡面只有pop/push/peer方法,然後仍然通過繼承Vector的方式實現,

IStack s = new MyStack();

此時,就無法add,get,set,remove

舉個生動一點的例子

public interface BritishSpy {
public String speak(); //英國間諜講英語
}

public interface GermanSpy {
public String sprechen(); //德國間諜講德語
}

public class DoubleAgent implements BritishSpy, GermanSpy {
public String speak() { return "Hello"; }
public String sprechen() { return "Gutentag"; }
}
// hovertree.com
public class Agency {
public static void toMI5(BritishSpy spy) {
//軍情5處當然只能說英語,做英國間諜
spy.speak();
//spy.sprechen();不可見
}

public static void inGermany(GermanSpy spy) {
//spy.speak();不可見
spy.sprechen();
}

public static void main(String[] args) {
DoubleAgent da = new DoubleAgent();
BritishSpy es = (BritishSpy) da;
GermanSpy gs = (GermanSpy) da;
toMI5(da); //MI5也不知道他是一個雙重間諜,只知道他是BritishSpy
toMI5(es); //更安全  何問起
//toMI5(gs); 不可能
inGermany(da); //在德國還是安全的,德國人不知道他的雙重間諜身份,只知道他是GermanSpy
inGermany(gs); 
//inGermany(es); 不可能
}
}

 

假設你只用class,因為不能多重繼承,所以,speak()/sprechen()比然聲明在同一個class裡面


public abstract class DoubleAgent extends Spy/**(略...)*/ {
public abstract String speak();
public abstract String sprechen();
}

public class PoorDoubleAgent {
public String speak() { return "Hello"; }
public String sprechen() { return "Gutentag"; }
}

晚了,不管你PoorDoubleAgent a = new PoorDoubleAgent();還是DoubleAgent a = new PoorDoubleAgent();,全世界都知道他是一個雙重間諜,他到哪裡都必死無疑
前面舉了一個關於“安全性”方面的例子

接口只暴露給對方(比如Agent的軍情5處方法)它所需要的足夠信息,其他無關的,甚至有害的信息不會暴露給對方。因為,我傳給你的是接口類型,我除了是這個接口(和這個接口的父接口,inteface A extends B, C)的實例外,你頂多知道我是一個Object(不是int:P),其他的姓甚名誰,哪裡住址,父母安好,兄妹幾何都與你無關,我們只需要關心我們簽訂的合同(接口) 

再舉一個有關靈活性方面的例子

假設某公司已經有一個更新過N代的,邏輯復雜無比
public class A extends B /** where b extends c, c extends d and so on... */ {
public void init() {...}
public void release() {...}
public String doXXX() {...}
public String doYYY() {...}
}

而這個A又被很多類繼承或使用,doXXX/doYYY 方法已經無法更改

假設現在這個公司要參加某個標准化組織,而這個組織要求所有提供這樣的方法

String getXXX(); String getYYY();

加入用接口標准化組織只要規定成員們都實現
public interface IBusiness {
String getXXX();
String getYYY();
}
而這個公司只需要稍微改寫一點點即可
public class A extends B /** where b extends c, c extends d and so on... */
implements IBusiness {
public String getXXX() { return doXXX(); }
public String getYYY() { return doYYY(); }

//保留
public void init() {...}
public void release() {...}
public String doXXX() {...}
public String doYYY() {...}
}

這樣既滿足了標准化的要求,又滿足了無需修改原來繼承A或者使用A的無數個class(有些可能在用戶那裡,不可能更改)

假如不用接口,你有兩個選擇:數典忘祖或者自絕於人

數典忘祖:
你的新A必須繼承標准化組織的Business,原來a,b, c d...裡面的代碼全部得重新組織到這個新的A裡面,與此同時,那些調用或者繼承A的class難保不需要重寫

自絕於人
原來的就讓它去,誰也別再提它了,我們以後就用新的NewA,結果,你的新客戶倒是滿足了標准化,你的老客戶可就 :< :@ :$,而且以後需要維護A和NewA
定義接口:
interface Fight{
void fight();
}

肥肥和瘦瘦去實現這個接口:
class FatFat implements Fight{
public void fight(){
System.out.println("FatFat 打人很痛!");
}
}

class ThinThin implements Fight{
public void fight(){
System.out.println("ThinThin 打人一點都不痛!!哈哈。");
}
}

然後你可能會這另一個類中使用到FatFat和ThinThin的對象,然後都去執行fight,但是你可能不到運行時就不會知道是具體的那個類的對象,這是你就感謝他們都實現了Fight接口,你可以向上轉型,然後通過運行時的多態產生你想要的行為。http://hovertree.com/menu/java/

Fight a=new FatFat();
Fight b=new ThinThin();
a.fight();
b.fight();
這樣就會執行不同的動作。

或者如果你有一個方法
f(Fight i){
i.fight();
}

如果c是實現了Fight接口的其中一個類,那麼你就可以這樣使用這個方法:
f(c);
你不需要知道c究竟是什麼對象(不管是FatFat還是ThinThin),你都可以得到你想要的fight動作

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved