第五條:避免創(chuàng)建不必要的對象

一般來說,最好能重用對象而不是在每次需要的時候就創(chuàng)建一個相同功能的新對象捶箱。重用方式既快速坑鱼,又流行膘流。如果對象是不可變的絮缅,他始終可以被重用。

反面例子:

String S = new String("dali");

該語句每次執(zhí)行的時候都創(chuàng)建一個新的String實例呼股,但是這些創(chuàng)建對象的動作全部都是不必要的耕魄。

改進后:

String s = "dali";

這個版本只用了一個String實例,而不是每次執(zhí)行的時候都創(chuàng)建一個新的實例彭谁。而且吸奴,它可以保證,對于所有在同一臺虛擬機中運行的代碼缠局,只要他們包含相同的字符串字面常量则奥,該對象就會被重用。

除了重用不可變的對象之外狭园,也可以重用那些已知不會被修改的可變對象逞度。

public class Person{

? ? ?private ?final Date ?birthDate;

? ? ?public ?Person(Date birthDate){

? ? ? ? ? ? ? ?this.birthDate=new Date(birthDate.getTime());

? ? ?}

? ? ?public boolean isBabyBoomer(){

? ? ? ? ? ? ?Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT+8"));

? ? ? ? ? ? ?gmtCal.set(1946,Calendar.JANUARY,1,0,0,0);

? ? ? ? ? ? ?Dateboom Start = gmtCal.getTime();

? ? ? ? ? ? ?gmtCal.set(1965,Calendar.JANUARY,1,0,0,0);

? ? ? ? ? ? ?DateboomEnd=gmtCal.getTime();

? ? ? ? ? ? ?return birthDate.compareTo(boomStart)>=0&&

? ? ? ? ? ? ? ? ? ? ? ? ? ?birthDate.compareTo(boomEnd)<0;

? ? ? ? }

}

isBabyBoomer每次調(diào)用的時候,都會創(chuàng)建一個Calendar妙啃、一個TimeZone和兩個Date實例档泽,這是不必要的。

正確方式:

public class Person{

? ? ?private final Date birthDate;

? ? ?public Person(DatebirthDate){

? ? ? ? ? ? ? ?this.birthDate=newDate(birthDate.getTime());

? ? ? }

? ? ? private static final Date BOOM_START;

? ? ? private static final Date BOOM_END;

? ? ? static{

? ? ? ? ? ? ?Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT+8"));

? ? ? ? ? ? ?gmtCal.set(1946,Calendar.JANUARY,1,0,0,0);

? ? ? ? ? ? ?BOOM_START=gmtCal.getTime();

? ? ? ? ? ? ?gmtCal.set(1965,Calendar.JANUARY,1,0,0,0);

? ? ? ? ? ? ?BOOM_END=gmtCal.getTime();

? ? ? ?}

? ? ? public boolean isBabyBoomer(){

? ? ? ? ? ? ? ?return ?birthDate.compareTo(BOOM_START)>=0&&

? ? ? ? ? ? ? ? ? ? ? birthDate.compareTo(BOOM_END)<0;

? ? ? ? }

}

這種只在初始化時候創(chuàng)建Calendar揖赴、TimeZone和Date實例一次馆匿,而不是在每次調(diào)用isBabyBoomer的時候創(chuàng)建這些實例。如果isBabyBoomer方法被頻繁地調(diào)用燥滑,這種方法將會顯著地提高性能渐北。

避免進行隱式裝箱

自動裝箱是Java5引入的一個特性,即自動將原始類型的數(shù)據(jù)轉(zhuǎn)換成對應(yīng)的引用類型铭拧,比如int轉(zhuǎn)為Integer等赃蛛。

這種特性,在編碼時稍有不注意就可能創(chuàng)建了不必要的對象了搀菩。

反面例子:

Integer?sum?=?0;

for?(int?i?=?1000;?i?<5000;?i++)?{

? ? ? ? sum?+=i;

}

上面的代碼sum+=i可以看成sum =sum+i呕臂,但是+不適用于Integer對象,首先sum進行自動拆箱操作肪跋,進行數(shù)值相加操作歧蒋,最后在自動裝箱轉(zhuǎn)換成Integer對象。其內(nèi)部實現(xiàn)如下:

int?result?=?sum.intValue()?+?i;

Integer?sum?=?new?Integer(result);

由于這里聲明的sum為Integer類型州既,在上面的循環(huán)中會創(chuàng)建將近4000個無用的Integer對象谜洽,在這個循環(huán)中,會降低程序的性能并且加重了垃圾回收的工作量吴叶。因此在我門編程時阐虚,需要注意到這一點,正確地聲明 變量類型蚌卤,避免因為自動裝箱引起的性能問題实束。

