關於JAVA你必須知道的那些事(四):單例模式和多態 原

好吧,今天一定要把面向對象的最後一個特性:多態,給說完。不過我們先來聊一聊設計模式,因爲它很重要。

設計模式

官方的解釋是,設計模式是:一套被反覆使用,多數人知曉的,經過分類編目,代碼設計經驗的總結。說人話就是:軟件開發人員在軟件開發過程中面臨的一般問題的解決方案。

常見的設計模式可以參看這張圖片:

我們可以對其按照作用來進行分類:: 關注對象創建過程的:創建型模式; 類和對象組合:結構型模式; 對象之間的通信過程:行爲型模式

單例模式

單例模式: 一個類有且僅有一個實例,並且自行實例化向整個系統提供,它的目的就是使得類的一個對象成爲該類系統中的唯一實例。

要點:

  1. 某個類只能有一個實例;;
  2. 必須自行創建實例;
  3. 必須自行向整個系統提供這個實例;

實現: 1、只提供私有的構造方法; 2、只含有一個該類的靜態私有對象; 3、提供一個靜態公有方法用於創建、獲取靜態私有對象。

對於1的理解:private是訪問限制能力最強的修飾符,只能在當前類內被使用。也就是說經過private修飾,該類的對象在類外無法通過new關鍵字直接實例化,這樣可以做到限制類實例化產生;

對於2的理解:1可以實現有且僅有一個實例,static修飾的靜態成員可以滿足該類有且僅有一個,所有的對象都共享這一個靜態成員;

對於3的理解:類似於封裝,必須向外部系統提供唯一的公有訪問方法。

在java中實現單例模式有2種方式:餓漢式和懶漢式。

餓漢式:在類中私有對象創建的過程中立刻進行實例化操作(言外之意,不管你用不用,我先把這個給做了)如此看來確實挺餓的;

懶漢式::對象創建時並不立刻進行實例化操作,而是在靜態公有方法中進行實例化操作(言外之意,你不需要我就不做)如此看來確實挺懶的。

餓漢式

餓漢式:在類中私有對象創建的過程中立刻進行實例化操作(言外之意,不管你用不用,我先把這個給做了):

package SingleExample;
// 餓漢式:創建對象實例的時候直接初始化;(空間換時間)

public class SingletonOne {

	//1、創建類中私有的構造方法
	private SingletonOne() {
		
	};
	
	//2、創建該類型的私有靜態實例
	private static SingletonOne instance = new SingletonOne();
	
	//3、創建公有的靜態方法,返回靜態實例對象
	public static SingletonOne getinstance() {
		return instance;
	};
}

測試代碼:

package SingleExample;

public class SingleOneTest {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		SingletonOne one =SingletonOne.getinstance();
		
		SingletonOne two =SingletonOne.getinstance();
		
		System.out.println(one==two);   //輸出結果爲true
	} 
}

懶漢式

懶漢式::對象創建時並不立刻進行實例化操作,而是在靜態公有方法中進行實例化操作(言外之意,你不需要我就不做):

package SingleExample;
//懶漢式:創建對象實例的時候並不初始化;(時間換空間)

public class SingletonTwo {
	// 1、創建類中私有的構造方法
	private SingletonTwo() {

	};

	// 2、創建靜態的該類實例對象
	private static SingletonTwo instance = null;

	// 3、創建公有的靜態方法,提供實例對象
	public static SingletonTwo getinstance() {
		if (instance == null) {
			instance = new SingletonTwo();
		}
		return instance;
	};
}

相應的測試代碼爲:

package SingleExample;

public class SingleTwoTest {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		SingletonTwo one = SingletonTwo.getinstance();

		SingletonTwo two = SingletonTwo.getinstance();

		System.out.println(one == two);   //輸出結果爲true
	}

}

單例模式兩種實現總結

餓漢式在類加載時就創建實例,第一次加載速度快; 懶漢式在第一次使用時才進行實例化,第一次加載速度慢;

餓漢式:空間換時間 懶漢式:時間換空間

餓漢式,類在加載時進行了對象的實例化創建,即使多個進程進行併發操作,訪問的實例也是唯一的,餓漢式線程安全。

懶漢式,第一次使用纔會實例化,多個線程併發操作時,由於時間片的切換,可能導致線程風險。

但是懶漢式的線程危險是可以規避的,通過關鍵字Synchronized實現線程的鎖定,也可以通過靜態內部類和枚舉保證操作時的線程唯一。

單例模式優缺點及使用場景

單例模式的優點: 1、在內存中只有一個對象,節省內存空間; 2、避免頻繁的創建銷燬對象, 提高性能; 3、避免對共享資源的多重佔用。

單例模式的缺點: 1、擴展比較困難; 2、如果實例化後的對象長期不利用,系統將默認爲垃圾進行回收,造成對象狀態丟失。

