當描述一批對象的時候,我們通常會將一些共有的方法和屬性進行向上抽取,抽取出它們的父類,通過繼承達到代碼復用的目的。
但是,每個子類的方法某些方法業務都是獨一無二的,它們都重寫了父類中定義的該方法。而這個時候,父類就沒有必要提供該方法的具體實現了,只需要將該方法定義為抽象方法,而且該類的存在也僅僅是為了讓子類繼承,實現代碼的復用,那么我們就可以將該類定義為抽象類。
抽象類必須使用abstract修飾符來修飾類名,有抽象方法的類只能被定義成抽象類,抽象類里可以沒有抽象方法,也可以有具體實現的方法。

1、 抽象類必須使用abstract修飾符來修飾類,抽象方法也必須使用abstract來修飾,抽象方法不能有方法體。

2、 抽象類不能被實例化,不能使用new關鍵字來調用抽象類的構造器創建抽象類的實例。即使抽象類里不包含抽象方法,也不能被創建實例。

3、 抽象類可以包含成員變量、方法(普通方法和抽象方法都可以)、構造器、初始化塊、內部類5種成分。抽象類的構造器不能用來創建實例,主要是用于被其子類調用。
abstract class Fu{ publicFu(String str){ System.out.PRintln(str); }}class Zi1 extends Fu{ publicZi1(){ super("abcd"); }}4、含有抽象方法的類只能被定義為抽象類。
定義抽象方法只需要在普通方法上增加abstract修飾符,并且把方法體去掉,在后面加分號即可。
注意:抽象方法和空方法完全不是同一個概念。一個是抽象方法,一個是普通方法,只不過普通方法沒有具體代碼。