謹慎選用容器

java提供了很多編輯的容器集合來組織對象奥秆。比如ArrayList,HashMap等磕洪。

容器雖然使用起來方便吭练,但存在一些問題,就是他們會自動擴容析显,這其中不是創(chuàng)建新的對象鲫咽,而是創(chuàng)建一個更大的容器對象。這就意味著將占用更大的內(nèi)存空間谷异。

以HashMap為例分尸,當我們put key和value時,會檢測是否需要擴容歹嘹,如需要則雙倍擴容箩绍。

public?V?put(K?key,?V?value)?{

? ? ?if?(key?==?null)

? ? ? ? ? ?return?putForNullKey(value);

? ? int?hash?=?hash(key.hashCode());

? ? int?i?=?indexFor(hash,?table.length);

? ?for?(Entry?e?=?table[i];?e?!=?null;?e?=?e.next)?{

? ? ? ?Object?k;

? ? ? ?if?(e.hash?==?hash?&&?((k?=?e.key)?==?key?||?key.equals(k)))?{

? ? ? ? ? ?V?oldValue?=?e.value;

? ? ? ? ? ?e.value?=?value;

? ? ? ? ? ?e.recordAccess(this);

? ? ? ? ? ?return?oldValue;

? ? ? ?}

}

modCount++;

addEntry(hash,?key,?value,?i);

return?null;

}


void addEntry(int?hash,?K?key,?V?value,?int?bucketIndex)?{

Entry?e?=?table[bucketIndex];

? ? ? ? table[bucketIndex]?=?new?Entry(hash,?key,?value,?e);

? ? ? ? if?(size++?>=?threshold)

? ? ? ? ? ? ?resize(2?*?table.length);

}

建議:預(yù)估一個較大的容量值,避免多次擴容


? ? ? 不要錯誤地認為本條碼所介紹的內(nèi)容暗示著“創(chuàng)建對象的代價非常昂貴尺上,我們應(yīng)該要盡可能地避免創(chuàng)建對象”材蛛。相反,由于小對象的構(gòu)造器只做很少量的顯式工作怎抛,所以卑吭,小對象的創(chuàng)建和回收動作是非常廉價的,特別是在現(xiàn)代的JVM實現(xiàn)上更是如此马绝。通過創(chuàng)建附加的對象豆赏,提升程序的清晰性、簡潔性和功能性富稻,這通常是件好事掷邦。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市椭赋,隨后出現(xiàn)的幾起案子抚岗,更是在濱河造成了極大的恐慌,老刑警劉巖纹份,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件苟跪,死亡現(xiàn)場離奇詭異,居然都是意外死亡蔓涧,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進店門笋额,熙熙樓的掌柜王于貴愁眉苦臉地迎上來元暴,“玉大人,你說我怎么就攤上這事兄猩≤哉担” “怎么了鉴未?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長鸠姨。 經(jīng)常有香客問我铜秆,道長,這世上最難降的妖魔是什么讶迁? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任连茧,我火速辦了婚禮,結(jié)果婚禮上巍糯,老公的妹妹穿的比我還像新娘啸驯。我一直安慰自己,他們只是感情好祟峦,可當我...
    茶點故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布罚斗。 她就那樣靜靜地躺著,像睡著了一般宅楞。 火紅的嫁衣襯著肌膚如雪针姿。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天厌衙,我揣著相機與錄音距淫,去河邊找鬼。 笑死迅箩,一個胖子當著我的面吹牛溉愁,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播饲趋,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼拐揭,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了奕塑?” 一聲冷哼從身側(cè)響起堂污,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎龄砰,沒想到半個月后盟猖,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡换棚,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年式镐,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片固蚤。...
    茶點故事閱讀 38,716評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡娘汞,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出夕玩,到底是詐尸還是另有隱情你弦,我是刑警寧澤惊豺,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站禽作,受9級特大地震影響尸昧,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜旷偿,卻給世界環(huán)境...
    茶點故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一烹俗、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧狸捅,春花似錦衷蜓、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至朽褪,卻和暖如春置吓,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背缔赠。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工衍锚, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人嗤堰。 一個月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓戴质,卻偏偏與公主長得像,于是被迫代替她去往敵國和親踢匣。 傳聞我的和親對象是個殘疾皇子告匠,可洞房花燭夜當晚...
    茶點故事閱讀 43,612評論 2 350

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