JAVA編程思想學習總結:第七章——複用類

/*此總結的主要內容是我在學習JAVA過程中,認爲需要記憶的知識點。並結合之前自己學習C++及javascript的相關知識,註明JAVA在一些情況下與這兩門語言的相同及不同之處。*/

(1)組合

只需將對象引用置於新類中,即意味着組合。

(2)繼承

package reusableClass;
//寫該示例的原因是有次做筆試題,問到同時存在兩個main函數時運行會出現什麼樣的情況
class Cleanser{
	private String s="Cleanser";
	public void append (String a){
		s+=a;
	}
	public void dilute(){
		append(" dilute()");
	}
	public void apply(){
		append(" apply()");
	}
	public void scrub(){
		append(" scrub()");
	}
	public String toString(){
		return s;
	}
	public static void main(String[] args){
		Cleanser x=new Cleanser();
		x.dilute();
		x.apply();
		x.scrub();
		System.out.println(x);
	}
}
public class Detergent extends Cleanser{
	public void scrub(){
		append(" Detergent.scrub()");
		super.scrub();//調用基類的方法
	}
	public void foam(){
		append(" foam()");
	}
	public static void main(String[] args){//測試同一個class文件中存在兩個mian方法時的運行情況
		Detergent x=new Detergent();
		x.dilute();
		x.apply();
		x.scrub();
		x.foam();
		System.out.println(x);
		System.out.println("Testing base class:");
		Cleanser.main(args);
	}
	//在有兩個main函數時,運行時需要選擇究竟運行哪個類中的函數,無論選擇哪個,都能正常運行。
}

繼承的構建過程是從基類向外擴散的,所以基類在導出類構造器可以訪問它之前,就已經完成了初始化。

不過這種初始化只會調用不帶參數的基類。如果沒有默認的基類構造器,或者想調用一個帶參數的基類構造器,就必須用關鍵字super顯式的編寫調用基類構造器語句,並且配以適當的參數列表。注意,調用基類構造器必須是在導出類構造器中要做的第一件事。

package reusableClass;
//P130
class Game{
	Game(int i){
		System.out.println("Game constructor");
	}
}
class BoardGame extends Game{
	BoardGame(int i){
		super(i);
		System.out.println("BoardGame one  constructor");
	}
	BoardGame(int i,int j){
		super(i);
		//this(j);//測試用了super調用基類的構造函數後還能否用this調用自身的其它構造函數,結果是不能,
		//即在同一個構造函數中,使用了super調用基類的構造函數,就不能再用this調用自身的構造函數
		//但是可以考慮在該構造函數中利用this調用其它構造函數,然後用this調用的構造函數調用基類構造函數
		//this(i);
		System.out.println("BoardGame constructor");
	}
}
public class Chess extends BoardGame{
	Chess(){
		super(11);
		System.out.println("Chess  constructor");
	}
	public static void main(String[] args){		
	//public static void main(String[] args){
		Chess x=new Chess();
	}
}

PS:在想覆寫基類的某個方法時,可以選擇添加這個註解,防止不想重載時意外的進行了重載。

(3)代理

這是繼承與組合之間的中庸之道。通過實驗成員對象的中一部分方法,即能對成員對象有一定的控制力,又能避免暴露成員對象的所有方法。

(4)組合與繼承之間的選擇

組合技術通常用於想在新類中使用現有類的功能而非它的接口這種情形,往往意味着has-a關係。
繼承是使用一個通用類,併爲了某種特殊需要而將其特殊化,往往意味着is-a關係。
如果需要一個新類向基類進行向上轉型,那麼繼承是必要的。但是如果不需要,則應當好好考慮是否需要繼承。

(5)protected關鍵字(補充上一章內容)

該關鍵字指明就類用戶而言,這是private的,但是對於像模像樣繼承於此類的導出類或其他任何類或其他任何位於同一個包內的類來說,它確是可以訪問的。因爲該關鍵字提供了包訪問權限。

(6)向上轉型

