java代碼優(yōu)化——靜態(tài)工廠方法與公有構(gòu)造器

通常筒占,我們使用new來創(chuàng)建一個(gè)對象舌涨。這應(yīng)該是最簡單的一種方式。但一個(gè)優(yōu)秀的程序員需要考慮具體的應(yīng)用場景以及性能等問題抓半,從而編寫出優(yōu)秀的代碼喂急。那么我們就從創(chuàng)建對象開始,了解如何創(chuàng)建對象笛求?
本文通過靜態(tài)工廠方法與公有構(gòu)造器的比較廊移,分析各自的優(yōu)缺點(diǎn),提供不同場景下創(chuàng)建對象的推薦方式涣易。

創(chuàng)建對象的兩種方式:

方法1: 使用類公有構(gòu)造器画机。
方法2:使用類的靜態(tài)工廠方法返回一個(gè)實(shí)例。

什么是靜態(tài)工廠方法新症?

靜態(tài)工廠方法(static factory methods)即是static修飾的返回類的實(shí)例的一種靜態(tài)方法步氏。
下面是一個(gè)靜態(tài)工廠方法的簡單示例(摘自JDK 1.7 java.lang.Boolean)。

public final class Boolean implements java.io.Serializable,
       Comparable<Boolean> {

   public static final Boolean TRUE = new Boolean(true);
   public static final Boolean FALSE = new Boolean(false);

   public static Boolean valueOf(boolean b) {
       return (b ? TRUE : FALSE);
   }
}

如果需要獲取一個(gè)Boolean對象徒爹,常規(guī)的方法是new Boolean(true)荚醒,但是也可以如上圖所示Boolean.valueOf(true),這便是靜態(tài)工廠方法隆嗅。

靜態(tài)工廠方法與公有構(gòu)造器的區(qū)別:

1:構(gòu)造方法的名字必須與類名相同界阁。這一特性的優(yōu)點(diǎn)是符合Java語言的規(guī)范,缺點(diǎn)是類的所有重載的構(gòu)造方法的名字都相同胖喳,不能從名字上區(qū)分每個(gè) 重載方法泡躯,容易引起混淆。靜態(tài)工廠方法的方法名可以是任意的丽焊,這一特性的優(yōu)點(diǎn)是可以提高程序代碼的可讀性较剃,在方法名中能體現(xiàn)與實(shí)例有關(guān)的信息。不同的工廠方法有不同名字技健,我們就可以很容易的記住什么方法名可以構(gòu)造什么樣的對象写穴。關(guān)于這一點(diǎn),在 JDK 中最有說服力的一個(gè)例子就是 java.util.concurrent.Executors雌贱,里面N多的靜態(tài)工廠方法:newFixedThreadPool啊送、newSingleThreadExecutor偿短、newCachedThreadPool、newScheduledThreadPool等等
2:每次執(zhí)行new語句時(shí)馋没,都會(huì)創(chuàng)建一個(gè)新的對象昔逗。而靜態(tài)工廠方法每次被調(diào)用的時(shí)候,是否會(huì)創(chuàng)建一個(gè)新的對象完全取決于方法的實(shí)現(xiàn)篷朵。我們調(diào)用靜態(tài)工廠方法返回的可能是緩存的一個(gè)對象纤子,而不是一個(gè)新的對象。這可以減少創(chuàng)建新的對象款票,從來提高性能控硼,前面提到的 Boolean 就是一個(gè)例子。這對于 不可變類的對象特別有用艾少,因?yàn)閷ο蟮牟豢勺冃钥ㄇ恍枰獙?shí)現(xiàn)一個(gè)對象實(shí)例即可。包裝類 Integer 便利用了這種思想缚够,Integer中的靜態(tài)工廠函數(shù)如下:

public static Integer valueOf(int i) {
    assert IntegerCache.high >= 127;
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

上面的代碼把出現(xiàn)概率高的 int 做了一個(gè) cache幔妨,這樣每次只要返回 cache 里的對象,而不用新建一個(gè)對象谍椅。
單例模式便是一種利用了靜態(tài)工廠方法來獲得對象實(shí)例的一種方式误堡。確保該類只有一個(gè)對象實(shí)例。
3:new語句只能創(chuàng)建當(dāng)前類的實(shí)例雏吭,而靜態(tài)工廠方法可以返回當(dāng)前類的子類的實(shí)例锁施。這個(gè)特性讓靜態(tài)工廠方法的可擴(kuò)展性大大的優(yōu)于構(gòu)造函數(shù)。在 JDK 中最典型的應(yīng)該是 java.util.EnumSet杖们。EnumSet 本身是 absract悉抵,我們無法直接調(diào)用它的構(gòu)造函數(shù)。不過我們可以調(diào)用它的靜態(tài)方法 noneOf 來創(chuàng)建對象摘完,RegularEnumSet/JumboEnumSet 都繼承至 EnumSet姥饰,noneOf 根據(jù)參數(shù)返回合適的對象。

public abstract class EnumSet<E extends Enum<E>> extends AbstractSet<E>
    implements Cloneable, java.io.Serializable {

    EnumSet(Class<E>elementType, Enum[] universe) {
    }

    public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) {
        if (universe.length <= 64)
            return new RegularEnumSet<>(elementType, universe);
        else
            return new JumboEnumSet<>(elementType, universe);
    }
}

