前幾天在一篇文章中聊到克隆的話題(參看http://blog.csdn.net/rosen/archive/2004/10/09/129948.aspx)。有朋友對我所提出的克隆可以提高效率深表懷疑,今天我就來具體說明一下。
現在有一典型的 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("運行時間:" + (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("運行時間:" + (System.currentTimeMillis() - lasting) + " 毫秒"); return al; }}
通過比較,克隆與非克隆,在構造 Auto 上花的時間是差不多的。 且慢,讓我們再看下面的 Auto 類。修改一下 Auto 類的構造函數,像這樣(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(); }
//以下方法僅僅為了構造一個 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()); } }
使用克隆構造 Auto 實例: 不使用克隆構造 Auto 實例:
運行時間:188 毫秒 運行時間:2219 毫秒 運行時間:78 毫秒 運行時間:2266 毫秒 運行時間:109 毫秒 運行時間:2156 毫秒 運行時間:219 毫秒 運行時間:2093 毫秒 運行時間:110 毫秒 運行時間:2266 毫秒 運行時間:78 毫秒 運行時間:2141 毫秒 運行時間:157 毫秒 運行時間:2078 毫秒 運行時間:78 毫秒 運行時間:2172 毫秒
好了,讓我們查看一下 Auto 類。可以看見只是在其構造函數中加入讀取10K XML文件的代碼,而克隆與非克隆運行時間卻有近 10 倍的差距! 為什么會這樣?
對象的構建不僅僅是“分配內存+初始化一些值域”那么簡單,它可能涉及非常多個步驟。所以將“待建對象”的數量和體積減到最低,才是明智之舉。
讓我們看看創建一個 LightWeight 類都發生了什么:
1、從 heap 分配內存,用來存放 Auto 類的實例變量,以及一份“實現專署數據”。 2、Auto 類的實例變量 No 和 Addr,被初始化為缺省值,缺省值都為null。 3、調用 Auto 類構造函數。 4、Auto 類構造函數調用其超類(java.lang.Object)的構造函數。 5、java.lang.Object 構造函數返回。 6、對象引用“auto”指向 heap 中完成的 Auto 對象。 再讓我們看看創建一個 HeavyWeight 類都發生了什么:
1、從 heap 分配內存,用來存放 Auto 類的實例變量,以及一份“實現專署數據”。 2、Auto 類的實例變量 No、Addr、str、f、sb,被初始化為缺省值,缺省值都為null。 3、File 類的構造函數載入 10K XML 文件得到實例變量 f,調用 StringBuffer 的構造函數得到實例變量 sb,接著調用 Auto 類構造函數。(在構造函數本體執行之前,所有實例變量的初始設定值和初始化區段先獲得執行,然后才執行構造函數本體。針對 f 和 sb,又從步驟 1 開始重復這個過程。) 4、Auto 類構造函數中調用 FileReader 類的構造函數將實例變量 f 載入,接著調用 BufferedReader 類的構造函數將 FileReader 類的實例載入,得到局部變量 inbuffer。(針對 FileReader 類的實例和 inbuffer,又從步驟 1 開始重復這個過程。) 5、讀取 inbuffer 中的數據,實例變量 sb 被循環賦值。 6、跳出循環后,實例變量 sb 經過方法調用返回給實例變量 str。 7、Auto 類構造函數調用其超類(java.lang.Object)的構造函數。 8、java.lang.Object 構造函數返回。 9、對象引用“auto”指向 heap 中完成的 Auto 對象。 通過比較可以看出,建立 HeavyWeight 對象比建立 LightWeight 對象的性能相差很多。步驟 3、4 代價最高,因為它不得不對四個聚合對象重復全過程。 創建對象代價高昂(特別是 HeavyWeight 對象)!應盡量減少創建次數。創建對象的次數越少,意味代碼執行越快。對于 Auto 類(HeavyWeight),復用對象引用“auto”所指向的對象才是正解。 對象復用的一種重要方式就是克隆。任何類如果支持克隆操作,就必須實現 Cloneable 接口,這只是一個標識接口,它并沒有實現任何方法。任何類如果實現 Cloneable,就宣布它支持克隆操作。正如以上這些代碼,利用克隆來提高性能是非常簡單的。請注意!引用、轉貼本文應注明原作者:Rosen Jiang 以及出處:http://www.tkk7.com/rosen
Powered by: BlogJava Copyright © Rosen