向上轉型即將導出類轉型成基類,這在繼承圖上是向上移動的,所以稱爲向上轉型。
在向上轉型的過程中,類接口中唯一可能發生的事情是丟失方法,而不是獲取它們。這就是爲什麼編譯器在“未曾明確表示轉型”或“未曾指定特殊標記”的情況下,仍然允許向上轉型的原因。

(7)final關鍵字

1、final數據:這意味着一個永不改變的編譯時常量,一個在運行時被初始化的值 ,並且不希望被改變。不過對於引用來說,final使引用恆定不變,一旦引用被初始化指向一個對旬,就無法再把它改爲指向另一個對象。但是,對象自身卻是可以被修改的。雖然java並未提供使任何對象恆定不變的途徑,但是可以通過將所有數據定義成private,並且不提供方法對數據進行修改實現。
即使某數據是final的,也不能認爲在編譯時就知道它的值,因爲可以採用隨機數生成函數對其賦值。
允許數據被聲明爲final但是不在聲明時給定初值,不過編譯器會確保這樣的數據在使用前被初始化——必須在定義處或者構造器中初始化。
2、final參數:這意味着該參數無法在方法中更改參數引用所指向的對象。
3、final方法:
用處一:把方法鎖定,以防任何繼承類修改它的含義,這是出於設計的考慮,想要確保在繼承中使方法行爲保持不變,並且不會被覆蓋。
用處二:效率。該方法的調用將轉爲內嵌,不過現在這種使用方法逐漸不被考慮。
private方法都會隱式地指定爲final方法。
4、final類:當將某個類定義爲final類時,意味着該類不能被繼承類。由於final類禁止繼承,所以final類中所有方法都隱匿指定爲final,而無法覆蓋。
慎用final方法以及final類。

(8)初始化及類的加載

類的代碼在初次使用時才加載。這通常是指加載發生於創建類的第一個對象之時,但是當訪問static域或Static方法時,也會發生加載。
其實構造器也是Static方法,儘管static並沒有顯式的寫出來。所以更準確地講,類是在其任何static成員被訪問時加載的。
package reusableClass;
//P146
/*程序運行過程
 * (1)首先會試圖訪問main函數
 * (2)訪問main函數時,會開始加載main函數所在的類Beetle
 * (3)如果現在加載的類有基類,會繼續加載基類,持續此過程,直到加載到根基類
 * (4)從根基類開始沿繼承鏈向上依次初始化類中的static聲明
 * (5)必要的類被加載完畢後,纔會開始運行main函數
 * (6)創建不帶main函數的其它類過程類同(3)(4),接下來纔可以創建類對象,首先,對象中的所有基本類型會被設爲默認值。然後,構造器纔可以被調用。構造器調用也會沿繼承鏈
 * 先不斷上溯直到根基類,再依繼承鏈順序執行構造器的其餘部分
 */

class Insect{
	private int i=9;
	protected int j;
	Insect(){
		System.out.println("i="+i+",j="+j);
		j=39;
	}
	private static int x1=printInit("static Insect.x1 initialized");
	static int printInit(String s){
		System.out.println(s);
		return 47;
	}
}
public class Beetle extends Insect{
	private int k=printInit("beetle.k initialized");
	public Beetle(){
		System.out.println("k="+k);
		System.out.println("j="+j);
	}
	private static int x2=printInit("static Beetle.x2 initialized");
	public static void main(String[] args){
		System.out.println("main start run");
		Beetle b=new Beetle();
	}
}

總結中有一段話,是我學習這一章的最大收穫。
當你開始設計一個系統時,應該認識到程序感嘆句一種增量過程,猶如人類的學習一樣,這一點很重要,程序開發依賴於實驗,你可以盡能去分析,但當你開始執行一個項目時,仍然無法知道所有的答案。如果將項目視作一種有機的,進化着的生命體去培養,而不是打算像蓋摩天大樓一樣快速見效,就會獲得更多的成功和更訊速的回饋。


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