﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-P to P-文章分类-JAVA</title><link>http://www.blogjava.net/nomigd/category/9656.html</link><description>何以解忧，唯有学习！让每一个人都能Open Source </description><language>zh-cn</language><lastBuildDate>Wed, 28 Feb 2007 21:00:44 GMT</lastBuildDate><pubDate>Wed, 28 Feb 2007 21:00:44 GMT</pubDate><ttl>60</ttl><item><title>JavaEye三周年，大家聊聊最喜欢的帖子一、你擦了吗？确定擦了？真的确定擦了？</title><link>http://www.blogjava.net/nomigd/articles/66760.html</link><dc:creator>何以解忧，唯有学习！让每一个人都能Open Source </dc:creator><author>何以解忧，唯有学习！让每一个人都能Open Source </author><pubDate>Thu, 31 Aug 2006 00:48:00 GMT</pubDate><guid>http://www.blogjava.net/nomigd/articles/66760.html</guid><wfw:comment>http://www.blogjava.net/nomigd/comments/66760.html</wfw:comment><comments>http://www.blogjava.net/nomigd/articles/66760.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/nomigd/comments/commentRss/66760.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/nomigd/services/trackbacks/66760.html</trackback:ping><description><![CDATA[
		<span class="postbody">      应用try-finally，我们可以在异常满天飞的程序里保证我们的关键资源被按时正确清理。一个最常见的应用就是jdbc的Connection, Statement, ResultSet等。 <br /><br />但是，我最近惊奇地发现，不知道怎么正确清理资源的人大有人在，即使是一些java老手。 <br /><br />看一个例子先： <br /><br /></span>
		<table cellspacing="1" cellpadding="3" width="90%" align="center" border="0">
				<tbody>
						<tr>
								<td>
										<span class="genmed">
												<b>java代码: </b>
										</span>
								</td>
						</tr>
						<tr>
								<td class="code">
										<div style="FONT-FAMILY: 'Courier New', Courier, monospace">
												<br />
												<span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">void</span> f<span style="COLOR: #000000">(</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">{</span><br />  <span style="COLOR: #aaaadd" ?="">Connection</span> conn = ...; <br />  <span style="COLOR: #aaaadd" ?="">Statement</span> stmt = conn.<span style="COLOR: #000000">createStatement</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">)</span>; <br />  <span style="COLOR: #aaaadd" ?="">ResultSet</span> rset = ...; <br />  ... <br /><span style="COLOR: #000000">}</span></div>
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<span class="postbody">
				<br />典型的jdbc程序。但是也是典型的光着屁股，其臭如兰地走出厕所的典范。哎，你擦屁股了吗？ <br />有的哥们振振有辞：我不用管，我的jdbc driver/我的应用服务器/garbage collector会处理的。 <br />这是典型的糊涂蛋逻辑。没有close()，jdbc driver, 应用服务器怎么知道你是拉完了，还是光着屁股出去接个电话先？难不成这driver都智能地会算命了？ <br />garbage collector倒确实管得了。不过，garbage collector不一定运行啊。你要是有10G得内存，要是你的程序就用了10M，garbage collector说不定就一直睡大觉。而且，就算它管，也许等你光着屁股上班被警察抓起来之后才匆匆赶到，你等的起吗？ <br /><br /><br />好，有人说，那我擦，我擦，我擦擦擦。行了吧？ <br /><br /><br /></span>
		<table cellspacing="1" cellpadding="3" width="90%" align="center" border="0">
				<tbody>
						<tr>
								<td>
										<span class="genmed">
												<b>java代码: </b>
										</span>
								</td>
						</tr>
						<tr>
								<td class="code">
										<div style="FONT-FAMILY: 'Courier New', Courier, monospace">
												<br />
												<span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">void</span> f<span style="COLOR: #000000">(</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">{</span><br />  <span style="COLOR: #aaaadd" ?="">Connection</span> conn = ...; <br />  <span style="COLOR: #aaaadd" ?="">Statement</span> stmt = conn.<span style="COLOR: #000000">createStatement</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">)</span>; <br />  <span style="COLOR: #aaaadd" ?="">ResultSet</span> rset = ...; <br />  rset.<span style="COLOR: #000000">close</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">)</span>; <br />  conn.<span style="COLOR: #000000">close</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">)</span>; <br />  ... <br /><span style="COLOR: #000000">}</span></div>
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<span class="postbody">
				<br />
				<br />呵呵。我的傻哥们，你只擦了靠近后背的那三公分，剩下的嘛，别人看不见你就乐得省土块儿了是么？ <br /><br />按jdbc标准，ResultSet, Statement, Connection都要close()，也许有的driver会在Connection关闭的时候同时正确清理ResultSet, Statement，但是，并没有一条规定让所有的driver都这么做。 <br />另外，也许你的Connection是从一个池里面来的，它只是回到池中去，如果你不关闭Statement, ResultSet，下一个拿到这个Connection的人也许就倒霉了！ <br />做事要有始有终，既然开始擦了，就擦干净点儿，行不？（那个，谁谁谁，借我个防毒面具先！） <br /><br /><br />ok，有个讲卫生的小傻子这样擦： <br /><br /><br /></span>
		<table cellspacing="1" cellpadding="3" width="90%" align="center" border="0">
				<tbody>
						<tr>
								<td>
										<span class="genmed">
												<b>java代码: </b>
										</span>
								</td>
						</tr>
						<tr>
								<td class="code">
										<div style="FONT-FAMILY: 'Courier New', Courier, monospace">
												<br />
												<span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">void</span> f<span style="COLOR: #000000">(</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">{</span><br />  <span style="COLOR: #aaaadd" ?="">Connection</span> conn = ...; <br />  <span style="COLOR: #aaaadd" ?="">Statement</span> stmt = conn.<span style="COLOR: #000000">createStatement</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">)</span>; <br />  <span style="COLOR: #aaaadd" ?="">ResultSet</span> rset = ...; <br />  rset.<span style="COLOR: #000000">close</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">)</span>; <br />  stmt.<span style="COLOR: #000000">close</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">)</span>; <br />  conn.<span style="COLOR: #000000">close</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">)</span>; <br />  ... <br /><span style="COLOR: #000000">}</span></div>
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<span class="postbody">
				<br />
				<br />然后洋洋得意地说：我是好孩子，我天天擦屁屁。 <br /><br /><br />是啊，多听话的孩子呀。可惜，某天，这孩子正坐在马桶上美着呢，妈妈喊了嗓子：二傻子，吃饭啦。 <br />哦！吃饭。二傻子裤子都没提就窜出来了，熏得妈妈一个跟头。 <br /><br />什么问题，傻子做事一根筋，不能打扰，一旦有异常情况出现，屁股就忘了擦了。 <br /><br /><br /><br />所以，我这里郑重提醒大家，请用"try-finally"！它独有凹槽，防止侧漏...（糟了，串台了） <br /><br />是啊，java老手们都不是傻子，都知道用try-finally的，可是，别美，你现在就保不齐擦没擦屁股呢！ <br /><br /><br />常见擦法： <br /></span>
		<table cellspacing="1" cellpadding="3" width="90%" align="center" border="0">
				<tbody>
						<tr>
								<td>
										<span class="genmed">
												<b>java代码: </b>
										</span>
								</td>
						</tr>
						<tr>
								<td class="code">
										<div style="FONT-FAMILY: 'Courier New', Courier, monospace">
												<br />
												<span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">void</span> f<span style="COLOR: #000000">(</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">{</span><br />  <span style="COLOR: #aaaadd" ?="">Connection</span> conn = <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">null</span>; <br />  <span style="COLOR: #aaaadd" ?="">Statement</span> stmt = <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">null</span>; <br />  <span style="COLOR: #aaaadd" ?="">ResultSet</span> rset = <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">null</span>; <br />  <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">try</span><span style="COLOR: #000000">{</span><br />    conn = ...; <br />    stmt = ...; <br />    rset = ...; <br />    ... <br />  <span style="COLOR: #000000">}</span><br />  <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">finally</span><span style="COLOR: #000000">{</span><br />      <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">if</span><span style="COLOR: #000000">(</span>rset!=<span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">null</span><span style="COLOR: #000000">)</span>rset.<span style="COLOR: #000000">close</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">)</span>; <br />      <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">if</span><span style="COLOR: #000000">(</span>stmt!=<span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">null</span><span style="COLOR: #000000">)</span>stmt.<span style="COLOR: #000000">close</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">)</span>; <br />      <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">if</span><span style="COLOR: #000000">(</span>conn!=<span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">null</span><span style="COLOR: #000000">)</span>conn.<span style="COLOR: #000000">close</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">)</span>; <br /><br />  <span style="COLOR: #000000">}</span><br /><span style="COLOR: #000000">}</span></div>
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<span class="postbody">
				<br />
				<br />嗯。怎么说呢。挺聪明的。都学会if(xxx!=null)这种传说中条件判断的上古绝学了。 <br />可惜，你屁股大，一张纸不够，你用了第一张纸，满意地看着它圆满地完成了金灿灿的任务，再用第二张，靠，只太薄，破了，一手金灿灿地，象带了个金戒指。你大怒，起，绝尘而去。于是也忘了第三张纸， <br />哥们儿，close()是可以出异常的，你rset关了，stmt.close()出现了异常，但是conn就不管了？ <br /><br /><br />近日有位室外高人，据说是鬼谷子高徒，鉴于怜我世人，不擦屁股的实多的高尚情操，亲手赚写一本绝世擦功秘籍，其文美，其意高，除了擦不干净之外，真可以说是称霸擦林。 <br /><br /></span>
		<table cellspacing="1" cellpadding="3" width="90%" align="center" border="0">
				<tbody>
						<tr>
								<td>
										<span class="genmed">
												<b>java代码: </b>
										</span>
								</td>
						</tr>
						<tr>
								<td class="code">
										<div style="FONT-FAMILY: 'Courier New', Courier, monospace">
												<br />
												<br />
												<span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">void</span> close<span style="COLOR: #000000">(</span><span style="COLOR: #aaaadd" ?="">Connection</span> conn<span style="COLOR: #000000">)</span><span style="COLOR: #000000">{</span><br />  <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">try</span><span style="COLOR: #000000">{</span><br />    <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">if</span><span style="COLOR: #000000">(</span>conn!=<span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">null</span><span style="COLOR: #000000">)</span> conn.<span style="COLOR: #000000">close</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">)</span>; <br />  <span style="COLOR: #000000">}</span><br />  <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">catch</span><span style="COLOR: #000000">(</span><span style="COLOR: #aaaadd" ?="">Exception</span> e<span style="COLOR: #000000">)</span><span style="COLOR: #000000">{</span><br />    e.<span style="COLOR: #000000">printStackTrace</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">)</span>; <br />  <span style="COLOR: #000000">}</span><br /><span style="COLOR: #000000">}</span><br /><span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">void</span> close<span style="COLOR: #000000">(</span><span style="COLOR: #aaaadd" ?="">ResultSet</span> rset<span style="COLOR: #000000">)</span><span style="COLOR: #000000">{</span><br />  ... <br /><span style="COLOR: #000000">}</span><br /><span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">void</span> close<span style="COLOR: #000000">(</span><span style="COLOR: #aaaadd" ?="">Statement</span> rset<span style="COLOR: #000000">)</span><span style="COLOR: #000000">{</span><br />  ... <br /><span style="COLOR: #000000">}</span><br /><span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">void</span> f<span style="COLOR: #000000">(</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">{</span><br />  <span style="COLOR: #aaaadd" ?="">Connection</span> conn = <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">null</span>; <br />  <span style="COLOR: #aaaadd" ?="">Statement</span> stmt = <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">null</span>; <br />  <span style="COLOR: #aaaadd" ?="">ResultSet</span> rset = <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">null</span>; <br />  <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">try</span><span style="COLOR: #000000">{</span><br />    conn = ...; <br />    stmt = ...; <br />    rset = ...; <br />    ... <br />  <span style="COLOR: #000000">}</span><br />  <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">finally</span><span style="COLOR: #000000">{</span><br />     close<span style="COLOR: #000000">(</span>rset<span style="COLOR: #000000">)</span>; <br />     close<span style="COLOR: #000000">(</span>stmt<span style="COLOR: #000000">)</span>; <br />     close<span style="COLOR: #000000">(</span>conn<span style="COLOR: #000000">)</span>; <br /><br />  <span style="COLOR: #000000">}</span><br /><span style="COLOR: #000000">}</span></div>
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<span class="postbody">
				<br />
				<br />哈，你们不能纸擦破了就不接着擦啊，甚至大而化之，不能擦股用具有了问题就半途而废呀！ <br /><br />具信，该高人以此法擦遍天下凡十数载，未有擦而无功者。 <br /><br />可惜，高人却忽视了，除了纸会出故障，甚至大而化之，一切擦具（如土块儿，木条儿，手指）都可能出现故障，还有别的地方也会出故障地！ <br />除了Exception，还有Error啊，我的高人！如果close(rset)抛了一个Error，你的close(stmt), close(conn)不都歇菜了？ <br /><br />后来，高人在《绝世武功补遗》里面解释说：Error代表不可恢复错误，说明整个排泄大业都受阻了，所以根本不应该试图对这种情况做任何处理，你也处理不了（自然也隐含此时你也根本无法擦屁股了的论断）。任何试图在这种情况下仍然固执擦屁股的做法都是倒行逆施，螳臂当车，必然被历史的车轮所撵碎。 <br /><br />此书一处，天下辟易。其革命性之深远，难以估量。具有关方面评论，Sun这个公共厕所的try-finally这个工具的设定本身就是不合理的，应该被历史车轮撵碎的，因为try-finally居然试图在出现Error的时候去做一些事情！是可忍，孰不可忍？ <br />可以预见，try-finally将被sun彻底废弃，并且向广大公众做公开道歉以检讨多年来的欺骗造成的恶劣影响。 <br />另外，公厕的构造也受到质疑，因为一旦有一个拉客在擦的时候某一步无可挽回地失败（比如，太紧张，手一抖，纸掉到了坑里，又死活伸手捞不着），那么他就大摇大摆不再继续擦，而如果碰巧此人刚吃了萝卜，就会把整个厕所里的其它拉客都熏得无法继续。（想想一个app server吧。你一个程序歇菜，乐得请病假不擦了，别人也跟着倒霉？） <br /><br /><br />嘿嘿，那么，你擦了吗？你肯定你擦了？擦干净了？ <br /><br />幸好，我们翻遍上古秘籍，最终在北京山顶洞人的失传宝典《呼呼，擦！》中发现了一个据称绝对干净的擦法，那就是－－－－－－－－－－－－ <br /><br />一下一下擦！ <br /><br />具体操作办法如下： <br /><br /></span>
		<table cellspacing="1" cellpadding="3" width="90%" align="center" border="0">
				<tbody>
						<tr>
								<td>
										<span class="genmed">
												<b>java代码: </b>
										</span>
								</td>
						</tr>
						<tr>
								<td class="code">
										<div style="FONT-FAMILY: 'Courier New', Courier, monospace">
												<br />
												<br />
												<span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">void</span> f<span style="COLOR: #000000">(</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">{</span><br />  <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">final</span><span style="COLOR: #aaaadd" ?="">Connection</span> conn = ...; <br />  <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">try</span><span style="COLOR: #000000">{</span><br />    <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">final</span><span style="COLOR: #aaaadd" ?="">Statement</span> stmt = ...; <br />    <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">try</span><span style="COLOR: #000000">{</span><br />      <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">final</span><span style="COLOR: #aaaadd" ?="">ResultSet</span> rset = ...; <br />      <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">try</span><span style="COLOR: #000000">{</span><br />        ... <br />      <span style="COLOR: #000000">}</span><br />      <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">finally</span><span style="COLOR: #000000">{</span>rset.<span style="COLOR: #000000">close</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">)</span>;<span style="COLOR: #000000">}</span><br />    <span style="COLOR: #000000">}</span><br />    <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">finally</span><span style="COLOR: #000000">{</span>stmt.<span style="COLOR: #000000">close</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">)</span>;<span style="COLOR: #000000">}</span><br />  <span style="COLOR: #000000">}</span><br />  <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">finally</span><span style="COLOR: #000000">{</span>conn.<span style="COLOR: #000000">close</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">)</span>;<span style="COLOR: #000000">}</span><br /><span style="COLOR: #000000">}</span></div>
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<span class="postbody">
				<br />
				<br />
				<br />其诀窍就是，每建立一个需要清理的资源，就用一个try-finally来保证它可以被清理掉。 <br /><br />如此，任何时候，你都是屁股干干静静地离开卫生间。 <br /><br /><br />哪。好多圣人门徒跟我说：这样一下一下擦，姿势非常不雅观（看看那嵌套的try块吧），有违古礼。我们反对！ <br /><br /><br />靠，你说孔丑儿古还是山顶洞人古？？ <br />屁股还泛着味儿呢，还拽什么“雅”？ <br /><br />而且，要是死要面子，也可以拉个帘子，擦的时候别让人看见嘛。比如： <br /><br /></span>
		<table cellspacing="1" cellpadding="3" width="90%" align="center" border="0">
				<tbody>
						<tr>
								<td>
										<span class="genmed">
												<b>java代码: </b>
										</span>
								</td>
						</tr>
						<tr>
								<td class="code">
										<div style="FONT-FAMILY: 'Courier New', Courier, monospace">
												<br />
												<br />
												<span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">interface</span> ResultListener<span style="COLOR: #000000">{</span><br />  <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">void</span> call<span style="COLOR: #000000">(</span><span style="COLOR: #aaaadd" ?="">ResultSet</span> rset<span style="COLOR: #000000">)</span>; <br /><span style="COLOR: #000000">}</span><br /><span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">class</span> SqlReader<span style="COLOR: #000000">{</span><br /><span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">void</span> read<span style="COLOR: #000000">(</span>ResultListener l<span style="COLOR: #000000">)</span><span style="COLOR: #000000">{</span><br />    <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">final</span><span style="COLOR: #aaaadd" ?="">Connection</span> conn = ...; <br />    <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">try</span><span style="COLOR: #000000">{</span><br />      <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">final</span><span style="COLOR: #aaaadd" ?="">Statement</span> stmt = ...; <br />      <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">try</span><span style="COLOR: #000000">{</span><br />        <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">final</span><span style="COLOR: #aaaadd" ?="">ResultSet</span> rset = ...; <br />        <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">try</span><span style="COLOR: #000000">{</span><br />          l.<span style="COLOR: #000000">call</span><span style="COLOR: #000000">(</span>rset<span style="COLOR: #000000">)</span>; <br />        <span style="COLOR: #000000">}</span><br />        <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">finally</span><span style="COLOR: #000000">{</span>rset.<span style="COLOR: #000000">close</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">)</span>;<span style="COLOR: #000000">}</span><br />      <span style="COLOR: #000000">}</span><br />      <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">finally</span><span style="COLOR: #000000">{</span>stmt.<span style="COLOR: #000000">close</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">)</span>;<span style="COLOR: #000000">}</span><br />    <span style="COLOR: #000000">}</span><br />    <span style="FONT-WEIGHT: bold; COLOR: #990066" ?="">finally</span><span style="COLOR: #000000">{</span>conn.<span style="COLOR: #000000">close</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">)</span>;<span style="COLOR: #000000">}</span><br />  <span style="COLOR: #000000">}</span><br /><span style="COLOR: #000000">}</span></div>
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<span class="postbody">
				<br />
				<br />这一下一下擦的动作都藏在SqlReader这个帘子里，你直接在ResultListener里面拉不就行了？ <br /><br />那位高人说了，这太复杂，就为了擦个屁股不值。 <br /><br />这个嘛，值不值的另说，你那个简单，就是简简单单地擦不干净屁股。要不您干脆别擦得了，更简单呢还。反正您出门儿就愣说擦的是Chanel香水儿就是了。有啥比瞪眼儿说白话儿简单？ <br /><br />对了， 我还忘了一个条款： <br />就是擦屁股的时候按顺序擦。谁<span style="FONT-WEIGHT: bold">后</span>进厕所的，要让人家<span style="FONT-WEIGHT: bold">先</span>出去。 <br /><br />“什么狗屁规则？“那位问了。 <br /><br />这个这个--，啊，你猜猜~~~？ <br /><br />嗯，对了，是这样的，上厕所都不着急，姗姗来迟，上课更不着急，更喜欢迟到了，对不对？而谁上课天天迟到早退还不担心毕业？当然是太子党了，是不？ <br />人家都太子党了，你还不让人家先出去？活腻味了你？（此处尾音要拉长，而且向上拐） <br /><br /><br />反正啊，具体说，ResultSet最后创建，但是要先关。 <br /><br />Statement其次。Connection最后。 <br /><br /><br />当然了，也许在你的环境下，次序错了也没出事情。但是，咱么吃软饭的（吃软件这口饭的）图啥？不就图个放心吗？上厕所图啥？不就图个别让太子党抓去当兔子吗？ <br />也许某个driver对次序不敏感，但是不好说哪天你换个环境就忽然她奶奶的敏感了呢？ <br />比如吧，你有connection pool, conn.close()把connection返回到connection。 <br /><br />你要是先conn.close()，好嘛，connection先回到pool了，正好别的线程里面等着要connection，立马这个connection又给分配出去了。 <br />这下齐了，你statement, resultset还没关呢，那边事故单位领导就找上门了。什么香油油的桌子，什么桐油炸丸子，全给你送来了。这不添堵吗？ <br /><br />好在，在我们《呼呼，擦！》宝典中记载的“一下一下擦”神功，老少咸宜，童叟无欺，有道是：法擦大法好，不如法擦冰箱好！ <br /><br />跑题了。反正是，只要你一个try-finally对应一个资源，你就不可能在次序上出错。自然而然的就是后入先出的堆栈结构。 <br />反观别的擦法，就没有这个效果，次序如何，全靠你自己掌握。弄错了，系统也不告诉你。等着吃桐油炸丸子吧。 <br /><br />这也是我们推广一下一下擦的一个原因。</span>
		<span class="postbody">
		</span>
		<span class="gensmall">
				<br />
				<br />上一次由ajoo于2005-6-09 周四, 下午12:45修改，总共修改了5次</span>
