06 面向物件(中)
阿新 • • 發佈:2019-02-18
----------- android培訓、java培訓、java學習型技術部落格、期待與您交流! ------------
面向物件(中) 1 繼承(Inherit) 概述 多個類中存在相同屬性和行為時,將這些內容抽取到單獨一個類中,那麼多個類只要繼承(extends)那個類即可。 繼承的類為子類(派生類),被繼承的類為父類(超類, 基類)。子類會自動繼承父類所有的方法和屬性。 作用: 當我們定義一個類時,發現另一個類的功能這個類都需要,而這個類又要增加一些新功能時,就可以使用extends 關鍵字繼承那個類,這樣那個被繼承類的功能就都有了,不必重寫編寫程式碼。只要在新類中編寫新的功能即可, 提高了程式碼的複用性。 繼承的出現讓類與類之間產生了關係,提供了多型的前提。 2 特點: Java只支援單繼承,不支援多繼承,但是可以多重繼承。如果一個類繼承多個類,多個類中有相同的方法,子類呼叫 該方法時就不知道該呼叫哪一個類中的方法了。 一個類只能有一個父類,不可以有多個父類: class SubDemo extends Demo{} //Yes class SubDemo extends Demo1,Demo2... //No java支援多層繼承體系: class A{} class B extends A{} class C extends B{} 注意:不要僅為了獲取其它類中某個功能而去繼承,類與類之間要有所屬(" is a")關係,B是A的一種。 成員變數 如果子類中出現非私有的同名成員變數時,子類要訪問本類中的變數,用this;訪問父類中的同名變數 用super。 super的使用和this的使用幾乎一致: this代表的是本類物件的引用;super代表的是當前物件父類物件的引用。 成員函式 當子類出現和父類相同的函式時,子類物件呼叫該函式,會執行子類函式的內容。如同父類的函式被覆蓋一樣。 這種情況是函式的另一個特性: 重寫(覆蓋)(override) 子類物件例項化過程: 子類物件進行初始化時,父類的建構函式也會執行,因為子類的建構函式預設第一行有一條隱式的語句super()語句 它會訪問父類中的空引數建構函式。而且子類中所有的建構函式預設第一行都是super(),在子類中第一行用this關 鍵字去調其它的構造方法,這時系統將不再自動調父類的。但其它建構函式中會呼叫父類建構函式。 繼承細節: 在構造方法中this和super關鍵字只能出現一次,而且必須是第一個語句。 以後在設計類的時候,最好定義一個無參的構造方法,不然子類例項化的時候就容易出錯。父類中沒有空參構造 函式,子類的建構函式必須通過this或者super語句指定要訪問的建構函式。 子類不繼承父類私有成員:父類中私有成員對外不可見,子類物件中無法訪問這些成員。 建構函式不被繼承:建構函式通常用來初始化類的成員變數。而父類和子類的成員變數,初始化方式、建構函式的名 字都不相同。 向上轉型: 子類物件可以當作父類物件使用,因為父類有的功能子類都有。反之不能,因為子類有的父類不一定有。 定義一個父類型別的變數來記住子類物件,這在程式中稱之為向上轉型, 強制型別轉換: 把一個子類當做父類來用的時候,不能呼叫子類特有方法。因為編譯時編譯器會做語法檢查,看到變數是父類型別 就會到父類中查詢是否有該方法,沒有則報錯。這種情況下,就需要將父類型別強轉成子類型別。以(子類名) 變數名形式進行強制型別轉換 強制型別轉換時,無論型別是否匹配編譯都不會報錯,但如果不匹配執行會報錯,可以使用instanceof進行判斷, 判斷是否是該型別。 子類當做父類來用時,不能呼叫子類特有方法,如果一定要呼叫,就需要強制型別轉換回子類。 在做轉換時最好instanceof判斷一下型別是否匹配。 3 函式覆蓋(Override) 子類中出現與父類一模一樣的方法時,會出現覆蓋操作,也稱為重寫或者複寫。 注意事項: 覆蓋時,子類方法許可權一定要大於等於父類方法許可權; 靜態只能覆蓋靜態:因為子類物件當做父類物件使用,父類物件中的方法在子類中必須都能獲取到。 重寫方法必須和被重寫方法的方法名稱、引數列表和返回值型別相同。子類方法返回值型別可以是父類方法返 回值型別的子類。 在子類覆蓋方法中,繼續使用被覆蓋的方法可以通過super.函式名獲取。如果直接呼叫方法,先在當前子類中查詢, 如果子類有會呼叫子類的,使用super只在父類中查詢,子類有沒有都不呼叫; 重寫方法時,不能比父類丟擲更多的異常。子類只能比父類強,不能比父類弱。 父類中的私有方法不可以被覆蓋。 過載(Overload)和重寫(Override)的區別: 過載是方法名相同,引數列表不同,和返回值型別無關。 重寫是方法名、引數列表、返回值型別全相同。 子類當做父類使用時需要注意: 當呼叫類的一個方法時,引數宣告需要一個父類物件,可以將一個子類物件作為實參傳遞。此時方法的形參為父類, 在方法中使用父類變數呼叫方法時,其實是呼叫子類的方法。因為jvm會找到變數引用的地址,根據地址訪問方法, 稱為動態分配。這種機制沒有被使用到類的成員變數上,如果用父類變數訪問屬性,會直接找父類的屬性。 4 super關鍵字 super和this的用法相同: this代表本類物件的引用 super代表父類的記憶體空間的標識。 當子父類出現同名成員時,可以用super進行區分 子類要呼叫父類建構函式時,可以使用super語句。 super和this的區別: this : 代表對當前物件的引用 使用this關鍵字引用成員變數。 使用this關鍵字在自身構造方法內部引用其他構造方法。 使用this關鍵字代表自身類的物件。 使用this關鍵字引用成員方法 super: 代表當前物件裡面的父類的記憶體空間的標識。 在子類的構造方法內部引用父類的構造方法。 在子類中呼叫父類中的成員方法。 在子類中呼叫父類中的成員變數。 5 final關鍵字 final可以修飾類,方法,變數。 final修飾的類不可以被繼承。 final修飾的方法不可以被覆蓋。 final修飾的變數是一個常量。只能被賦值一次。 內部類只能訪問被final修飾的區域性變數。 什麼時候將變數修飾成final: 通常在程式中使用常見的一些不會變化的資料.也就是常量值.比如3.14,這個數直接使用是可以的,但並不利於閱讀, 所以一般情況下,都會被該資料起個容易閱讀的名稱。 使用public static final共同修飾的常量就是全域性常量。通常全部字母大寫。double PI = 3.14; 如果由多個單片語成每個單詞間用下劃線連線; final修飾變數賦值: final修飾成員變數,必須初始化賦值,初始化有兩種 final int NUM = 15; //顯示初始化 NUM = 20; //錯誤,final修飾意味著不可以改變 final int NUM; //建構函式初始化,但是不能兩個一起初始化 Demo() { NUM = 15; } final和private小結: final修飾的類可以訪問 privateb不能修飾外部類,但可以修飾內部類,把外部類私有化是沒有意義的 final修飾的方法不可以被子類重寫 private修飾的方法不可以被子類重寫的,子類看不到父類的私有方法 final修飾的變數只能在顯示初始化或者建構函式初始化的時候賦值一次,以後不允許更改 private修飾的變數,也不允許直接被子類或包中的其它類訪問或修改,但可以通過set和get方法進行訪問 6 抽象類(abstract) 抽象定義:抽象就是從多個事物中將共性的,本質的內容抽取出來。 抽象類:Java中可以定義沒有方法體的方法,該方法的具體實現由子類完成,該方法稱為抽象方法。 包含抽象方法的類就是抽象類。 抽象方法的由來:多個物件都具備相同的功能,但是功能具體內容有所不同,那麼在抽取過程中,只抽取了功能定義, 並未抽取功能主體。在功能宣告,沒有功能主體的方法稱為抽象方法。 例如:狼和狗都有吼叫的方法,可吼叫內容是不一樣的。所以抽象出來的犬科雖然有吼叫功能,但是 並不明確吼叫的細節。 抽象類特點: 抽象方法一定在抽象類中 抽象方法和抽象類都必須被abstract關鍵字修飾 抽象類不可以用new建立物件,因為抽象類本身是不具體的,沒有對應的例項。呼叫抽象方法也沒有沒意義 抽象類中的抽象方法要被使用,必須由子類複寫其所有的抽象方法後,建立子類物件呼叫; 如果子類只覆蓋了部分的抽象方法,那麼該子類還是抽象類。 抽象類中可以有抽象方法也可以有非抽象方法 抽象類和一般類沒有太大的不同,該如何描述事物,就如何描述事物,只不過,該事物出現了一些看不懂得東西。 這些不確定的部分,也是該事物的功能,需要明確出現。但是無法定義主體 抽象類比一般類多了個抽象函式,就是在類中可以定義抽象方法; 抽象類不可以例項化。 特殊:抽象類中可以不定義抽象方法,這樣做僅僅是不讓該類建立物件。 什麼時候定義抽象類: 如果有多個類具有相同的方法宣告,而方法的實現不一樣,這時就可以抽象出父類,將方法在父類中宣告; 在設計軟體時,要盡力抽象父類,繼承關係以3~4層為宜 抽象類中是否有建構函式? 只要是class定義的類裡面就肯定有建構函式,抽象類中的函式是給子類例項化的; 抽象關鍵字abstract不可以和哪些關鍵字共存? final:如果方法被抽象,就需要被覆蓋,而final是不可以被覆蓋,所以衝突。 private:如果函式被私有了,子類無法直接訪問,不能覆蓋 static : 不需要物件,類名即可以呼叫抽象方法。而呼叫抽象方法沒有意義 7 模板設計模式(Template Pattern) 定義:定義功能時,功能的一部分是確定且不允許更改的,但是有一部分是不確定的,而確定的部分在使用不確定的部分, 那麼這時就將不確定的部分暴露出去,由該類的子類去實現。這種方式稱為模板設計模式。 為什麼要使用模板方法設計模式: 在解決一些問題或者設計一個軟體的時候,需要先定義一個模板,就相當於一種事先定義好的協議。 以後要做這系列的事情都按照這個模板來做。這樣就實現統一化管理。 如何實現模板方法設計模式: 定義一個抽象的父類做為模板,定義所有需要的方法; 在父類中實現供外界呼叫的主方法,將方法宣告為final; 根據不同業務需求定義子類實現父類的抽象方法; class Demo { public static void main(String[] args) { SubTemplate st = new SubTemplate();//主函式建立子類物件,呼叫繼承自父類的模板方法 st.method(); } } abstract class Template { //定義模板類,abstract修飾 public final void method() { //定義模板方法,final修飾 run(); //在模板方法中呼叫本類抽象方法 } public abstract void run(); } class SubTemplate extends Template { //子類extends模板類 public void run() { //複寫抽象方法實現子類需要的功能 .... } }