結合JDK源碼看設計模式——享元模式
前言
在說享元模式之前,你一定見到過這樣的面試題
public class Test { public static void main(String[] args) { Integer a=Integer.valueOf(127); Integer b=new Integer(127); System.out.println(a==b); int c=127; System.out.println(a==c); System.out.println(b==c); } }
問你輸出結果是什麽?有些人可能一下就看出了答案是什麽,有些人可能不是特別清楚。那麽一起看下面的文章。我想你很快就能知曉。
一、享元模式定義
提供了減少對象數量從而改善應用所需的對象結構方式,使用共享技術有效地支持大量細粒度的對象。
二、適用場景
常用於系統底層開發,以便解決系統的性能問題。像數據庫連接池,裏面都是創建好的連接對象,在這些連接對象中有我們需要的則直接拿來用,避免重新創建。如果沒有我們需要的,則創建一個。
在一個系統中有大量相似對象,需要緩沖池的場景。不需要一直創建一個新的對象,可以直接從緩沖池裏拿。這樣可以降低系統內存,同時提高效率。
三、內部狀態與外部狀態
內部狀態:
在享元模式內部,不隨外界的改變而改變。比如說Integer類中的MIN_VALUE和MAX_VALUE兩個值,無論外部傳什麽值。都不會改變這兩個值。
外部狀態:
這就很好理解了,就是隨外部的改變而改變的狀態。比如說Integer類中的value值。
四、Integer中的享元模式
經過上面的介紹,你肯定大概了解了享元模式的概念。那麽我們來看看Integer中的享元模式具體是怎麽樣的吧。
public final class Integer extends Number implements Comparable<Integer> { public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high)return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); } private final int value; public Integer(int value) { this.value = value; } }
上面是我簡化了的Integer類。平常在使用Integer類的時候。你是否思考過用valueOf還是用new創建Integer對象。看完源碼就會發現在valueOf這個方法中它會先判斷傳進去的值是否在IntegerCache中,如果不在就創建新的對象,在就直接返回緩存池裏的對象。這個valueOf方法就用到享元模式。它將-128到127的Integer對象先在緩存池裏創建好,等我們需要的時候直接返回即可。所以在-128到127中的數值我們用valueOf創建會比new更快。如果你還想繼續往裏鉆研,可以去看看IntegerCache如何實現。在這裏我們主要說設計模式。看接下來的一個測試代碼及內存分析。
這裏就可以很清晰的看出來a和b的內存不相等。結果當然是false。回到我們的設計模式上來,在實際的場景中我們更多的是完成緩沖池的創建,來達到緩沖池對象裏面復用的功能。就像下面這種情況,盡管我定義了兩個不同的對象,但實際上我指向的是同一塊內存地址,這樣就減少了系統內存,並且使系統的響應速度更快。
五、總結
在享元模式裏我們要理解享元,“享”就表示共享,“元”表示對象。當我們頻繁需要這個對象的時候,我們考慮new,考慮clone等等這些方法。當然這些方法實際上用的場景和這個不一樣。看上面的內存分析就能知道,我們頻繁需要相同的一個範圍內的對象去做某件事情,我們還需要重新創建對象就會有兩個缺點:第一就是內存浪費,第二就是性能稍慢,特別是我這個對象new起來需要響應的時間很長的時候。這時候考慮用享元模式來先創建一個緩沖池會更好。這個緩沖池可以放在容器中進行存儲,當我們需要的時候直接拿出來用即可。一次創建,多次使用。
在這裏多說一點就是當int類型和Integer比較的時候會自動的拆箱也就是只比較裏面的值大小是否相等,所以上面的答案就是false,true,true。
結合JDK源碼看設計模式——享元模式