Java基礎-->面向對象

第一節   繼承


當兩個事物之間存在一定的所屬關係,即就像孩子從父母那裏得到遺傳基因一樣,當然,java要遺傳的更完美,這兩個類中,一個繼承的類(爲子類或者基礎類)可以從被繼承的類(爲父類或者超類)中獲得一些屬性和方法,而不必再自己創建新方法(在不需要複寫的情況等)。

一、特點:
1、提高代碼複用性,定義在父類中的成員(變量和方法),可以被子類重複使用;
2、讓類與類之間產生關係,這樣就會有多態的特性。使得應用起來更方便。
需要注意的是:
A.不可以只是爲了獲取其他類的功能,簡化代碼就一味的使用繼承;必須是類與類之間有所屬關係,纔可以用繼承,這種關係稱爲“is-a”。
B.java語言中,只支持單繼承,不支持多繼承。究其原因,是因爲多繼承容易帶來安全隱患:
a.當多個父類中定義了相同的功能,且功能內容不同時,子類對象並不確定要運行哪一個,這就造成了程序的混亂而導致異常出現。
b但是java保留了這種機制,並改良了多繼承爲多實現,而且接口就可以多繼承。

二、使用繼承體系中的功能
1、如果使用體系,要先對體系中父類的描述進行參閱,瞭解父類中的共性功能,即可以使用該體系了。這樣既可以減少查閱時間,也能更系統的瞭解體系結構,以及父類的功能。
2、具體調用父類中的功能的時候,需要創建子類對象,通過子類對象對父類方法調用,實現繼承。
爲何要通過創建子類對象調用父類中的方法呢?原因如下:
a.父類很可能不可以創建對象,如父類是一個抽象類或者接口,這就需要子類創建對象,調用方法。
b.創建子類對象,可以使用更多的功能,如父類公有的,和子類中自定義的特有功能。
三、子父類出現後,類成員的特點:
類成員:變量、函數、構造函數
1、變量:
子父類中出現非私有的同名成員變量是,子類訪問本類的同名時,要用this關鍵字(如果省略了this,仍是代表本類的變量);子類訪問父類同名變量時,用super關鍵字。
補充:this和super兩者都存在與方法區中。
    this:本類對象引用,那個對象調用this所在的函數,this就代表那個對象。
    super:父類對象引用,用於子類初始化父類構造函數時等。
2、.函數:(覆蓋(重寫))
當子類同父類出現相同函數時,子類對象調用該函數時,會運行子類內容,如同覆蓋穀類函數一樣。實際上並沒有覆蓋父類的函數,如果還需要調用父類的這個方法,需要用super.方法名即可。
示例:
繼承在內存中的加載方式:

應用:
a.當子類繼承父類時,就沿襲了父類的功能,在子類中,雖然具備該功能,,但是其內容卻與父類不同,此時,可覆蓋父類的方法(即保留),使用新特性。
注意:
第一、子類權限必須大於或等於父類的才能覆蓋;
第二、靜態只能覆蓋靜態。
b.用於擴展(新功能或內容等)
示例:

3、子父類構造函數:子類的構造函數中有一個隱式的構造函數
特點:在對子類對象進行初始化時,父類構造函數也在運行,而且是在子類之前運行。因爲子類構造函數默認第一行有一條隱式語句:super();(沒有顯式的繼承父類的類中,是默認繼承Object的,所以構造函數第一條語句仍是super();),因此會首先訪問父類中空參數的構造函數(在不手動加入含有參數的super的語句的情況下),這是系統默認的。所有的構造函數均是如此。
需要注意的是:a.如果父類中無空參數構造函數(即父類中顯式的構造了含有參數的構造函數),必須手動加入父類中該構造函數。b.構造函數不存在覆蓋,子類中的構造函數必定至少有一個會訪問父類中的構造函數。
舉例:

爲什麼子類一定要訪問父類的構造函數呢?
第一、由於父類中的數據可直接獲取,所以子類對象建立時,需要先查看父類是如何對這些數據進行初始化的。因此,子類在初始化的時候須先訪問父類構造函數,如果父類對這些數據初始化後,可以使用,子類就無需在進行多餘的操作了。
第二、如果要訪問指定的構造函數,可手動定義super語句的方式來指定特定的構造函數。
注意:super語句一定要定義在子類構造函數的第一條語句,即第一行,因爲要先初始化父類構造函數,然後再初始化子類構造函數,子類構造函數判斷是否父類的可用,不可用則子類將其覆蓋掉,這樣子類在可以方便選擇。
構造函數中,this和super語句都必須在第一語句出現因爲兩者都是用來初始化的,既然是初始化,就要首先存在,就只能進行一次,因此不能同時作爲第一條語句出現。

