前幾天在一篇文章中聊到克隆的話題(參看http://blog.csdn.net/rosen/archive/2004/10/09/129948.aspx)。有朋友對我所提出的克隆可以提高效率深表懷疑,今天我就來具體說明一下。
現(xiàn)在有一典型的 VO 類 Auto(LightWeight):
package com.test; public class Auto implements Cloneable{ public String setNo(String no){ |
接著分別通過使用克隆和不使用克隆的 Bean 來構(gòu)造 Auto 實(shí)例。
使用克隆的 Bean:
package com.test; import java.io.*; public class MyXMLReader { Auto auto=new Auto(); //請比較不同 public ArrayList go() { |
取八次運(yùn)行時間
運(yùn)行時間:172 毫秒
運(yùn)行時間:93 毫秒
運(yùn)行時間:94 毫秒
運(yùn)行時間:141 毫秒
運(yùn)行時間:125 毫秒
運(yùn)行時間:78 毫秒
運(yùn)行時間:203 毫秒
運(yùn)行時間:63 毫秒
沒有使用克隆的 Bean:
package com.test; import java.io.*; public class MyXMLReader { ArrayList al=new ArrayList(); public ArrayList go() { |
取八次運(yùn)行時間
運(yùn)行時間:187 毫秒
運(yùn)行時間:93 毫秒
運(yùn)行時間:172 毫秒
運(yùn)行時間:78 毫秒
運(yùn)行時間:204 毫秒
運(yùn)行時間:79 毫秒
運(yùn)行時間:204 毫秒
運(yùn)行時間:78 毫秒
通過比較,克隆與非克隆,在構(gòu)造 Auto 上花的時間是差不多的。
且慢,讓我們再看下面的 Auto 類。
修改一下 Auto 類的構(gòu)造函數(shù),像這樣(HeavyWeight):
package com.test; public class Auto implements Cloneable{ //以下方法僅僅為了構(gòu)造一個 HeavyWeight 對象。 public String setNo(String no){ |
再看看測試數(shù)據(jù)呢?
使用克隆構(gòu)造 Auto 實(shí)例: 不使用克隆構(gòu)造 Auto 實(shí)例:
運(yùn)行時間:188 毫秒 運(yùn)行時間:2219 毫秒
運(yùn)行時間:78 毫秒 運(yùn)行時間:2266 毫秒
運(yùn)行時間:109 毫秒 運(yùn)行時間:2156 毫秒
運(yùn)行時間:219 毫秒 運(yùn)行時間:2093 毫秒
運(yùn)行時間:110 毫秒 運(yùn)行時間:2266 毫秒
運(yùn)行時間:78 毫秒 運(yùn)行時間:2141 毫秒
運(yùn)行時間:157 毫秒 運(yùn)行時間:2078 毫秒
運(yùn)行時間:78 毫秒 運(yùn)行時間:2172 毫秒
好了,讓我們查看一下 Auto 類。可以看見只是在其構(gòu)造函數(shù)中加入讀取10K XML文件的代碼,而克隆與非克隆運(yùn)行時間卻有近 10 倍的差距!
為什么會這樣?
對象的構(gòu)建不僅僅是“分配內(nèi)存+初始化一些值域”那么簡單,它可能涉及非常多個步驟。所以將“待建對象”的數(shù)量和體積減到最低,才是明智之舉。
讓我們看看創(chuàng)建一個 LightWeight 類都發(fā)生了什么:
1、從 heap 分配內(nèi)存,用來存放 Auto 類的實(shí)例變量,以及一份“實(shí)現(xiàn)專署數(shù)據(jù)”。
2、Auto 類的實(shí)例變量 No 和 Addr,被初始化為缺省值,缺省值都為null。
3、調(diào)用 Auto 類構(gòu)造函數(shù)。
4、Auto 類構(gòu)造函數(shù)調(diào)用其超類(java.lang.Object)的構(gòu)造函數(shù)。
5、java.lang.Object 構(gòu)造函數(shù)返回。
6、對象引用“auto”指向 heap 中完成的 Auto 對象。
再讓我們看看創(chuàng)建一個 HeavyWeight 類都發(fā)生了什么:
1、從 heap 分配內(nèi)存,用來存放 Auto 類的實(shí)例變量,以及一份“實(shí)現(xiàn)專署數(shù)據(jù)”。
2、Auto 類的實(shí)例變量 No、Addr、str、f、sb,被初始化為缺省值,缺省值都為null。
3、File 類的構(gòu)造函數(shù)載入 10K XML 文件得到實(shí)例變量 f,調(diào)用 StringBuffer 的構(gòu)造函數(shù)得到實(shí)例變量 sb,接著調(diào)用 Auto 類構(gòu)造函數(shù)。(在構(gòu)造函數(shù)本體執(zhí)行之前,所有實(shí)例變量的初始設(shè)定值和初始化區(qū)段先獲得執(zhí)行,然后才執(zhí)行構(gòu)造函數(shù)本體。針對 f 和 sb,又從步驟 1 開始重復(fù)這個過程。)
4、Auto 類構(gòu)造函數(shù)中調(diào)用 FileReader 類的構(gòu)造函數(shù)將實(shí)例變量 f 載入,接著調(diào)用 BufferedReader 類的構(gòu)造函數(shù)將 FileReader 類的實(shí)例載入,得到局部變量 inbuffer。(針對 FileReader 類的實(shí)例和 inbuffer,又從步驟 1 開始重復(fù)這個過程。)
5、讀取 inbuffer 中的數(shù)據(jù),實(shí)例變量 sb 被循環(huán)賦值。
6、跳出循環(huán)后,實(shí)例變量 sb 經(jīng)過方法調(diào)用返回給實(shí)例變量 str。
7、Auto 類構(gòu)造函數(shù)調(diào)用其超類(java.lang.Object)的構(gòu)造函數(shù)。
8、java.lang.Object 構(gòu)造函數(shù)返回。
9、對象引用“auto”指向 heap 中完成的 Auto 對象。
通過比較可以看出,建立 HeavyWeight 對象比建立 LightWeight 對象的性能相差很多。步驟 3、4 代價(jià)最高,因?yàn)樗坏貌粚λ膫€聚合對象重復(fù)全過程。
創(chuàng)建對象代價(jià)高昂(特別是 HeavyWeight 對象)!應(yīng)盡量減少創(chuàng)建次數(shù)。創(chuàng)建對象的次數(shù)越少,意味代碼執(zhí)行越快。對于 Auto 類(HeavyWeight),復(fù)用對象引用“auto”所指向的對象才是正解。
對象復(fù)用的一種重要方式就是克隆。任何類如果支持克隆操作,就必須實(shí)現(xiàn) Cloneable 接口,這只是一個標(biāo)識接口,它并沒有實(shí)現(xiàn)任何方法。任何類如果實(shí)現(xiàn) Cloneable,就宣布它支持克隆操作。正如以上這些代碼,利用克隆來提高性能是非常簡單的。
請注意!引用、轉(zhuǎn)貼本文應(yīng)注明原作者:Rosen Jiang 以及出處:http://www.aygfsteel.com/rosen