<img src ="http://www.blogjava.net/nomigd/aggbug/66760.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/nomigd/" target="_blank">何以解忧，唯有学习！让每一个人都能Open Source </a> 2006-08-31 08:48 <a href="http://www.blogjava.net/nomigd/articles/66760.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>提升JSP应用程序的七大绝招</title><link>http://www.blogjava.net/nomigd/articles/60887.html</link><dc:creator>何以解忧，唯有学习！让每一个人都能Open Source </dc:creator><author>何以解忧，唯有学习！让每一个人都能Open Source </author><pubDate>Sun, 30 Jul 2006 12:51:00 GMT</pubDate><guid>http://www.blogjava.net/nomigd/articles/60887.html</guid><wfw:comment>http://www.blogjava.net/nomigd/comments/60887.html</wfw:comment><comments>http://www.blogjava.net/nomigd/articles/60887.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/nomigd/comments/commentRss/60887.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/nomigd/services/trackbacks/60887.html</trackback:ping><description><![CDATA[
		<font face="Verdana">
				<font color="#3399cc">
						<font color="#ff0000">方法一：在servlet的init()方法中缓存数据</font>
						<br />
				</font>   当应用服务器初始化servlet实例之后，为客户端请求提供服务之前，它会调用这个servlet的init()方法。在一个servlet的生命周期中，init()方法只会被调用一次。通过在init()方法中缓存一些静态的数据或完成一些只需要执行一次的、耗时的操作，就可大大地提高系统性能。<br />　　例如，通过在init()方法中建立一个JDBC连接池是一个最佳例子，假设我们是用jdbc2.0的DataSource接口来取得数据库连接，在通常的情况下，我们需要通过JNDI来取得具体的数据源。我们可以想象在一个具体的应用中，如果每次SQL请求都要执行一次JNDI查询的话，那系统性能将会急剧下降。解决方法是如下代码，它通过缓存DataSource，使得下一次SQL调用时仍然可以继续利用它：<br />public class ControllerServlet extends HttpServlet<br />{<br />　private javax.sql.DataSource testDS = null; <br />　public void init(ServletConfig config) throws ServletException<br />　{<br />　　super.init(config); <br />　　Context ctx = null;<br />　　try<br />　　{ <br />　　　ctx = new InitialContext();<br />　　　testDS = (javax.sql.DataSource)ctx.lookup("jdbc/testDS");<br />　　}<br />　　catch(NamingException ne)<br />　　{<br />　　　ne.printStackTrace(); <br />　　}<br />　　catch(Exception e)<br />　　{<br />　　　e.printStackTrace();<br />　　}<br />　}<br /><br />　public javax.sql.DataSource getTestDS()<br />　{<br />　　return testDS;<br />　}<br />　...<br />　... <br />}</font>
		<br />
		<br />
		<font face="Verdana">
				<font color="#ff0000">方法 2:禁止servlet和JSP 自动重载(auto-reloading)</font>
				<br />　　Servlet/JSP提供了一个实用的技术，即自动重载技术，它为开发人员提供了一个好的开发环境，当你改变servlet和JSP页面后而不必重启应用服务器。然而，这种技术在产品运行阶段对系统的资源是一个极大的损耗，因为它会给JSP引擎的类装载器(classloader)带来极大的负担。因此关闭自动重载功能对系统性能的提升是一个极大的帮助。<br /><br /><font color="#ff0000">方法 3: 不要滥用HttpSession</font><br />　　在很多应用中，我们的程序需要保持客户端的状态，以便页面之间可以相互联系。但不幸的是由于HTTP具有天生无状态性，从而无法保存客户端的状态。因此一般的应用服务器都提供了session来保存客户的状态。在JSP应用服务器中，是通过HttpSession对像来实现session的功能的，但在方便的同时，它也给系统带来了不小的负担。因为每当你获得或更新session时，系统者要对它进行费时的序列化操作。你可以通过对HttpSession的以下几种处理方式来提升系统的性能：<br /><br />　　1、 如果没有必要，就应该关闭JSP页面中对HttpSession的缺省设置： 如果你没有明确指定的话，每个JSP页面都会缺省地创建一个HttpSession。如果你的JSP中不需要使用session的话，那可以通过如下的JSP页面指示符来禁止它：<br />＜%@ page session="false"%＞ <br /><br />　　2、 不要在HttpSession中存放大的数据对像：如果你在HttpSession中存放大的数据对像的话，每当对它进行读写时，应用服务器都将对其进行序列化，从而增加了系统的额外负担。你在HttpSession中存放的数据对像越大，那系统的性能就下降得越快。<br /><br />　　3、当你不需要HttpSession时，尽快地释放它：当你不再需要session时，你可以通过调用HttpSession.invalidate()方法来释放它。<br /><br />　　4、尽量将session的超时时间设得短一点：在JSP应用服务器中，有一个缺省的session的超时时间。当客户在这个时间之后没有进行任何操作的话，系统会将相关的session自动从内存中释放。超时时间设得越大，系统的性能就会越低，因此最好的方法就是尽量使得它的值保持在一个较低的水平。<br /><br /><font color="#ff0000">方法 4: 将页面输出进行压缩<br /></font><br />　　压缩是解决数据冗余的一个好的方法，特别是在网络带宽不够发达的今天。有的浏览器支持gzip(GNU zip)进行来对HTML文件进行压缩，这种方法可以戏剧性地减少HTML文件的下载时间。因此，如果你将servlet或JSP页面生成的HTML页面进行压缩的话，那用户就会觉得页面浏览速度会非常快。但不幸的是，不是所有的浏览器都支持gzip压缩，但你可以通过在你的程序中检查客户的浏览器是否支持它。下面就是关于这种方法实现的一个代码片段：<br /><br />public void doGet(HttpServletRequest request, HttpServletResponse response)<br />throws IOException, ServletException <br />{<br />　OutputStream out = null<br />　String encoding = request.getHeader("Accept-Encoding"); <br />　if (encoding != null &amp;&amp; encoding.indexOf("gzip") != -1)<br />　{<br />　　request.setHeader("Content-Encoding" , "gzip");<br />　　out = new GZIPOutputStream(request.getOutputStream());<br />　}<br />　else if (encoding != null &amp;&amp; encoding.indexOf("compress") != -1)<br />　{<br />　　request.setHeader("Content-Encoding" , "compress");<br />　　out = new ZIPOutputStream(request.getOutputStream());<br />　} <br />　else<br />　{<br />　　out = request.getOutputStream();<br />　}<br />　...<br />　... <br />} <br /><br /><font color="#ff0000">方法 5: 使用线程池</font><br />　　应用服务器缺省地为每个不同的客户端请求创建一个线程进行处理，并为它们分派service()方法，当service()方法调用完成后，与之相应的线程也随之撤消。由于创建和撤消线程会耗费一定的系统资源，这种缺省模式降低了系统的性能。但所幸的是我们可以通过创建一个线程池来改变这种状况。另外，我们还要为这个线程池设置一个最小线程数和一个最大线程数。在应用服务器启动时，它会创建数量等于最小线程数的一个线程池，当客户有请求时，相应地从池从取出一个线程来进行处理，当处理完成后，再将线程重新放入到池中。如果池中的线程不够地话，系统会自动地增加池中线程的数量，但总量不能超过最大线程数。通过使用线程池，当客户端请求急剧增加时，系统的负载就会呈现的平滑的上升曲线，从而提高的系统的可伸缩性。<br /><br /><font color="#ff0000">方法 6: 选择正确的页面包含机制</font><br />　　在JSP中有两种方法可以用来包含另一个页面：1、使用include指示符(＜%@ includee file=”test.jsp” %＞)。2、使用jsp指示符(＜jsp:includee page=”test.jsp” flush=”true”/＞)。在实际中我发现，如果使用第一种方法的话，可以使得系统性能更高。<br /><br /><font color="#ff0000">方法 7:正确地确定javabean的生命周期</font><br />　　JSP的一个强大的地方就是对javabean的支持。通过在JSP页面中使用＜jsp:useBean＞标签，可以将javabean直接插入到一个JSP页面中。它的使用方法如下：<br />＜jsp:useBean id="name" scope="page|request|session|application" class=<br />"package.className" type="typeName"＞<br />＜/jsp:useBean＞ <br /><br />　　其中scope属性指出了这个bean的生命周期。缺省的生命周期为page。如果你没有正确地选择bean的生命周期的话，它将影响系统的性能。<br />　　举例来说，如果你只想在一次请求中使用某个bean，但你却将这个bean的生命周期设置成了session，那当这次请求结束后，这个bean将仍然保留在内存中，除非session超时或用户关闭浏览器。这样会耗费一定的内存，并无谓的增加了JVM垃圾收集器的工作量。因此为bean设置正确的生命周期，并在bean的使命结束后尽快地清理它们，会使用系统性能有一个提高。<br /><br /><font color="#ff0000">其它一些有用的方法</font><br />　　1、在字符串连接操作中尽量不使用“＋”操作符：在java编程中，我们常常使用“＋”操作符来将几个字符串连接起来，但你或许从来没有想到过它居然会对系统性能造成影响吧？由于字符串是常量，因此JVM会产生一些临时的对像。你使用的“＋”越多，生成的临时对像就越多，这样也会给系统性能带来一些影响。解决的方法是用StringBuffer对像来代替“＋”操作符。<br /><br />　　2、 避免使用System.out.println()方法：由于System.out.println()是一种同步调用，即在调用它时，磁盘I/O操作必须等待它的完成，因此我们要尽量避免对它的调用。但我们在调试程序时它又是一个必不可少的方便工具，为了解决这个矛盾，我建议你最好使用Log4j工具(<a href="http://jakarta.apache.org/" target="_blank">http://Jakarta.apache.org</a> )，它既可以方便调试，而不会产生System.out.println()这样的方法。<br /><br />　　3、 ServletOutputStream 与 PrintWriter的权衡:使用PrintWriter可能会带来一些小的开销，因为它将所有的原始输出都转换为字符流来输出，因此如果使用它来作为页面输出的话，系统要负担一个转换过程。而使用ServletOutputStream作为页面输出的话就不存在一个问题，但它是以二进制进行输出的。因此在实际应用中要权衡两者的利弊。<br /><br />　　<font size="5"><font color="#ff9900">总结</font></font><br />　　本文的目的是通过对servlet和JSP的一些调优技术来极大地提高你的应用程序的性能，并因此提升整个J2EE应用的性能。通过这些调优技术，你可以发现其实并不是某种技术平台（比如J2EE和.NET之争）决定了你的应用程序的性能，重要是你要对这种平台有一个较为深入的了解，这样你才能从根本上对自己的应用程序做一个优化！</font>
<img src ="http://www.blogjava.net/nomigd/aggbug/60887.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/nomigd/" target="_blank">何以解忧，唯有学习！让每一个人都能Open Source </a> 2006-07-30 20:51 <a href="http://www.blogjava.net/nomigd/articles/60887.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用JAVA实现UBB代码</title><link>http://www.blogjava.net/nomigd/articles/57617.html</link><dc:creator>何以解忧，唯有学习！让每一个人都能Open Source </dc:creator><author>何以解忧，唯有学习！让每一个人都能Open Source </author><pubDate>Tue, 11 Jul 2006 03:11:00 GMT</pubDate><guid>http://www.blogjava.net/nomigd/articles/57617.html</guid><wfw:comment>http://www.blogjava.net/nomigd/comments/57617.html</wfw:comment><comments>http://www.blogjava.net/nomigd/articles/57617.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/nomigd/comments/commentRss/57617.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/nomigd/services/trackbacks/57617.html</trackback:ping><description><![CDATA[
		<p>      相信大家一定可以想到UBB代码的解析，其实就是将“[b][/b]”这样的格式转换成““”就可以了，但是怎么转换呢？答案是用正则表达式。利用上一期讲到的正则表达式类(sony.utils.Regex)中的eregi_replace替换方法，可以很轻松地做到。下面是一段示例。 <br />　　String s="[b]这是粗体[/b]"; <br />　　String result; <br />　　result = Regex.eregi_replace("[b](.+?)[/b]","“$1“", s); <br />　　System.out.println(result); <br />　　//打印结果是： <br />　　//“这是粗体“。 <br />这么简单吗？是的，我们只需要将其它的UBB Tag作类似的替换就实现了UBB代码的解析了。 <br />下面给出一个UBB类.<br /><br />/***************************UbbCode.java****************************************/<br />import java.util.regex.Matcher; //导入所需要的类<br />import java.util.regex.Pattern;<br />public class UbbCode //类定义<br />{<br />private String source; //待转化的HTML代码字符串<br />private String ubbTags[]; //UBB标记数组<br />private String htmlTags[]; //HTML标记数组</p>
		<p>//初始化,分别为UBB标记数组和HTML标记数组赋值<br />public UbbCode() <br />{<br />byte byte0 = 74;<br />source = new String();<br />ubbTags = new String[byte0];<br />htmlTags = new String[byte0];<br />ubbTags[0] = "[b]";<br />htmlTags[0] = "&lt;b&gt;";<br />ubbTags[1] = "[/b]";<br />htmlTags[1] = "&lt;/b&gt;";<br />ubbTags[2] = "[i]";<br />htmlTags[2] = "&lt;em&gt;";<br />ubbTags[3] = "[/i]";<br />htmlTags[3] = "&lt;/em&gt;";<br />ubbTags[4] = "[quote]";<br />htmlTags[4] = "&lt;div style=\"border-style:dashed;background-color:#CCCCCC;border-width:thin;border-color:#999999\"&gt;&lt;br&gt;&lt;em&gt;";<br />ubbTags[5] = "[/quote]";<br />htmlTags[5] = "&lt;/em&gt;&lt;br&gt;&lt;br&gt;&lt;/div&gt;";<br />ubbTags[6] = "[/size]";<br />htmlTags[6] = "&lt;/font&gt;";<br />ubbTags[7] = "[size=6]";<br />htmlTags[7] = "&lt;font style=\"font-size:6px\"&gt;";<br />ubbTags[8] = "[size=8]";<br />htmlTags[8] = "&lt;font style=\"font-size:8px\"&gt;";<br />ubbTags[9] = "[size=10]";<br />htmlTags[9] = "&lt;font style=\"font-size:10px\"&gt;";<br />ubbTags[10] = "[size=12]";<br />htmlTags[10] = "&lt;font style=\"font-size:12px\"&gt;";<br />ubbTags[11] = "[size=14]";<br />htmlTags[11] = "&lt;font style=\"font-size:14px\"&gt;";<br />ubbTags[12] = "[size=18]";<br />htmlTags[12] = "&lt;font style=\"font-size:18px\"&gt;";<br />ubbTags[13] = "[size=24]";<br />htmlTags[13] = "&lt;font style=\"font-size:24px\"&gt;";<br />ubbTags[14] = "[size=36]";<br />htmlTags[14] = "&lt;font style=\"font-size:36px\"&gt;";</p>
		<p>//字体<br />ubbTags[15] = "[/font]";<br />htmlTags[15] = "&lt;/font&gt;";<br />ubbTags[16] = "[font=Arial]";<br />htmlTags[16] = "&lt;font face=\"Arial\"&gt;";<br />ubbTags[17] = "[font=Arial Black]";<br />htmlTags[17] = "&lt;font face=\"Arial Black\"&gt;";<br />ubbTags[18] = "[font=Verdana]";<br />htmlTags[18] = "&lt;font face=\"Verdana\"&gt;";<br />ubbTags[19] = "[font=Times New Roman]";<br />htmlTags[19] = "&lt;font face=\"Times New Roman\"&gt;";<br />ubbTags[20] = "[font=Garamond]";<br />htmlTags[20] = "&lt;font face=\"Garamond\"&gt;";<br />ubbTags[21] = "[font=Courier New]";<br />htmlTags[21] = "&lt;font face=\"Courier New\"&gt;";<br />ubbTags[22] = "[font=Webdings]";<br />htmlTags[22] = "&lt;font face=\"Webdings\"&gt;";<br />ubbTags[23] = "[font=Wingdings]";<br />htmlTags[23] = "&lt;font face=\"Wingdings\"&gt;";<br />ubbTags[24] = "[font=隶书]";<br />htmlTags[24] = "&lt;font face=\"隶书\"&gt;";<br />ubbTags[25] = "[font=幼圆]";<br />htmlTags[25] = "&lt;font face=\"幼圆\"&gt;"; <br />ubbTags[26] = "[font=方正舒体]";<br />htmlTags[26] = "&lt;font face=\"方正舒体\"&gt;";<br />ubbTags[27] = "[font=方正姚体]";<br />htmlTags[27] = "&lt;font face=\"方正姚体\"&gt;";<br />ubbTags[28] = "[font=仿宋_GB2312]";<br />htmlTags[28] = "&lt;font face=\"仿宋_GB2312\"&gt;";<br />ubbTags[29] = "[font=黑体]";<br />htmlTags[29] = "&lt;font face=\"黑体\"&gt;";<br />ubbTags[30] = "[font=华文彩云]";<br />htmlTags[30] = "&lt;font face=\"华文彩云\"&gt;";<br />ubbTags[31] = "[font=华文细黑]";<br />htmlTags[31] = "&lt;font face=\"华文细黑\"&gt;";<br />ubbTags[32] = "[font=华文新魏]";<br />htmlTags[32] = "&lt;font face=\"华文新魏\"&gt;";<br />ubbTags[33] = "[font=华文中宋]";<br />htmlTags[33] = "&lt;font face=\"华文中宋\"&gt;";<br />ubbTags[34] = "[font=华文行楷]";<br />htmlTags[34] = "&lt;font face=\"华文行楷\"&gt;";<br />ubbTags[35] = "[font=楷体_GB2312]";<br />htmlTags[35] = "&lt;font face=\"楷体_GB2312\"&gt;";<br />ubbTags[36] = "[font=隶书]";<br />htmlTags[36] = "&lt;font face=\"隶书\"&gt;"; <br />ubbTags[37] = "[font=华文楷体]";<br />htmlTags[37] = "&lt;font face=\"华文楷体\"&gt;"; <br />ubbTags[38] = "[font=宋体]";<br />htmlTags[38] = "&lt;font face=\"宋体\"&gt;";<br />ubbTags[39] = "[font=新宋体";<br />htmlTags[39] = "&lt;font face=\"新宋体\"&gt;";<br />ubbTags[40] = "[font=幼圆";<br />htmlTags[40] = "&lt;font face=\"幼圆\"&gt;";</p>
		<p>//字体颜色<br />ubbTags[41] = "[red]";<br />htmlTags[41] = "&lt;font color=\"red\"&gt;";<br />ubbTags[42] = "[/red]";<br />htmlTags[42] = "&lt;/font&gt;";<br />ubbTags[43] = "[blue]";<br />htmlTags[43] = "&lt;font color=\"blue\"&gt;";<br />ubbTags[44] = "[/blue]";<br />htmlTags[44] = "&lt;/font&gt;";<br />ubbTags[45] = "[yellow]";<br />htmlTags[45] = "&lt;font color=\"yellow\"&gt;";<br />ubbTags[46] = "[/yellow]";<br />htmlTags[46] = "&lt;/font&gt;";<br />ubbTags[47] = "[green]";<br />htmlTags[47] = "&lt;font color=\"green\"&gt;";<br />ubbTags[48] = "[/green]";<br />htmlTags[48] = "&lt;/font&gt;";</p>
		<p>ubbTags[49] = "[f]";<br />htmlTags[49] = "&lt;marquee width=\"400\" scrolldelay=\"30\" scrollamount=\"1\" onmouseover=\"this.stop()\" onmouseout=\"this.start()\"&gt;";</p>
		<p>//标题<br />ubbTags[50] = "[h1]";<br />htmlTags[50] = "&lt;h1&gt;";<br />ubbTags[51] = "[/h1]";<br />htmlTags[51] = "&lt;/h1&gt;";<br />ubbTags[52] = "[h2]";<br />htmlTags[52] = "&lt;h2&gt;";<br />ubbTags[53] = "[/h2]";<br />htmlTags[53] = "&lt;/h2&gt;";<br />ubbTags[54] = "[h3]";<br />htmlTags[54] = "&lt;h3&gt;";<br />ubbTags[55] = "[/h3]";<br />htmlTags[55] = "&lt;/h3&gt;";<br />ubbTags[56] = "[h4]";<br />htmlTags[56] = "&lt;h4&gt;";<br />ubbTags[57] = "[/h4]";<br />htmlTags[57] = "&lt;/h4&gt;";<br />ubbTags[58] = "[h5]";<br />htmlTags[58] = "&lt;h5&gt;";<br />ubbTags[59] = "[/h5]";<br />htmlTags[59] = "&lt;/h5&gt;";<br />ubbTags[60] = "[h6]";<br />htmlTags[60] = "&lt;h6&gt;";<br />ubbTags[61] = "[/h6]";<br />htmlTags[61] = "&lt;/h6&gt;";<br />ubbTags[62] = "[hr]";<br />htmlTags[62] = "&lt;hr&gt;";<br />ubbTags[63] = "[img]";<br />htmlTags[63] = "&lt;br&gt;&lt;img src=\"";<br />ubbTags[64] = "[/img]";<br />htmlTags[64] = "\"&gt;&lt;br&gt;";<br />ubbTags[65] = "[center]";<br />htmlTags[65] = "&lt;div align=\"center\"&gt;";<br />ubbTags[66] = "[/center]";<br />htmlTags[66] = "&lt;/div&gt;";</p>
		<p>ubbTags[67] = "[/f]";<br />htmlTags[67] = "&lt;/marquee&gt;"; <br />ubbTags[68] = "[left]";<br />htmlTags[68] = "&lt;div align=\"left\"&gt;";<br />ubbTags[69] = "[/left]";<br />htmlTags[69] = "&lt;/div&gt;";<br />ubbTags[70] = "[right]";<br />htmlTags[70] = "&lt;div align=\"right\"&gt;";<br />ubbTags[71] = "[/right]";<br />htmlTags[71] = "&lt;/div&gt;";<br />ubbTags[72] = "[u]";<br />htmlTags[72] = "&lt;u&gt;";<br />ubbTags[73] = "[/u]"; <br />htmlTags[73] = "&lt;/u&gt;";</p>
		<p>}</p>
		<p>private String replace(String s, String s1, String s2) {<br />  StringBuffer stringbuffer = new StringBuffer();<br />  for(int i = 0; i &lt; s1.length(); i++) {<br />  char c = s1.charAt(i);<br />  switch(c) {<br />   case 91: // '['<br />    stringbuffer.append("\\[");<br />    break;</p>
		<p>   case 93: // ']'<br />     stringbuffer.append("\\]");<br />     break;</p>
		<p>   default:<br />     stringbuffer.append(c);<br />     break;<br />   }<br />}</p>
		<p>Pattern pattern = Pattern.compile(stringbuffer.toString());<br />Matcher matcher = pattern.matcher(s);<br />StringBuffer stringbuffer1 = new StringBuffer();<br />for(boolean flag = matcher.find(); flag; flag = matcher.find())<br />matcher.appendReplacement(stringbuffer1, s2);</p>
		<p>return matcher.appendTail(stringbuffer1).toString();<br />}</p>
		<p>private String replaceNormalUBBCode(String s)<br />{<br />String s1 = new String(s);<br />for(int i = 0; i &lt; ubbTags.length; i++)<br />s1 = replace(s1, ubbTags[i], htmlTags[i]);</p>
		<p>return s1;<br />}</p>
		<p>private String replaceURL(String s)<br />{<br />StringBuffer stringbuffer = new StringBuffer(s);<br />String s1 = new String();<br />int i = s.indexOf("[url]");<br />int j = s.indexOf("[/url]");<br />if(i != -1 &amp;&amp; j != -1 &amp;&amp; i &lt; j)<br />{<br />String s2 = s.substring(i + 5, j);<br />String s3 = "&lt;a href=\"" + s2 + "\"&gt;" + s2 + "&lt;/a&gt;";<br />stringbuffer.replace(i, j + 6, s3);<br />}<br />return stringbuffer.toString();<br />}</p>
		<p>private String replaceEmail(String s)<br />{<br />StringBuffer stringbuffer = new StringBuffer(s);<br />String s1 = new String();<br />int i = s.indexOf("[email]");<br />int j = s.indexOf("[/email]");<br />if(i != -1 &amp;&amp; j != -1 &amp;&amp; i &lt; j)<br />{<br />String s2 = s.substring(i + 7, j);<br />String s3 = "&lt;a href=\"mailto:" + s2 + "\"&gt;" + s2 + "&lt;/a&gt;";<br />stringbuffer.replace(i, j + 8, s3);<br />}<br />return stringbuffer.toString();<br />}</p>
		<p>public void setSource(String s)<br />{<br />source = s;<br />}</p>
		<p>public String getResult()<br />{<br />return source;<br />}</p>
		<p>public void run()<br />{<br />for(source = replaceNormalUBBCode(source); source.indexOf("[url]") != -1 &amp;&amp; source.indexOf("[/url]") != -1;<br />  source = replaceURL(source));<br />for(; source.indexOf("[email]") != -1 &amp;&amp; source.indexOf("[/email]") != -1; source = replaceEmail(source));<br />}<br />}</p>
		<p> </p>
