1. 程式人生 > >06 面向物件(中)

06 面向物件(中)

----------- 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() {			//複寫抽象方法實現子類需要的功能
		....
	    }
	}