前幾天在一篇文章中聊到克隆的話題(參看http://blog.csdn.net/rosen/archive/2004/10/09/129948.aspx)。有朋友對我所提出的克隆可以提高效率深表懷疑,今天我就來具體說明一下。
現(xiàn)在有一典型的 VO 類 Auto(LightWeight):
package com.test;
public class Auto implements Cloneable{ private String No; private String Addr; public Object clone() throws CloneNotSupportedException{ return super.clone(); }
public String setNo(String no){ return this.No=no; } public String getNo(){ return this.No; } public String setAddr(String addr){ return this.Addr=addr; } public String getAddr(){ return this.Addr; }}
使用克隆的 Bean:
import java.io.*;import java.util.*;import org.dom4j.*;import org.dom4j.io.*;
public class MyXMLReader {
Auto auto=new Auto(); //請比較不同 ArrayList al=new ArrayList();
public ArrayList go() { long lasting = System.currentTimeMillis(); try { File f = new File("data_100k.xml"); SAXReader reader = new SAXReader(); Document doc = reader.read(f); Element root = doc.getRootElement(); Element foo; for (Iterator i = root.elementIterator("VALUE"); i.hasNext();) { foo = (Element) i.next(); auto.setNo(foo.elementText("NO")); auto.setAddr(foo.elementText("ADDR")); al.add(auto.clone()); //請比較不同 } } catch (Exception e) { e.printStackTrace(); } System.out.println("運(yùn)行時間:" + (System.currentTimeMillis() - lasting) + " 毫秒"); return al; }}
ArrayList al=new ArrayList();
public ArrayList go() { long lasting = System.currentTimeMillis(); try { File f = new File("data_100k.xml"); SAXReader reader = new SAXReader(); Document doc = reader.read(f); Element root = doc.getRootElement(); Element foo; for (Iterator i = root.elementIterator("VALUE"); i.hasNext();) { foo = (Element) i.next(); Auto auto=new Auto(); //請比較不同 auto.setNo(foo.elementText("NO")); auto.setAddr(foo.elementText("ADDR")); al.add(auto); //請比較不同 } } catch (Exception e) { e.printStackTrace(); } System.out.println("運(yùn)行時間:" + (System.currentTimeMillis() - lasting) + " 毫秒"); return al; }}
通過比較,克隆與非克隆,在構(gòu)造 Auto 上花的時間是差不多的。 且慢,讓我們再看下面的 Auto 類。修改一下 Auto 類的構(gòu)造函數(shù),像這樣(HeavyWeight):
package com.test;import java.io.*;
public class Auto implements Cloneable{ private String No; private String Addr; private String str; private File f = new File("data_10k.xml"); private StringBuffer sb=new StringBuffer(); public Object clone() throws CloneNotSupportedException{ return super.clone(); }
//以下方法僅僅為了構(gòu)造一個 HeavyWeight 對象。 public Auto(){ try{ BufferedReader inbuffer=new BufferedReader(new FileReader(f)); while ((str=inbuffer.readLine())!=null){ sb.append(str); } }catch(Exception e){ System.out.println(e.toString()); } }
使用克隆構(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 代價最高,因?yàn)樗坏貌粚λ膫€聚合對象重復(fù)全過程。 創(chuàng)建對象代價高昂(特別是 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.tkk7.com/rosen
Powered by: BlogJava Copyright © Rosen