第一節 繼承
第二節 內部類
先來看一段簡單的代碼:
從代碼中就可以看出,內部類的好處。
內部類:將一個類定義在另一個類之中。
一、訪問規則(即使用內部類的好處):
1、內部類方法可以訪問該類所在的類中作用域的成員,包括私有成員變量。
2、內部類可以對同一個包中的其他類隱藏起來,從而不被訪問
3、使用匿名內部類是比較便捷簡單的,這種情況較多的用於AWT設計中。
注:爲何內部類可直接訪問外部類:
由於成員可被對象訪問,內部類中持有了一個外部類的引用,,因此就可以直接用:外部類名.this.成員
二、訪問格式:
1當內部類定義在外部類的成員位置上,而且非私有,可在外部其他類中直接建立內部類對象
格式:外部類名.內部類名 變量名 = 外部類對象.內部類對象
2、當內部類在成員變量的位置上,可被成員修飾符修飾
·private:將內部類在外部類中進行封裝
·static:內部類具備了static的特性,當內部類被static修飾(下面說到的靜態內部類),只可訪問外部類中的static的成員,訪問則受限。
注:(Outer爲外部類名,Inner爲內部類名,function爲非靜態成員)
在其他類中,如何訪問靜態內部類中非靜態成員:new Outer.Inner.function();(建立對象訪問)
在其他類中,如何訪問靜態內部類中的靜態成員:Outer.Inner.function();(可直接訪問)
注意:
1、當內部類中定義了靜態成員,該內部類必須爲靜態的
2、當外部類中靜態方法訪問內部類時,內部類必須爲靜態的
3、內部類一般定義爲private的,而很少定義爲public的。
三、內部類定義原則:------->多在程序設計中使用
1、當描述事物時,事物的內部還有事物,則該事物使用內部類來描述,因爲內部事物要使用外部事物內容
舉例來說:樓房內部還有家庭住戶,家庭住戶中還有房間,這就可以用內部類描述。(總不能訪問一個住戶,就建立一個樓房對象吧,那就可真是有錢人的風範了。)
2、何時定義內部類:
當一個類需要直接訪問另一個類中的成員時,則當這個類放入另一個類中,並將內部類封裝。
3、內部類生成文件:
我們在編譯一個源文件是,如果代碼中有內部類,你會發現,生成的class文件中含有例如這樣的文件:A$C.class。這是爲什麼呢?因爲內部類是一種編譯現象,與虛擬機無關。編譯器將會把內部類翻譯成用$(美元符號)分隔外部類名和內部類名的常規類文件,而虛擬機對此卻一無所知。
四、局部內部類(也稱局部類)
局部內部類:當內部類只在外部類中的某個方法中,創建了這個類型的對象時,且僅使用了一次,那麼可在這個方法中定義局部類。
注:
1、局部內部類不可用public或者private訪問修飾符聲明,它的作用域被限定在了聲明這個局部類的代碼塊中
2、局部類的優勢:
a.對外界完全隱藏,即使此方法所在的類也不可訪問,也就是說,除此方法外,無任何方法知道它的存在。
b.可訪問包含他們的外部類,因還持有外部類的引用;還可訪問局部變量,但是局部變量必須被聲明爲final。
需要注意:局部內部類不可被成員修飾符修飾,如static
五、匿名內部類:
1、匿名內部類:就是內部類的一種簡寫格式。
當只創建該類的一個對象,可不用再爲其命名。所以稱之爲匿名內部類。代碼示例:
內部類必須繼承一個類或實現接口。
但是有一種很特殊,可以不直接繼承一個父類,仍可定義一個匿名內部類。因爲任何類都是Object的子類
3、格式:
new 父類或接口(參數){定義子類的內容};
4、要點說明:
A.其實匿名內部類就是一個匿名子類對象,可以理解爲帶有內容的對象。
B.匿名內部類中的方法最好少於3個,方法少,比較方便簡單,匿名內部類一定要簡化,否則就違背了初衷。
六、靜態內部類
1、概述:
上面提到當內部類在成員變量的位置上,可被成員修飾符static修飾,這就是靜態內部類
2、使用前提:
某些情況下,會把內部類作爲一個隱藏的類,不需要使用內部類引用外部類的對象。因此,可以將外部類聲明爲static,就可以消除產生的引用。在內部類不需要訪問外部類對象的時候,應該使用靜態內部類。
匿名內部類的應用:
第三節 多態
多態:可理解爲事物存在的多種體現形態。又稱爲動態綁定,是java的核心機制之一。
理解:多態是在運行期間,判斷引用實際類型,根據實際類型調用相應的方法。
比如說人又男女之分,動物有貓、狗等之分
一、多態的體現形式:
1、父類的引用指向了自己子類的對象。
2、父類的引用可接收子類的對象。
比如說Person p = new Student();中p指向了Student中的一個對象。如圖:
二、多態的前提:
1、必須是類與類之間的關係,如繼承和實現關係
2、要存在覆蓋的操作,父類中必須由方法被子類覆蓋,即重寫
3、有父類引用指向子類對象
三、多態的利弊:
1、好處:大大提高了程序的擴展性
2、弊端:雖然提高擴展性,但是隻能使用父類的引用訪問父類中的成員,不可預先使用子類。這是由於,子類在父類之後加載,此時還沒有子類被加載。
在下面的代碼中,Animal a = new Cat();是一種“類型提升,向上轉型”的過程。如果要實現Cat中的其他Animal沒有的功能,那麼就需要強制將父類的引用轉換成子類類型,然後再調用子類的方法:
注意:
1、一定不能將父類的對象轉換成子類類型。
2、可轉換的:父類引用指向自己子類的對象時,該引用可被提升,也可被強制轉化。
3、多態自始至終均爲子類對象在做變化
四、多態的特點:
1、在多態中成員函數的特點:
·編譯時期:參閱引用型變量所屬的類中,是否有調用的方法,如果有,則編譯通過,若沒有,則編譯失敗。如上面的代碼中,引用型變量a是父類Animal的類型,其中有eat 的方法,所以沒問題,但是如果調用a.catchM()就會編譯失敗。
·運行時期:參與對象所屬的類中,是否有調用的方法。如引用型變量c是所屬於Cat類型的,可以調用c.catchM()
總結:成員函數在多態調用時,編譯看左邊,運行看右邊。子類中局部有變量就訪問局部的,沒有就訪問成員的變量,成員中沒有的就在父類中找;如果父類中沒有,編譯失敗。
2、在多態中成員變量(和靜態成員)的特點:
·無論編譯和運行,都參考左邊的,即引用型變量所屬的類型。也就是說父類中有自己的變量,則先找父類自己的成員。
·非靜態有重寫的特點,靜態一般不被重寫。
原因:因爲當調用靜態方法時,只要建立子類對象,父類與子類中的靜態方法都會隨之加載入內存,是不需要調用就可直接用類名.方法名的,而不需要對象。只要引用還存在,就看引用變量的類型。
只要這些貓狗都繼承動物就可以了!!
五、多態的應用
1、定義好工具類,即將共同行爲封裝在一個類中。
2、對類型進行抽取,---->多態的產生。
3、操作同一個大類型,對其中的小類型均可操作
第五節 抽象類
一、抽象類含義的概括:
當多個類出現相同功能時,但功能主體不同,這樣可以向上抽取,抽取時只抽取功能定義,而不抽取功能主體。也就是說,我們在從下往上看繼承這個體系結構時,位於上層的類要比下層更具有通用性,也就是說更加抽象,即最上層的祖先(即超類)最具通用性。這時只講上層的類作爲遺傳(或者說派生)下層類的基本的類,而不考慮特定的實例對象。
二、抽象類的特點:
1、抽象方法一定在抽象類中,就是說,一個類中含有抽象方法,這個類也必須是抽象的。
2、抽象方法和抽象類必須被abstract修飾,這是作爲抽象(類或方法)的一個標誌。
3、抽象類不可用new創建對象,因爲調用抽象方法沒有意義(抽象方法爲類中的成員)。
4、抽象類中的方法要被使用,必須由子類複寫所有的抽象方法後,建立子類對象調用,也就是說,如果子類中只覆蓋了部分抽象方法,那麼這個子類仍爲抽象的,是個抽象類。
總結來說,抽象類,是提供功能的,具體實現形式還是需要由子類來實現的,這就強迫了子類複寫抽象類中的抽象方法。需要注意的是,抽象類中是可以有非抽象方法(子類可不必對其複寫)的。
在此,我個人補充一點關於抽象類可以創建數組的東西。
因爲數組也是一種特殊的對象,但是像下面這樣就可以用new。代碼如下:
三、抽象類與一般類無多大區別:
1、描述事物還依然照常描述,只是抽象類中出現了一些看不懂的東西,即功能定義,這些不確定的部分也爲事物的功能,需要明確出來,但無法定義主體。通過抽象方法來表示。
2、抽象類比一般類多了抽象函數,類中可以定義抽象方法,但是不必創建主體內容。
3、抽象類不可以實例化,因爲抽象方法沒意義,無法創建對象
4、特殊之處:抽象類中可以不定義抽象方
第六節 接口
接口:是一種實現關係
一、接口:
接口可理解爲一種特殊的抽象類(但不是),當抽象類中的方法全爲抽象的(即不包含任何非抽象方法),可通過接口表示。---- class用來定義類;而interface定義接口
二、定義接口的格式特點:
接口:interface 實現:implements
1、接口中常見定義:常量、抽象方法
2、接口中成員的固定修飾符:
常量:public static final
方法:public abstract
注意:
A、接口中的成員全爲public,當然那些修飾符是可以省略的,因爲接口會自動設爲相應的權限,但是還是最好加上。
B、當接口中的常量賦值後,不可再進行第二次賦值操作。
C、接口不可創建對象,因爲其中全爲抽象方法,需要被子類實現後,對接口中抽象方法全覆蓋後,子類纔可以實現實例化。
三、接口可被類多實現,即將java中的多繼承改良成多實現。
1、多繼承不可以:
是因爲父類中的方法有方法體,若多個父類存在相同方法(而方法體不同),子類如果多繼承這些父類的話,那麼在運行子類的時候,並不能判斷出要運行這些父類中的哪個方法,因此程序會出現異常。所以多繼承不可以。
2、多實現可以:
是因爲接口中的方法是抽象的,並無方法體,無論這些接口中存在多少個同名的方法,由於無方法體,子類只需要覆蓋一次即可,這個方法的具體實現只是通過子類這一個方法實現的。
3、接口之間是可以多繼承的:
因爲接口中存在的是抽象的方法,接口與接口之間無論是否存在同名函數,這些都是需要子類覆蓋的,這樣就不會出現無法判斷覆蓋哪一個的問題了。
四、接口的特點:
1、接口是對外暴露的規則
2、接口可以用來多實現
3、接口是程序的擴展功能
4、接口與接口之間可有繼承關係
5、接口降低了耦合性
6、類與接口之間是實現關係,且類可以繼承一個類的同時實現多個接口
接口關係:like-a; 類關係:has-a
需要注意的是:兩個或多個接口中不可有不同返回類型的同名抽象函數。
第七節 抽象類和接口的異同
一、概述:
1、抽象類(abstract class):------->一般僅用於被子類繼承。
當多個類出現相同功能時,但功能主體不同,這樣可以向上抽取,抽取時只抽取功能定義,而不抽取功能主體。也就是說,我們在從下往上看繼承這個體系結構時,位於上層的類要比下層更具有通用性,也就是說更加抽象,即最上層的祖先(即超類)最具通用性。這時只講上層的類作爲遺傳(或者說派生)下層類的基本的類,而不考慮特定的實例對象。
2、接口(interface):------->用來建立類與類之間關聯的標準
接口可理解爲一種特殊的抽象類(但不是),當抽象類中的方法全爲抽象的
(即不包含任何非抽象方法),可通過接口表示。
二)聯繫:
1.其實接口是抽象類的延伸,可以將它看做是純粹的抽象類,就是說接口比抽象類還抽象。
2、抽象類和接口都必須被一個類(子類)複寫裏面的全部抽象方法。
3、接口和抽象類都不可創建對象,因爲其中含有抽象方法,需要被子類實現後,
對接口中抽象方法全覆蓋後,子類纔可以實現實例化。
補充:
Java接口和Java抽象類有太多相似的地方,又有太多特別的地方,究竟在什麼地方,纔是它們的最佳位置呢?把它們比較一下,你就可以發現了。
1、Java接口和Java抽象類最大的一個區別,就在於Java抽象類可以提供某些方法的部分實現,而Java接口不可以,這大概就是Java抽象類唯一的優點吧,但這個優點非常有用。
如果向一個抽象類里加入一個新的具體方法時,那麼它所有的子類都一下子都得到了這個新方法,而Java接口做不到這一點,如果向一個Java接口裏加入一個新方法,所有實現這個接口的類就無法成功通過編譯了,因爲你必須讓每一個類都再實現這個方法才行,這顯然是Java接口的缺點。
2、一個抽象類的實現只能由這個抽象類的子類給出,也就是說,這個實現處在抽象類所定義出的繼承的等級結構中,而由於Java語言的單繼承性,所以抽象類作爲類型定義工具的效能大打折扣。
在這一點上,Java接口的優勢就出來了,任何一個實現了一個Java接口所規定的方法的類都可以具有這個接口的類型,而一個類可以實現任意多個Java接口,從而這個類就有了多種類型。
3、從第2點不難看出,Java接口是定義混合類型的理想工具,混合類表明一個類不僅僅具有某個主類型的行爲,而且具有其他的次要行爲。
4、結合1、2點中抽象類和Java接口的各自優勢,具精典的設計模式就出來了:聲明類型的工作仍然由Java接口承擔,但是同時給出一個Java抽象類,且實現了這個接口,而其他同屬於這個抽象類型的具體類可以選擇實現這個Java接口,也可以選擇繼承這個抽象類,也就是說在層次結構中,Java接口在最上面,然後緊跟着抽象類,哈,這下兩個的最大優點都能發揮到極至了。這個模式就是“缺省適配模式”。
在Java語言API中用了這種模式,而且全都遵循一定的命名規範:Abstract +接口名。
Java接口和Java抽象類的存在就是爲了用於具體類的實現和繼承的,如果你準備寫一個具體類去繼承另一個具體類的話,那你的設計就有很大問題了。Java抽象類就是爲了繼承而存在的,它的抽象方法就是爲了強制子類必須去實現的。
使用Java接口和抽象Java類進行變量的類型聲明、參數是類型聲明、方法的返還類型說明,以及數據類型的轉換等。而不要用具體Java類進行變量的類型聲明、參數是類型聲明、方法的返還類型說明,以及數據類型的轉換等。
我想,如果你編的代碼裏面連一個接口和抽象類都沒有的話,也許我可以說你根本沒有用到任何設計模式,任何一個設計模式都是和抽象分不開的,而抽象與Java接口和抽象Java類又是分不開的。
理解抽象,理解Java接口和抽象Java類,我想就應該是真正開始用面向對象的思想去分析問題,解決問題了吧。