<img src ="http://www.blogjava.net/nomigd/aggbug/57617.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/nomigd/" target="_blank">何以解忧，唯有学习！让每一个人都能Open Source </a> 2006-07-11 11:11 <a href="http://www.blogjava.net/nomigd/articles/57617.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JAVA中的指针,引用及对象的clone</title><link>http://www.blogjava.net/nomigd/articles/47881.html</link><dc:creator>何以解忧，唯有学习！让每一个人都能Open Source </dc:creator><author>何以解忧，唯有学习！让每一个人都能Open Source </author><pubDate>Wed, 24 May 2006 12:03:00 GMT</pubDate><guid>http://www.blogjava.net/nomigd/articles/47881.html</guid><wfw:comment>http://www.blogjava.net/nomigd/comments/47881.html</wfw:comment><comments>http://www.blogjava.net/nomigd/articles/47881.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/nomigd/comments/commentRss/47881.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/nomigd/services/trackbacks/47881.html</trackback:ping><description><![CDATA[
		<p>看到这个标题，是不是有点困惑：Java语言明确说明取消了指针，因为指针往往是在带来方便的同时也是导致代码不安全的根源，同时也会使程序的变得非常复杂难以理解，滥用指针写成的代码不亚于使用早已臭名昭著的"GOTO"语句。Java放弃指针的概念绝对是极其明智的。但这只是在Java语言中没有明确的指针定义，实质上每一个new语句返回的都是一个指针的引用，只不过在大多时候Java中不用关心如何操作这个"指针"，更不用象在操作C＋＋的指针那样胆战心惊。唯一要多多关心的是在给函数传递对象的时候。如下例程：</p>
		<table cellspacing="0" cellpadding="5" width="550" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">package reference;
