分享
 
 
 

循证克隆

王朝java/jsp·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

前几天在一篇文章中聊到克隆的话题(参看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 来构造 Auto 实例。

使用克隆的 Bean:

package com.test;

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;

}

}

取八次运行时间

运行时间:172 毫秒

运行时间:93 毫秒

运行时间:94 毫秒

运行时间:141 毫秒

运行时间:125 毫秒

运行时间:78 毫秒

运行时间:203 毫秒

运行时间:63 毫秒

没有使用克隆的 Bean:

package com.test;

import java.io.*;

import java.util.*;

import org.dom4j.*;

import org.dom4j.io.*;

public class MyXMLReader {

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;

}

}

取八次运行时间

运行时间:187 毫秒

运行时间:93 毫秒

运行时间:172 毫秒

运行时间:78 毫秒

运行时间:204 毫秒

运行时间:79 毫秒

运行时间:204 毫秒

运行时间:78 毫秒

通过比较,克隆与非克隆,在构造 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());

}

}

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;

}

}

再看看测试数据呢?

使用克隆构造 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://blog.csdn.net/rosen

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有