使用場景: 1、創建對象時佔用資源過多,但同時又需要用到該類對象; 2、對系統內資源要求統一讀寫,如讀寫配置信息; 3、當多個實例存在可能引起程序邏輯錯誤,如號碼生成器;

每一種設計模式都是針對場景,針對某種具體問題的,具體場景應當進行具體分析,選用合適的設計模式。

多態

終於開始進入多態的世界了,在這裏你將全面瞭解多態的特點及使用。

多態你可以理解爲不同類的對象對同一消息做出不同的響應。

一般而言,多態分爲編譯時多態和運行時多態這兩種。

編譯時多態:也稱設計時多態,它是通過方法重載來實現的,編譯器在編譯狀態可以進行不同行爲的區分。

而運行時多態,則必須要求程序運行時,動態決定調用哪個方法。

我們通常在Java中的多態指的就是運行時多態。

實現多態的必要條件: 滿足繼承;父類引用指向子類對象

向上轉型

所謂的向上轉型也指隱式轉型(自動轉型)。說通俗一點就是父類引用指向子類實例,它可以調用子類重寫父類的方法以及父類派生的方法,但是無法調用子類特有方法。

舉個例子,假如Dog這個類繼承了我們Animal這個類,我們不僅可以這樣:

Dog dog =new Dog();
Animal animal =new Animal();

你還可以這樣:

Animal dog2 =new Dog();

這就是將一個子類對象轉型爲一個父類對象,這個很好理解,對吧。

接下來我們來說一下,向下轉型,顧名思義就是和向上轉型相反的操作了,是的,你很聰明。

向下轉型

向下轉型也稱強制類型轉換。它是子類引用指向父類實例,我們在之前就用過了,還記得我們在重寫Object類的equals方法時,就將父類Object強制轉換,然後才調用子類特有的方法。

向下轉型並不是可以隨便轉換的,需要滿足一定的轉換條件。我們可以通過instanceof這個運算符來判斷是否能進行強制類型轉換。

通過上面的圖片,我們可以很清楚的知道instanceof的作用就是判斷左邊對象是否是右邊這個類的實例,如果是就返true,否則就返回false。

因此,我們在進行向下轉型的時候,可以用instanceof來判斷一個對象是否滿足某個類的實例特徵。滿足,我們才進行類型轉換,否則強制轉換會報錯。

總結一下: 向上轉型: 父類引用指向子類對象。即小變大。

向下轉型: 子類引用指向父類對象。即大變小。

需要注意的是:父類中static修飾的方法允許被子類使用,但是不允許被子類重寫,所以向上轉型之後,只能調用到父類原有的靜態方法。如果此時要用子類中的,只能通過向下轉型來實現。

抽象類

某個父類只是知道其子類應該包含怎樣的方法,但無法準確知道這些子類如何實現這些方法,這樣我們的抽象類就派上用場了。

抽象類可以避免子類設計的隨意性,還可以避免父類無意義的實例化。

你只需知道,修飾抽象類要用abstract這個關鍵詞,抽象類不可以直接被實例化。

抽象方法

我們前面說過,父類只是規定子類擁有該項能力,但在父類中具體實現它是沒有任何意義的,因此該方法應設置爲抽象方法。

public abstract void test();

你記住,抽象方法是不允許有方法體的,也就是不能有花括號。而且此時子類必須實現父類的抽象方法,如果你不實現,那麼這個類就必須被設置爲抽象類(不設置就會報錯),然後由繼承它的類去具體實現相應的方法。簡單來說就是一句話:抽象方法中不允許包含方法體,子類需要重寫父類的抽象方法。

一般抽象類適用於這種情況:1、父類中的實現沒有意義;2、提醒子類必須要去自己實現自己的這個方法。

通常子類變多了之後,你新建一個類只要繼承了抽象的父類,IDE會自動提醒你實現父類中的抽象方法的,你不實現就會報錯。

抽象類和抽象方法的使用

你可以使用abstract關鍵詞來定義抽象類,抽象類不能被直接實例化,你可以通過向上轉型完成對象實例,只能被繼承。

abstract關鍵詞定義抽象方法 ,你不需要具體實現也不能具體實現,也就是花括號不能有。

需要注意的是:抽象類可以沒有抽象方法,但包含抽象方法的類一定是抽象類。

我們前面說過,當一個類繼承抽象類,必須實現類中的抽象方法。如果不重寫,則必須將該子類也變爲抽象類,由其子類來實現,否則會報錯。

注意:static final private 不可以和abstract同時出現(因爲抽象方法是要在子類中進行重寫的,而private只能在當前類被訪問,final方法不允許被子類重寫,static靜態不允許被子類重寫。)

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