class Obj{
    String str = "init value";
    public String toString(){
        return str;
    }
}
public class ObjRef{
    Obj aObj = new Obj();
    int aInt = 11;
    public void changeObj(Obj inObj){
        inObj.str = "changed value";
    }
    public void changePri(int inInt){
        inInt = 22;
    }
    public static void main(String[] args) 
    {
        ObjRef oRef = new ObjRef();
        
        System.out.println("Before call changeObj() method: " + oRef.aObj);
        oRef.changeObj(oRef.aObj);
        System.out.println("After call changeObj() method: " + oRef.aObj);

        System.out.println("==================Print Primtive=================");
        System.out.println("Before call changePri() method: " + oRef.aInt);
        oRef.changePri(oRef.aInt);
        System.out.println("After call changePri() method: " + oRef.aInt);

    }
}

/* RUN RESULT
Before call changeObj() method: init value
After call changeObj() method: changed value
==================Print Primtive=================
Before call changePri() method: 11
After call changePri() method: 11

*
*/
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>这段代码的主要部分调用了两个很相近的方法，changeObj()和changePri()。唯一不同的是它们一个把对象作为输入参数，另一个把Java中的基本类型int作为输入参数。并且在这两个函数体内部都对输入的参数进行了改动。看似一样的方法，程序输出的结果却不太一样。changeObj()方法真正的把输入的参数改变了，而changePri()方法对输入的参数没有任何的改变。</p>
		<p>从这个例子知道Java对对象和基本的数据类型的处理是不一样的。和C语言一样，当把Java的基本数据类型（如int，char，double等）作为入口参数传给函数体的时候，传入的参数在函数体内部变成了局部变量，这个局部变量是输入参数的一个拷贝，所有的函数体内部的操作都是针对这个拷贝的操作，函数执行结束后，这个局部变量也就完成了它的使命，它影响不到作为输入参数的变量。这种方式的参数传递被称为"值传递"。而在Java中用对象的作为入口参数的传递则缺省为"引用传递"，也就是说仅仅传递了对象的一个"引用"，这个"引用"的概念同C语言中的指针引用是一样的。当函数体内部对输入变量改变时，实质上就是在对这个对象的直接操作。</p>
		<p>除了在函数传值的时候是"引用传递"，在任何用"＝"向对象变量赋值的时候都是"引用传递"。如：</p>
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">package reference;
class PassObj
{
    String str = "init value";
}
public class ObjPassValue 
{