定義抽象類
只需要在普通類上增加abstract修飾符即可。甚至一個普通類(沒有抽象方法)增加abstract修飾符后也將變成抽象類。
//定義Shape抽象類和實現類三角形,圓形求周長方法。獲取形狀方法
class AbstractTest{ //使用抽象類,進行解耦操作 static XingZhuang xz; public static void main(String[] args){ if(true){ xz= new Circle(12.12 ,"紅色"); }else{ xz= new Rect(12,12,"黑色"); } double zc= xz.zhouChang(); String info = xz.getInfo(); }}abstract class XingZhuang //形狀{ abstract double zhouChang(); abstract String getInfo(); String color; } class Circle extends XingZhuang{ public Circle(double radius , String color){ this.radius= radius; this.color= color; } double radius; double zc= 0; double zhouChang(){ zc =Math.PI * 2 * radius; return zc; } String getInfo(){ return color + "圓形的周長是:"+ zc; }}class Rect extends XingZhuang{ double chang; double kuang; double zc= 0; public Rect(double chang , double kuang,String color){ this.chang= chang; this.kuang= kuang; this.color= color; } double zhouChang(){ zc = (chang + kuang) * 2; return zc; } String getInfo(){ return color + "矩形的周長是:"+ zc; }}
抽象類的作用
抽象類不能被創建實例,只能當成父類被繼承。普通類描述對象是對某一類事物的抽象,而抽象類則是更高層次的抽象。從多個具有相同特征的類中抽象出一個抽象類,以這個抽象類作為其子類的模板,從而避免了子類設計的隨意性。
抽象類體現的就是一種模板的設計,抽象類作為多個子類的模板,子類建立在抽象類的基礎上進行擴展,改造,但子類總體上大致會保留這些抽象類的行為。
如果編寫一個抽象類,父類可以提供多個子類通用的抽象方法,并把具體實現推遲到子類去實現。當然,父類也可以提供通用的普通方法,這些普通方法可以作為輔助方法用來輔助子類。
接口
抽象類是從多個類中抽象出來的模板,如果將這種抽象進行的更加徹底,則可以提煉出一種更加特殊的抽象類--接口(interface),接口里不能包含普通方法,接口里所有的方法都是抽象方法。

接口的概念:
在計算機主板上,有N多個接口插槽,供我們拓展計算機的功能,如顯卡、內存、硬盤、聲卡等。主板只是定義了一下接口規則,這些生產顯卡、內存等廠家生產的產品必須實現該接口的規則,才可以將它們的產品插到主板上。
那么,在java中,接口就是定義了一種規范,接口定義的某一批類所需要遵守的規范,接口并不關心這些類的內部狀態數據,也不關心這些類里的方法實現的細節,它只是規定了這批類里必須提供某些方法,提供這些方法的類就可以滿足實際需要。
可見,接口是從多個類中抽象出來的規范,接口不提供任何實現。接口體現的是規范和實現分離的設計哲學。
class JieKou{ public static void main(String[] args){ DianNao dn = new DianNao(); //調用方法,傳入實現Input接口的實現類 dn.getInput(new JianPan()); //調用方法,傳入實現Input接口的實現類 dn.getInput(new ShouXie()); }} class DianNao{ //定義了獲取信息需要的組件,只需要遵循Input接口就OK void getInput(Input input){ System.out.println("輸入了" + input. inputMethod()); }}//定義了輸入設備的規范
interface Input{ String inputMethod();}//遵循了輸入設備的規范的鍵盤class JianPan implements Input{ publicString inputMethod(){ return"鍵盤"; }}//遵循了輸入設備的規范的手寫板class ShouXie implements Input{ public String input Method(){ return "手寫"; }}
讓規范和實現分離正是接口的好處,弱化了各個組件之間的依賴性,即松耦合設計。例如主機上的各種插槽,只要顯卡遵守規范,就可以與主機進行通信,至于顯卡是如何設計,內部怎么實現,主板無需關心。
類似的,軟件系統之間的各個模塊之間也應該采用這種面向接口的耦合,從而降低各個模塊之間的耦合,為系統提供了更好的可擴展性和可維護性。
因此,接口定義的是多個類共同的公共行為的規范,這些行為是與外部交流的通道,這就意味著接口里通常是定義一組公用方法。
定義規則:
interface 接口名 extends 父接口1、父接口2
{
0到多個抽象方法的定義
0到多個內部類、接口、枚舉
0到多個默認方法或類方法
}
詳細說明:
1、命名規范與類名一致。大駝峰。
2、接口可以有多個直接父接口,但是接口只能繼承接口,不可以繼承類。

由于接口定義的是一種規范,因此接口里不能包含構造器和初始化塊。接口可以包含成員變量(只能是靜態常量)、方法(只能是抽象實例方法、類方法或默認方法)、內部類(包括內部接口、枚舉)定義。
對比接口和類的定義方式,不難發現接口的成員比類里的成員少了兩種,而且接口里的成員變量只能是靜態常量,接口里的方法只能是抽象方法。

class JieKou{ public static void main(String[] args){ DaoDian daoDian = new DaoDianImpl(); String[] cusInfo = daoDian.cusInfo(); String mrs = daoDian.mrs(cusInfo[0]); System.out.println(mrs); daoDian.zhixing(mrs, cusInfo[1]); }}
//顧客到店服務
interface DaoDian{ //獲取預約顧客的信息 String[] cusInfo(); //安排顧客預約的美容師 String mrs(String name); //執行預約的服務 void zhixing(String name , String fuwu);}class DaoDianImpl implements DaoDian{ //獲取預約顧客的信息 public String[] cusInfo(){String[] arr = new String[]{"顧客小紅" , "Spa"}; retur narr; } //安排顧客預約的美容師 public String mrs(String name){ if(name.equals("顧客小紅")){ return "小蘭"; } return "小明"; } //執行預約的服務 public void zhixing(String name , String fuwu){ System.out.println(name+"美容師執行了" +fuwu+"項目"); }}前面已經說了,接口里定義的是多個類共同的公共行為規范,因此接口里的所有成員,包括常量、方法、內部類都是public訪問權限。定義接口成員時,可以省略訪問控制修飾符,如果指定訪問控制修飾符,則只能使用public訪問控制修飾符。
對于接口里的定義的靜態常量而言,他們是接口相關的,因此系統會自動為這些成員變量增加static和final兩個修飾符。也就是說,在接口中定義成員變量時,不管是否使用public static final修飾符,接口里的成員變量總是使用者3個修飾符來修飾,而且接口里沒有構造器和初始化塊,因此接口里定義的成員變量只能是在定義時指定默認值。
如下兩行代碼的結果是完全一樣的。
int MAX_SIZE = 50;
public static final int MAX_SIZE = 50;
接口里定義的方法只能是抽象方法,因此系統會將自動為普通方法增加public abstract修飾符。
1、 屬性一律使用靜態修飾符:
如下,接口中定義屬性沒有使用static修飾,但是在測試類中,直接使用接口.name就可以訪問該屬性,說明該屬性是靜態的。


屬性權限修飾符是:public
如下,屬性是默認修飾符,但是在不同包下的類中,也可以訪問。

屬性默認使用final修飾:
2、 方法默認使用abstract、public
在接口中定義方法,使用默認權限修飾,子類也使用默認權限修飾,報錯,說接口的該方法是public,證明了,接口方法默認使用public修飾。



接口的繼承:
接口的繼承和類的繼承不一樣,接口是完全支持多繼承的,即一個接口可以有多個直接父接口。和類繼承想死,接口擴展某個父接口,將會獲得負借口定義的所有抽象方法、常量。
一個接口繼承多個父接口時,多個父接口排在extends關鍵字之后,多個父接口之間以英文逗號隔開。
//TODOclass JieKou implements JieKouC,JieKouB,JieKouA{ public void methodc(){} public void methodb(){} public void methoda(){}}interface JieKouA{ void methoda();}interface JieKouB{ void methodb();}interface JieKouC{ void methodc();} 接口的多層繼承,實現接口,如果接口還有父類接口,那么實現類必須實現包括接口和其父接口的所有抽象方法:
class JieKou implements JieKouC{ public void methodc(){} public void methodb(){} public void methoda(){}}interface JieKouA{ void methoda();}interface JieKouB extends JieKouA{ void methodb();}interface JieKouC extends JieKouB{ void methodc();}使用接口
接口不能用于創建實例,但接口可以用于聲明引用類型變量。當使用接口來聲明引用類型變量時,這個引用類型變量必須引用到其實現類的對象,這也是屬于多態特性。
class JieKou{ public static void main(String[] args){ Person person = new Man(); }}interface Person{ }class Man implements Person{}
接口的主要用途就是被實現類實現,除此之外,,接口主要用途如下:
1、 定義變量,也可以用于進行強制類型轉換。
class JieKou{ public static void main(String[] args){ Manman = new Man(); Person person = (Person)man; }}2、 調用接口中定義的常量。

3、被其他類實現,實現功能的擴展
一個類可以實現一個或多個接口,繼承只能使用extends關鍵字實現單繼承,實現接口使用implements關鍵字多實現。
//TODOclass JieKou{ public static void main(String[] args){ Man man = new Man(); Person person = (Person)man; }}class Person{ }class Man extends Person implements Working,ShanYang{ void zhengqian(){} void xiwan(){} void shanYang(){}}class WoMan extends Person implements ShanYang{ void shanYang(){}}interface Working{ void zhengqian(); void xiwan();}interface ShanYang{ void shanYang();}實現接口與繼承父類相似,一樣可以獲得所實現接口里定義的常量(成員變量)、方法(包括抽象方法和默認方法)
讓類實現接口需要定義后增加implements部分,當需要實現多個接口時,使用逗號隔開,一個類可以繼承一個父類,并且同時實現多個接口。implements必須放在extends之后。

一個類實現一個或多個接口后,這個類必須實現這些接口里所定義的全部抽象方法(也就是重寫),否則就定義為抽象類。
一個類實現某個接口,就會擁有該接口的定義的常量、方法等。因此也可以將實現接口理解為一種特殊的繼承。相當于一個更加徹底的抽象類。
//TODO實現兩個接口,兩個接口都可以接受該對象
class JieKou{ public static void main(String[] args){ Working working = new Man(); ShanYang shanYang = (ShanYang)working; }}class Person{ }class Man extends Person implements Working,ShanYang{ public void zhengqian(){} public void xiwan(){} public void shanYang(){}} interface Working{ void zhengqian(); void xiwan();}interface ShanYang{ void shanYang();}接口不能繼承任何類,但是所有接口類型的變量都可以直接賦值給Object類型的引用變量。因為既然是存在的對象,那么肯定是Object對象的子類對象。
class JieKou{ public static void main(String[] args){ Working working = new Man(); Object obj =working; }}接口和抽象類區別
接口和抽象類很相似,都具有如下特征:
1、接口和抽象類都不能被實例化,他們都需要被繼承或實現。
2、接口和抽象類都可以包含抽象方法,實現或繼承他們的普通類必須重寫抽象方法。
但接口和抽象差別也是非常大,這種差別主要體現在二者的設計目的上。
接口作為系統與外界的交互的窗口,接口體現的是一種規范,對于接口的實現者而言,接口規定了實現者必須向外提供哪些服務,對于接口調用者而言,接口規定了調用者可以調用哪些服務,以及如何調用。當一個程序中使用了接口時,接口是多個模塊間的耦合標準。當多個程序之間使用了接口,那么該接口就是多個程序之間的通訊標準。
抽象類則不一樣,抽象類作為多個子類共同父類,他所體現的是一種模板設計。抽象類作為多個子類的抽象父類,可以被當成系統實現過程中的中間產品,必須有更進一步的完善。
除此之外,在使用用法上也有差別:
1、接口里只能包含抽象方法,抽象類則完全可以包含普通方法。
2、接口不能定義靜態方法,抽象類可以。
3、接口只能定義靜態常量,不能定義普通成員變量,抽象類則可以定義靜態常量,也可以定義普通成員變量。
4、接口不含構造器,抽象類可以包含構造器和構造代碼塊。
抽象類是可以被實例化,只不過是子類對象創建的時候,創建抽象類父類對象。所以,抽象類是可以有靜態代碼塊,構造代碼塊,構造方法,抽象類就既可以有實例變量、也可以有靜態變量。 接口沒有構造器、構造代碼塊,所以,接口不能被實例化,也不可能有實例變量。
接口沒有靜態代碼塊,那么,就無法為接口定義的常量賦值,那么接口就規定:定義接口屬性是需要在聲明時直接賦值。

4、 一個類最多只能有一個直接父類,包括抽象類;但一個類可以多個實現接口,通過實現多個接口可以彌補java單繼承的不足。
當新增功能時,發現,該功能并不屬于該類的父類,就需要使用接口,來擴展一下該功能。
面向接口編程:
接口體現的是一種規范和實現分離的設計哲學,充分利用接口可以降低各個模塊之間的耦合性,從而提高系統的擴展性和維護性。
面向接口編程設計在這里不做太多解釋,這個不屬于現階段內容,如果有興趣可以參閱:
http://baike.baidu.com/link?url=cjLmsENJgShmA6DGWi2RBh9gccRbn7dAXgOoaEuRrBiM9voyhUof8PvFSHI-HhxEp-ueDyacewd1ZwQdDWdsxfFMOZCS4UkojZkZr5P1vDDc3kQvMJr_vbJBx3bUPWIovM1oKESe9CJAf3fvj4eAca
基于這種原則,很多軟件架構設計都倡導“面向接口”編程。而不是面向實現類編程。希望通過面向接口編程來降低程序的耦合。
工廠模式
工廠模式(Factory Pattern)是 Java 中最常用的設計模式之一。這種類型的設計模式屬于創建型模式,它提供了一種創建對象的最佳方式。
在工廠模式中,我們在創建對象時不會對客戶端暴露創建邏輯,并且是通過使用一個共同的接口來指向新創建的對象。
介紹
意圖:定義一個創建對象的接口,讓其子類自己決定實例化哪一個工廠類,工廠模式使其創建過程延遲到子類進行。
主要解決:主要解決接口選擇的問題。
何時使用:我們明確地計劃不同條件下創建不同實例時。
如何解決:讓其子類實現工廠接口,返回的也是一個抽象的產品。
關鍵代碼:創建過程在其子類執行。
應用實例: 1、您需要一輛汽車,可以直接從工廠里面提貨,而不用去管這輛汽車是怎么做出來的,以及這個汽車里面的具體實現。 2、Hibernate 換數據庫只需換方言和驅動就可以。
優點: 1、一個調用者想創建一個對象,只要知道其名稱就可以了。 2、擴展性高,如果想增加一個產品,只要擴展一個工廠類就可以。 3、屏蔽產品的具體實現,調用者只關心產品的接口。
缺點:每次增加一個產品時,都需要增加一個具體類和對象實現工廠,使得系統中類的個數成倍增加,在一定程度上增加了系統的復雜度,同時也增加了系統具體類的依賴。這并不是什么好事。
使用場景: 1、日志記錄器:記錄可能記錄到本地硬盤、系統事件、遠程服務器等,用戶可以選擇記錄日志到什么地方。 2、數據庫訪問,當用戶不知道最后系統采用哪一類數據庫,以及數據庫可能有變化時。 3、設計一個連接服務器的框架,需要三個協議,"POP3"、"IMAP"、"HTTP",可以把這三個作為產品類,共同實現一個接口。
注意事項:作為一種創建類模式,在任何需要生成復雜對象的地方,都可以使用工廠方法模式。有一點需要注意的地方就是復雜對象適合使用工廠模式,而簡單對象,特別是只需要通過 new 就可以完成創建的對象,無需使用工廠模式。如果使用工廠模式,就需要引入一個工廠類,會增加系統的復雜度。
http://www.runoob.com/design-pattern/factory-pattern.html
//TODO
class Test{ public static void main(String[] args){ //調用工廠類獲取對象方法,傳遞對象信息 HuaTu huatu = Factory.getHuaTu("Rect"); //調用返回對象的畫圖方法 huatu.huaTu(); }} interface HuaTu{ void huaTu();}class Circle implements HuaTu{ public void huaTu(){ System.out.println("繪制圓形"); }}class Rect implements HuaTu{ public void huaTu(){ System.out.println("繪制矩形"); }}class Factory{ //接收傳入信息 static HuaTu getHuaTu(String str){ //根據傳入信息判斷返回什么類型對象 if(str.equals("Circle")){ return new Circle(); }elseif(str.equals("Rect")){ return new Rect(); } return null; }}
新聞熱點
疑難解答