1.接口定義
接口屬於一個特殊的類,這個類里面只能有抽象方法和全局常量 (該概念在JDK1.8之后被打破,在1.8后接口中還可以定義普通方法和靜態方法,在后續章節會詳講)
1.1 接口具有以下幾個原則
- 接口通過interface關鍵字來實現定義
- 一個子類如果要繼承接口的話,則需要通過implements關鍵字去實現多個接口(多接口之間通過","隔開),從而實現多繼承.
- 接口的子類如果不是個抽象類,則必須要覆寫接口的所有抽象方法,才能承認該類實現了這個接口
- 接口的子對象可以通過向上轉型進行實例化操作
1.2 接下來來個示例,通過Demo類繼承InA和InB兩個接口
interface InA //接口InA { public static final String ATTR = "Attribute:InA"; public abstract void PrintA(); } interface InB //接口InB { public static final String ATTR = "Attribute:InB"; public abstract void PrintB(); } class Demo implements InA,InB { public void PrintA() { System.out.println(InA.ATTR); //打印接口A的全局常量 } public void PrintB() { System.out.println(InB.ATTR); //打印接口B的全局常量 } } public class Test{ public static void print(InB b) //接口支持向上轉型 { b.PrintB(); } public static void main(String args[]) { Demo d = new Demo(); d.PrintA(); //打印接口A的全局常量 print(d); //等價於d.PrintB(); } }
運行打印:
從上面代碼可以看出,接口實際上只是表示一種操作標准 ,而接口本身其實是沒有操作能力的,需要子類去實現這個操作能力才行.
2.接口的簡化定義
由於接口組成部分是抽象方法和全局常量,所以在方法和常量上寫不寫public結果都一樣,並且方法也可以不用abstract修飾,因為接口里的訪問權限都是public的,並且方法默認為抽象的,所以InA接口也可以寫為下面這樣:
interface InA //接口InA { String ATTR = "Attribute:InA"; //不需要添加public static final void PrintA(); //不需要添加public abstract }
3.接口定義注意的地方
3.1 對於子類或者抽象子類,可以同時繼承抽象類以及多個接口,比如:
class Demo extends A implements InA,InB{ // Demo子類繼承於A類,以及接口inA和inB //... ... //實現所有抽象方法 }
3.2 對於一個子接口,可以通過extends來繼承多個父接口,比如:
interface InC extends InA,InB{ //InC子接口繼承父接口inA和inB public void funcC(); //定義抽象方法 }
3.3 接口不能繼承於抽象類,因為extends關鍵字用於繼承同一品種的(接口!=抽象類),而 implements用於繼承於接口的(抽象類!=接口),所以無法實現.
4.接口之工廠設計模式Factory
工廠設計模式,就是說建立一個工廠類,對實現了同一接口的子類們進行統一的實例創建方法,用來提供給用戶調用.而用戶無需去了解這些對象該如何創建以及如何組織.
4.1工廠設計示例
我們以常用的usb為例,首先需要定義一個USB接口,然后寫同一接口的子類們(比如:鍵盤,鼠標,打印機).由於這些子類們都是獨立的,所以我們需要在定義一個工廠類UsbFactory,通過一個方法去統一創建他們,如果不寫工廠類的話,假如有100多個USB子類,那豈不是全部創建都要100多個不同的new才行?所以需要一個工廠類負責管理這些對象.
首先定義USB接口和鍵盤,鼠標子類:
interface USB //USB接口 { public void plugin(); public void out(); } class Keyboard implements USB { public void plugin() { System.out.println("****插上 usb鍵盤****"); } public void out() { System.out.println("****取出 usb鍵盤****"); } } class Mouse implements USB { public void plugin() { System.out.println("****插上 usb鼠標****"); } public void out() { System.out.println("****取出 usb鼠標****"); } }
然后定義UsbFactory工廠類:
class UsbFactory { static public USB getInstance(String name) { if("keyboard".equals(name)) //是否為鍵盤 return new Keyboard(); else if("mouse".equals(name)) //是否為鍵盤 return new Mouse(); else return null; } }
最后寫測試代碼:
public class Test{ public static void main(String args[]) { USB usb1 = UsbFactory.getInstance("keyboard"); //獲取鍵盤類 usb1.plugin(); usb1.out(); USB usb2 = UsbFactory.getInstance("mouse"); //獲取鼠標類 usb2.plugin(); } }
打印如下:
從上面代碼可以看出,通過工廠模式,我們可以更加容易地管理多個相同接口的子類們的操作.
PS:當前工廠模式還是最簡單的,在后續學到反射機制泛型后,在講解.
5.代理模式proxy
代理模式,就是說為一個具體對象提供一個代理對象,該代理對象主要是為了封裝具體對象,並且完成與具體對象有關的所有操作.而具體對象則只需要負責核心業務.
5.1 代理設計示例
我們以生活中的Eat吃為例,首先需要定義一個Eat接口,然后寫一個具體類WhatEat(用來指定具體吃什么),但是在生活中,我們如果吃的不是水果,而是蔬菜,則都要有盤子啊,並且吃之前要先去燒菜盛菜,並且吃完后還要洗碗.而這些操作,我們就不能寫在WhatEat類里,因為WhatEat類只負責核心業務(吃),所以便有了代理對象(完成與具體對象有關的所有操作),接下來便寫一個EatProxy代理節點類來實現這些與WhatEat類操作.
首先定義Eat接口和具體吃的類(WhatEat):
interface Eat { public int TypeVegetable = 0; //蔬菜 public int TypeFruit = 1; //水果 public void eat(int type); } class WhatEat implements Eat { public void eat(int type) { if(type == Eat.TypeVegetable) System.out.println("*** 吃蔬菜 ***"); else System.out.println("*** 吃水果 ***"); } }
然后定義EatProxy代理節點類:
class EatProxy implements Eat { private Eat eatObject; //代理下的具體對象 public EatProxy(Eat eatObject) { this.eatObject = eatObject; } public void eat(int type) //吃東西 { this.eatPrepare(type); this.eatObject.eat(type); this.eatFinish(type); } private void eatPrepare(int type) //吃東西之前的准備工作 { if(type == Eat.TypeVegetable) { System.out.println("正在燒菜... ..."); System.out.println("燒菜完成,正在盛菜"); System.out.println("盛菜完成,准備開吃"); } else { System.out.println("正在洗水果,削皮中..."); System.out.println("削皮完成,准備開吃"); } } private void eatFinish(int type) //吃完東西之后的工作 { if(type == Eat.TypeVegetable) { System.out.println("吃完了,准備洗碗..."); } else { System.out.println("吃完了,准備干其它事..."); } } }
最后寫測試代碼:
public class Test{ public static void main(String args[]) { EatProxy proxy = new EatProxy(new WhatEat()); proxy.eat(Eat.TypeFruit); //通過代理節點吃水果 //分割線 System.out.println(); System.out.println(); proxy.eat(Eat.TypeVegetable); //通過代理節點吃蔬菜 } }
打印如下所示:
從上面可以看到,我們WhatEat類只需要完成吃(核心業務),可以發現通過代理可以降低不同類之間的依賴性
6.總結
學完接口后,它和抽象類之間的區別如下
區別 |
抽象類 |
接口 |
關鍵字 |
abstract class |
interface |
內部組成 |
支持屬性,常量,構造方法,普通方法,abstract抽象方法,靜態方法等 |
支持全局常量,abstract抽象方法 |
子類繼承 |
class 子類 extends 抽象類{ //... ... } |
class 子類 interface 接口1,接口2,...{ //... ... } |
自身繼承 |
抽象類可以繼承於多個接口,或者抽象類. |
接口可以繼承多個接口,但不能繼承抽象類. |
繼承限制 |
單繼承,一個子類只能繼承一個抽象類 |
多繼承,一個子類可以繼承多個接口 |
下章學習:11.JAVA-Object類之finalize(),clone(),toString()等方法覆寫