    public static void main(String[] args) 
    {
        PassObj objA = new PassObj();
        PassObj objB = objA;

        objA.str = "changed in objA";
        System.out.println("Print objB.str value: " + objB.str);
    }
}
/* RUN RESULT
Print objB.str value: changed in objA
*/
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>第一句是在内存中生成一个新的PassObj对象，然后把这个PassObj的引用赋给变量objA，第二句是把PassObj对象的引用又赋给了变量objB。此时objA和objB是两个完全一致的变量，以后任何对objA的改变都等同于对objB的改变。</p>
		<p>即使明白了Java语言中的"指针"概念也许还会不经意间犯下面的错误。</p>
		<p>
				<a name="1">
						<span class="atitle">
								<font face="Arial" size="4">Hashtable真的能存储对象吗？</font>
						</span>
				</a>
		</p>
		<p>
				<font face="Arial" size="4">
				</font>
		</p>
		<p>看一看下面的很简单的代码，先是声明了一个Hashtable和StringBuffer对象，然后分四次把StriingBuffer对象放入到Hashtable表中，在每次放入之前都对这个StringBuffer对象append()了一些新的字符串：</p>
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">package reference;
import java.util.*;
public class HashtableAdd{
    public static void main(String[] args){
        Hashtable ht = new Hashtable();
        StringBuffer sb = new StringBuffer();
        sb.append("abc,");
        ht.put("1",sb);     
        sb.append("def,");
        ht.put("2",sb);
        sb.append("mno,");
        ht.put("3",sb);
        sb.append("xyz.");
        ht.put("4",sb);
        
        int numObj=0;
        Enumeration it = ht.elements();
        while(it.hasMoreElements()){
            System.out.print("get StringBufffer "+(++numObj)+" from Hashtable: ");
            System.out.println(it.nextElement());
        }
    }
}
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>如果你认为输出的结果是： <br />get StringBufffer 1 from Hashtable: abc, <br />get StringBufffer 2 from Hashtable: abc,def， <br />get StringBufffer 3 from Hashtable: abc,def,mno, <br />get StringBufffer 4 from Hashtable: abc,def,mno,xyz. </p>
		<p>那么你就要回过头再仔细看一看上一个问题了，把对象时作为入口参数传给函数，实质上是传递了对象的引用，向Hashtable传递StringBuffer对象也是只传递了这个StringBuffer对象的引用！每一次向Hashtable表中put一次StringBuffer，并没有生成新的StringBuffer对象，只是在Hashtable表中又放入了一个指向同一StringBuffer对象的引用而已。</p>
		<p>对Hashtable表存储的任何一个StringBuffer对象（更确切的说应该是对象的引用）的改动，实际上都是对同一个"StringBuffer"的改动。所以Hashtable并不能真正存储能对象，而只能存储对象的引用。也应该知道这条原则对与Hashtable相似的Vector, List, Map, Set等都是一样的。</p>
		<p>上面的例程的实际输出的结果是：</p>
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">/* RUN RESULT
get StringBufffer 1 from Hashtable: abc,def,mno,xyz.
get StringBufffer 2 from Hashtable: abc,def,mno,xyz.
get StringBufffer 3 from Hashtable: abc,def,mno,xyz.
get StringBufffer 4 from Hashtable: abc,def,mno,xyz.
*/
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<font face="Lucida Console">
												<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
												<br />
												<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
										</font>
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<font face="Lucida Console">
												<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
												<br />
										</font>
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<font face="Lucida Console">
																				<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																				<br />
																		</font>
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/l-jpointer/index.html#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="2">
						<span class="atitle">
								<font face="Arial" size="4">类，对象与引用</font>
						</span>
				</a>
		</p>
		<p>
				<font face="Arial" size="4">
				</font>
		</p>
		<p>Java最基本的概念就是类，类包括函数和变量。如果想要应用类，就要把类生成对象，这个过程被称作"类的实例化"。有几种方法把类实例化成对象，最常用的就是用"new"操作符。类实例化成对象后，就意味着要在内存中占据一块空间存放实例。想要对这块空间操作就要应用到对象的引用。引用在Java语言中的体现就是变量，而变量的类型就是这个引用的对象。虽然在语法上可以在生成一个对象后直接调用该对象的函数或变量，如：</p>
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">new String("Hello NDP")).substring(0,3)　　//RETURN RESULT: Hel
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>但由于没有相应的引用，对这个对象的使用也只能局限这条语句中了。</p>
		<ol>
				<li>产生：引用总是在把对象作参数"传递"的过程中自动发生，不需要人为的产生，也不能人为的控制引用的产生。这个传递包括把对象作为函数的入口参数的情况，也包括用"＝"进行对象赋值的时候。 