總結:子類實例化過程
1、子類所有的構造函數默認均訪問父類中的空參數構造函數,因爲子類每個構造函數內的第一行均有一句隱式的super();語句。
2、當父類中悟空參數構造函數時,子類必須手動通過super語句的形式指定要訪問的父類中的構造函數
3、子類構造函數也可手動指定this語句,來訪問本類中的構造函數,但子類中至少要有一個構造函數訪問父類的構造函數。

還有一個問題,就是繼承是對封裝性的一個挑戰,這個問題是用final解決的。具體關於final在此不再贅述了。



第二節   內部類


先來看一段簡單的代碼:


從代碼中就可以看出,內部類的好處。

內部類:將一個類定義在另一個類之中。

一、訪問規則(即使用內部類的好處):

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、匿名內部類:就是內部類的一種簡寫格式。

當只創建該類的一個對象,可不用再爲其命名。所以稱之爲匿名內部類。代碼示例:



2、定義前提:

內部類必須繼承一個類或實現接口。

但是有一種很特殊,可以不直接繼承一個父類,仍可定義一個匿名內部類。因爲任何類都是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、操作同一個大類型,對其中的小類型均可操作



第四節   包
一、包概述:
java中的包就相當於系統中的文件夾。
當我們需要將各個類分門別類的存放的時候,或者含有不同功能的相同類名的時候,需要用到包(package)。包可以將相關的類放在一起,並可以將兩個或多個相同文件名的文件放在不同包中。

二、包的作用:
1、爲避免多個類重名的情況,如果出現兩個相同名字的類,可通過包將兩者區分,從而避免衝突
2、對類文件進行分類管理,可以將相關的一些類放在同一個包中。
3、給類提供多層命名空間,如a包中的Demo.class文件即packagea.Demo.class

三、規則:
1、寫在程序的第一行,因爲是包下的類,先有包了,才能將類放進去。
2、類名的全稱:包名.類名
3、包是一種封裝形式,是java封裝性的體現。

四、包與包之間的訪問:
1、要訪問其他包中的類,需要定義類名的全名:包名.類名
2、如果包不再當前目錄下,需要設置classpath,告知虛擬機包的執行路徑
3、有了包,範圍變大,一個包中的類要被訪問,必須有足夠大的權限。
注:
a.包與包間進行訪問,被訪問的包中的類以及類中的成員,需要public修飾。
b.不同包中的子類還可直接訪問父類中被protected權限修飾的成員。包與包間可使用的權限有兩種:public和protected。
c.其中protected只用於覆蓋。




五、包的導入:
1、爲了簡化類名的書寫,使用import導入
如:import packa.packb.packc.*;  是將包packa下的包packb下的包packc下的所有類導入進來。
注:如果需要packb下還有類需要導入,則還需在導入,
如: import packa.packb.*;
2、注意事項:
a.兩個包中有相同類名文件,當再統一類中創建對象時,需要加上包名.類名創建。
b.建議定義包名不要重複,可以使用URL來定義,因爲URL是唯一的。
   如:www.itcast.com---->package cn.itcast.Demo以及cn.itcast.Test

Java中各個主要包的作用(javax開頭的都是擴展包
java.utilJAVAutility工具包,包含一些使用工具類,如定義系統特性、使用與日期日曆相關的函數等的類
java.langJAVAlanguage核心語言包;如String、Math、Integer、System、Thread,提供常用的功能。特殊之處是不需要導入,是作爲默認導入的包。
java.awtJAVAabstractwindow toolkit,抽象窗口工具包;包含了構成抽象窗口共具體的多個類,這些類用於構建和管理應用程序的圖形用戶(GUI)。
java.applet是創建APPLET的必須包;包含applet運行時所需要的一些類。
java.netJAVA有關網絡操作的包。
java.ioJAVA的輸入輸出流的包。
java.sqlJAVA的數據庫操作包。
javax.swing是新的界面包。



第五節   抽象類

一、抽象類含義的概括:

當多個類出現相同功能時,但功能主體不同,這樣可以向上抽取,抽取時只抽取功能定義,而不抽取功能主體。也就是說,我們在從下往上看繼承這個體系結構時,位於上層的類要比下層更具有通用性,也就是說更加抽象,即最上層的祖先(即超類)最具通用性。這時只講上層的類作爲遺傳(或者說派生)下層類的基本的類,而不考慮特定的實例對象。

二、抽象類的特點:

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類,我想就應該是真正開始用面向對象的思想去分析問題,解決問題了吧。






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章