靜態(tài)工廠方法的缺點(diǎn):

1. 如果一個(gè)類只能通過靜態(tài)工廠方法來獲得實(shí)例孝治,那么該類的構(gòu)造函數(shù)就不能是共有的或受保護(hù)的列粪,那么該類就不會(huì)有子類,即該類不能被繼承谈飒。單例模式中首先要私有化構(gòu)造器岂座。
 2.靜態(tài)工廠方法和其他靜態(tài)方法從名字上看無法區(qū)分,建議在命名靜態(tài)工廠方法的時(shí)候遵循一定的規(guī)則步绸。

valueOf — 返回和參數(shù)一樣的對象掺逼,通常都用作類型轉(zhuǎn)換吃媒,比如 Intger.valueOf(int i)
of — 和 valueOf 類似瓤介。
getInstance — 根據(jù)參數(shù)返回對應(yīng)的對象吕喘,該對象可能是緩存在對象池中的對象。對于單例 singleton刑桑,我們使用無參數(shù)的 getInstance氯质,并且總是返回同一個(gè)對象
newInstance — 和 getInstance 一樣,不過這個(gè)方法的調(diào)用每次返回的都是新的對象祠斧。
getType — 和 getInstance 類似闻察,不過區(qū)別是這個(gè)方法返回的對象是另外一個(gè)不同的類。
newType — 和 getType 類似琢锋,不過每次返回的都是一個(gè)新的對象辕漂。

靜態(tài)工廠方法最主要的特點(diǎn)是:每次被調(diào)用的時(shí)候,不一定要?jiǎng)?chuàng)建一個(gè)新的對象吴超。利用這一特點(diǎn)钉嘹,靜態(tài)工廠方法可用來創(chuàng)建以下類的實(shí)例。

<1>單例類:只有惟一的實(shí)例鲸阻。實(shí)例一旦創(chuàng)建跋涣,其屬性值就不會(huì)被改變。

<2>枚舉類:實(shí)例的數(shù)量有限的類鸟悴。

<3>具有實(shí)例緩存的類:能把已經(jīng)創(chuàng)建的實(shí)例暫且存放在緩存中的類陈辱。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市细诸,隨后出現(xiàn)的幾起案子沛贪,更是在濱河造成了極大的恐慌,老刑警劉巖震贵,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鹏浅,死亡現(xiàn)場離奇詭異,居然都是意外死亡屏歹,警方通過查閱死者的電腦和手機(jī)隐砸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蝙眶,“玉大人季希,你說我怎么就攤上這事∮姆祝” “怎么了式塌?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長友浸。 經(jīng)常有香客問我峰尝,道長,這世上最難降的妖魔是什么收恢? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任武学,我火速辦了婚禮祭往,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘火窒。我一直安慰自己硼补,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布熏矿。 她就那樣靜靜地躺著已骇,像睡著了一般。 火紅的嫁衣襯著肌膚如雪票编。 梳的紋絲不亂的頭發(fā)上褪储,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天,我揣著相機(jī)與錄音慧域,去河邊找鬼乱豆。 笑死,一個(gè)胖子當(dāng)著我的面吹牛吊趾,可吹牛的內(nèi)容都是我干的宛裕。 我是一名探鬼主播,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼论泛,長吁一口氣:“原來是場噩夢啊……” “哼揩尸!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起屁奏,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤岩榆,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后坟瓢,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體勇边,經(jīng)...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年折联,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了粒褒。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,977評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡诚镰,死狀恐怖奕坟,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情清笨,我是刑警寧澤月杉,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站抠艾,受9級特大地震影響苛萎,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一腌歉、第九天 我趴在偏房一處隱蔽的房頂上張望蛙酪。 院中可真熱鬧,春花似錦究履、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至炊甲,卻和暖如春泥彤,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背卿啡。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工吟吝, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人颈娜。 一個(gè)月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓剑逃,卻偏偏與公主長得像,于是被迫代替她去往敵國和親官辽。 傳聞我的和親對象是個(gè)殘疾皇子蛹磺,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,927評論 2 355

推薦閱讀更多精彩內(nèi)容