</li>
				<li>范围：只有局部的引用，没有局部的对象。引用在Java语言的体现就是变量，而变量在Java语言中是有范围的，可以是局部的，也可以是全局的。 
</li>
				<li>生存期：程序只能控制引用的生存周期。对象的生存期是由Java控制。用"new Object()"语句生成一个新的对象，是在计算机的内存中声明一块区域存储对象，只有Java的垃圾收集器才能决定在适当的时候回收对象占用的内存。 
</li>
				<li>没有办法阻止对引用的改动。 </li>
		</ol>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																		<br />
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/l-jpointer/index.html#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="3">
						<span class="atitle">
								<font face="Arial" size="4">什么是"clone"？</font>
						</span>
				</a>
		</p>
		<p>
				<font face="Arial" size="4">
				</font>
		</p>
		<p>在实际编程过程中，我们常常要遇到这种情况：有一个对象A，在某一时刻A中已经包含了一些有效值，此时可能会需要一个和A完全相同新对象B，并且此后对B任何改动都不会影响到A中的值，也就是说，A与B是两个独立的对象，但B的初始值是由A对象确定的。在Java语言中，用简单的赋值语句是不能满足这种需求的。要满足这种需求虽然有很多途径，但实现clone（）方法是其中最简单，也是最高效的手段。</p>
		<p>Java的所有类都默认继承java.lang.Object类，在java.lang.Object类中有一个方法clone()。JDK API的说明文档解释这个方法将返回Object对象的一个拷贝。要说明的有两点：一是拷贝对象返回的是一个新对象，而不是一个引用。二是拷贝对象与用new操作符返回的新对象的区别就是这个拷贝已经包含了一些原来对象的信息，而不是对象的初始信息。</p>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																		<br />
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/l-jpointer/index.html#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="4">
						<span class="atitle">
								<font face="Arial" size="4">怎样应用clone()方法？</font>
						</span>
				</a>
		</p>
		<p>
				<font face="Arial" size="4">
				</font>
		</p>
		<p>一个很典型的调用clone()代码如下：</p>
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">class CloneClass implements Cloneable{
    public int aInt;
    public Object clone(){
        CloneClass o = null;
        try{
            o = (CloneClass)super.clone();
        }catch(CloneNotSupportedException e){
            e.printStackTrace();
        }
        return o;
    }
｝
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>有三个值得注意的地方，一是希望能实现clone功能的CloneClass类实现了Cloneable接口，这个接口属于java.lang包，java.lang包已经被缺省的导入类中，所以不需要写成java.lang.Cloneable。另一个值得请注意的是重载了clone()方法。最后在clone()方法中调用了super.clone()，这也意味着无论clone类的继承结构是什么样的，super.clone()直接或间接调用了java.lang.Object类的clone()方法。下面再详细的解释一下这几点。</p>
		<p>应该说第三点是最重要的，仔细观察一下Object类的clone()一个native方法，native方法的效率一般来说都是远高于java中的非native方法。这也解释了为什么要用Object中clone()方法而不是先new一个类，然后把原始对象中的信息赋到新对象中，虽然这也实现了clone功能。对于第二点，也要观察Object类中的clone()还是一个protected属性的方法。这也意味着如果要应用clone()方法，必须继承Object类，在Java中所有的类是缺省继承Object类的，也就不用关心这点了。然后重载clone()方法。还有一点要考虑的是为了让其它类能调用这个clone类的clone()方法，重载之后要把clone()方法的属性设置为public。</p>
		<p>那么clone类为什么还要实现Cloneable接口呢？稍微注意一下，Cloneable接口是不包含任何方法的！其实这个接口仅仅是一个标志，而且这个标志也仅仅是针对Object类中clone()方法的，如果clone类没有实现Cloneable接口，并调用了Object的clone()方法（也就是调用了super.Clone()方法），那么Object的clone()方法就会抛出CloneNotSupportedException异常。</p>
		<p>以上是clone的最基本的步骤，想要完成一个成功的clone，还要了解什么是"影子clone"和"深度clone"。</p>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																		<br />
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/l-jpointer/index.html#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="5">
						<span class="atitle">
								<font face="Arial" size="4">什么是影子clone？</font>
						</span>
				</a>
		</p>
		<p>
				<font face="Arial" size="4">
				</font>
		</p>
		<p>下面的例子包含三个类UnCloneA，CloneB，CloneMain。CloneB类包含了一个UnCloneA的实例和一个int类型变量，并且重载clone()方法。CloneMain类初始化UnCloneA类的一个实例b1，然后调用clone()方法生成了一个b1的拷贝b2。最后考察一下b1和b2的输出：</p>
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">package clone;
class UnCloneA {
    private int i;
    public UnCloneA(int ii) { i = ii; }
    public void doubleValue() { i *= 2; }
    public String toString() {
        return Integer.toString(i);
    }
}
class CloneB implements Cloneable{
    public int aInt;
    public UnCloneA unCA = new UnCloneA(111);
    public Object clone(){
        CloneB o = null;
        try{
            o = (CloneB)super.clone();
        }catch(CloneNotSupportedException e){
            e.printStackTrace();
        }
        return o;
    }
}
public class CloneMain {
    public static void main(String[] a){
        CloneB b1 = new CloneB();
        b1.aInt = 11;
        System.out.println("before clone,b1.aInt = "+ b1.aInt);
        System.out.println("before clone,b1.unCA = "+ b1.unCA);
                
        CloneB b2 = (CloneB)b1.clone();
        b2.aInt = 22;
        b2.unCA.doubleValue();
        System.out.println("=================================");
        System.out.println("after clone,b1.aInt = "+ b1.aInt);
        System.out.println("after clone,b1.unCA = "+ b1.unCA);
        System.out.println("=================================");
        System.out.println("after clone,b2.aInt = "+ b2.aInt);
        System.out.println("after clone,b2.unCA = "+ b2.unCA);
    }
}


/** RUN RESULT:
before clone,b1.aInt = 11
before clone,b1.unCA = 111
=================================
after clone,b1.aInt = 11
after clone,b1.unCA = 222
=================================
after clone,b2.aInt = 22
after clone,b2.unCA = 222
*/
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>输出的结果说明int类型的变量aInt和UnCloneA的实例对象unCA的clone结果不一致，int类型是真正的被clone了，因为改变了b2中的aInt变量，对b1的aInt没有产生影响，也就是说，b2.aInt与b1.aInt已经占据了不同的内存空间，b2.aInt是b1.aInt的一个真正拷贝。相反，对b2.unCA的改变同时改变了b1.unCA，很明显，b2.unCA和b1.unCA是仅仅指向同一个对象的不同引用！从中可以看出，调用Object类中clone()方法产生的效果是：先在内存中开辟一块和原始对象一样的空间，然后原样拷贝原始对象中的内容。对基本数据类型，这样的操作是没有问题的，但对非基本类型变量，我们知道它们保存的仅仅是对象的引用，这也导致clone后的非基本类型变量和原始对象中相应的变量指向的是同一个对象。</p>
		<p>大多时候，这种clone的结果往往不是我们所希望的结果，这种clone也被称为"影子clone"。要想让b2.unCA指向与b2.unCA不同的对象，而且b2.unCA中还要包含b1.unCA中的信息作为初始信息，就要实现深度clone。</p>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																		<br />
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/l-jpointer/index.html#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="6">
						<span class="atitle">
								<font face="Arial" size="4">怎么进行深度clone？</font>
						</span>
				</a>
		</p>
		<p>
				<font face="Arial" size="4">
				</font>
		</p>
		<p>把上面的例子改成深度clone很简单，需要两个改变：一是让UnCloneA类也实现和CloneB类一样的clone功能（实现Cloneable接口，重载clone()方法）。二是在CloneB的clone()方法中加入一句o.unCA = (UnCloneA)unCA.clone();</p>
		<p>程序如下：</p>
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">package clone.ext;
class UnCloneA implements Cloneable{
    private int i;
    public UnCloneA(int ii) { i = ii; }
    public void doubleValue() { i *= 2; }
    public String toString() {
        return Integer.toString(i);
    }
    public Object clone(){
        UnCloneA o = null;
        try{
            o = (UnCloneA)super.clone();
        }catch(CloneNotSupportedException e){
            e.printStackTrace();
        }
        return o;
    }
}
class CloneB implements Cloneable{
    public int aInt;
    public UnCloneA unCA = new UnCloneA(111);
    public Object clone(){
        CloneB o = null;
        try{
            o = (CloneB)super.clone();
        }catch(CloneNotSupportedException e){
            e.printStackTrace();
        }
        o.unCA = (UnCloneA)unCA.clone();
        return o;
    }
}
public class CloneMain {
    public static void main(String[] a){
        CloneB b1 = new CloneB();
        b1.aInt = 11;
        System.out.println("before clone,b1.aInt = "+ b1.aInt);
        System.out.println("before clone,b1.unCA = "+ b1.unCA);
                
        CloneB b2 = (CloneB)b1.clone();
        b2.aInt = 22;
        b2.unCA.doubleValue();
        System.out.println("=================================");
        System.out.println("after clone,b1.aInt = "+ b1.aInt);
        System.out.println("after clone,b1.unCA = "+ b1.unCA);
        System.out.println("=================================");
        System.out.println("after clone,b2.aInt = "+ b2.aInt);
        System.out.println("after clone,b2.unCA = "+ b2.unCA);
    }
}

/** RUN RESULT:
before clone,b1.aInt = 11
before clone,b1.unCA = 111
=================================
after clone,b1.aInt = 11
after clone,b1.unCA = 111
=================================
after clone,b2.aInt = 22
after clone,b2.unCA = 222
*/
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>可以看出，现在b2.unCA的改变对b1.unCA没有产生影响。此时b1.unCA与b2.unCA指向了两个不同的UnCloneA实例，而且在CloneB b2 = (CloneB)b1.clone();调用的那一刻b1和b2拥有相同的值，在这里，b1.i = b2.i = 11。</p>
		<p>要知道不是所有的类都能实现深度clone的。例如，如果把上面的CloneB类中的UnCloneA类型变量改成StringBuffer类型，看一下JDK API中关于StringBuffer的说明，StringBuffer没有重载clone()方法，更为严重的是StringBuffer还是一个final类，这也是说我们也不能用继承的办法间接实现StringBuffer的clone。如果一个类中包含有StringBuffer类型对象或和StringBuffer相似类的对象，我们有两种选择：要么只能实现影子clone，要么就在类的clone()方法中加一句（假设是SringBuffer对象，而且变量名仍是unCA）： o.unCA = new StringBuffer(unCA.toString()); //原来的是：o.unCA = (UnCloneA)unCA.clone();</p>
		<p>还要知道的是除了基本数据类型能自动实现深度clone以外，String对象是一个例外，它clone后的表现好象也实现了深度clone，虽然这只是一个假象，但却大大方便了我们的编程。</p>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																		<br />
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/l-jpointer/index.html#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="7">
						<span class="atitle">
								<font face="Arial" size="4">Clone中String和StringBuffer的区别</font>
						</span>
				</a>
		</p>
		<p>
				<font face="Arial" size="4">
				</font>
		</p>
		<p>应该说明的是，这里不是着重说明String和StringBuffer的区别，但从这个例子里也能看出String类的一些与众不同的地方。</p>
		<p>下面的例子中包括两个类，CloneC类包含一个String类型变量和一个StringBuffer类型变量，并且实现了clone()方法。在StrClone类中声明了CloneC类型变量c1，然后调用c1的clone()方法生成c1的拷贝c2，在对c2中的String和StringBuffer类型变量用相应的方法改动之后打印结果：</p>
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">package clone;
class CloneC implements Cloneable{
    public String str;
    public StringBuffer strBuff;
    public Object clone(){
        CloneC o = null;
        try{
            o = (CloneC)super.clone();
        }catch(CloneNotSupportedException e){
            e.printStackTrace();
        }
        return o;
    }
    
}
public class StrClone {
    public static void main(String[] a){
        CloneC c1 = new CloneC();
        c1.str = new String("initializeStr");
        c1.strBuff = new StringBuffer("initializeStrBuff");
        System.out.println("before clone,c1.str = "+ c1.str);
        System.out.println("before clone,c1.strBuff = "+ c1.strBuff);
                
        CloneC c2 = (CloneC)c1.clone();
        c2.str = c2.str.substring(0,5);
        c2.strBuff = c2.strBuff.append(" change strBuff clone");
        System.out.println("=================================");
        System.out.println("after clone,c1.str = "+ c1.str);
        System.out.println("after clone,c1.strBuff = "+ c1.strBuff);
        System.out.println("=================================");
        System.out.println("after clone,c2.str = "+ c2.str);
        System.out.println("after clone,c2.strBuff = "+ c2.strBuff);
    }
}
/* RUN RESULT
before clone,c1.str = initializeStr
before clone,c1.strBuff = initializeStrBuff
=================================
after clone,c1.str = initializeStr
after clone,c1.strBuff = initializeStrBuff change strBuff clone
=================================
after clone,c2.str = initi
after clone,c2.strBuff = initializeStrBuff change strBuff clone
*
*/
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>打印的结果可以看出，String类型的变量好象已经实现了深度clone，因为对c2.str的改动并没有影响到c1.str！难道Java把Sring类看成了基本数据类型？其实不然，这里有一个小小的把戏，秘密就在于c2.str = c2.str.substring(0,5)这一语句！实质上，在clone的时候c1.str与c2.str仍然是引用，而且都指向了同一个String对象。但在执行c2.str = c2.str.substring(0,5)的时候，它作用相当于生成了一个新的String类型，然后又赋回给c2.str。这是因为String被Sun公司的工程师写成了一个不可更改的类（immutable class），在所有String类中的函数都不能更改自身的值。下面给出很简单的一个例子：</p>
		<p>package clone; public class StrTest { public static void main(String[] args) { String str1 = "This is a test for immutable"; String str2 = str1.substring(0,8); System.out.println("print str1 : " + str1); System.out.println("print str2 : " + str2); } } /* RUN RESULT print str1 : This is a test for immutable print str2 : This is */</p>
		<p>例子中，虽然str1调用了substring()方法，但str1的值并没有改变。类似的，String类中的其它方法也是如此。当然如果我们把最上面的例子中的这两条语句</p>
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">c2.str = c2.str.substring(0,5);
c2.strBuff = c2.strBuff.append(" change strBuff clone");
       </font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>改成下面这样：</p>
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">c2.str.substring(0,5);
c2.strBuff.append(" change strBuff clone");
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>去掉了重新赋值的过程，c2.str也就不能有变化了，我们的把戏也就露馅了。但在编程过程中只调用</p>
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">c2.str.substring(0,5);
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>语句是没有任何意义的。</p>
		<p>应该知道的是在Java中所有的基本数据类型都有一个相对应的类，象Integer类对应int类型，Double类对应double类型等等，这些类也与String类相同，都是不可以改变的类。也就是说，这些的类中的所有方法都是不能改变其自身的值的。这也让我们在编clone类的时候有了一个更多的选择。同时我们也可以把自己的类编成不可更改的类。</p>
		<br />
		<br />
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<font color="#996699">
												<br />
												<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
										</font>
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<font color="#996699">
												<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
												<br />
										</font>
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<font color="#996699"> <br /></font>
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/l-jpointer/index.html#main">
																				<b>
																						<font color="#996699">
																						</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p> </p>
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td colspan="3">
										<font face="Arial" size="4">
										</font>
								</td>
						</tr>
						<tr valign="top" align="left">
								<td>
										<p>
												<font face="Arial" size="4">
												</font>
										</p>
								</td>
								<td>
										<font face="Arial" size="4">
												<img height="5" alt="" src="http://www.ibm.com/i/c.gif" width="4" />
										</font>
								</td>
								<td width="100%">
										<p> </p>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
<img src ="http://www.blogjava.net/nomigd/aggbug/47881.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/nomigd/" target="_blank">何以解忧，唯有学习！让每一个人都能Open Source </a> 2006-05-24 20:03 <a href="http://www.blogjava.net/nomigd/articles/47881.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>