??xml version="1.0" encoding="utf-8" standalone="yes"?>久草精品视频,久久一区二区三区喷水,色婷婷综合久久久 http://www.aygfsteel.com/nomigd/category/9656.html何以解忧Q唯有学习!让每一个h都能Open Source zh-cnWed, 28 Feb 2007 21:00:44 GMTWed, 28 Feb 2007 21:00:44 GMT60JavaEye三周q_大家聊聊最喜欢的帖子一、你擦了吗?定擦了Q真的确定擦了?http://www.aygfsteel.com/nomigd/articles/66760.html何以解忧Q唯有学习!让每一个h都能Open Source 何以解忧Q唯有学习!让每一个h都能Open Source Thu, 31 Aug 2006 00:48:00 GMThttp://www.aygfsteel.com/nomigd/articles/66760.htmlhttp://www.aygfsteel.com/nomigd/comments/66760.htmlhttp://www.aygfsteel.com/nomigd/articles/66760.html#Feedback0http://www.aygfsteel.com/nomigd/comments/commentRss/66760.htmlhttp://www.aygfsteel.com/nomigd/services/trackbacks/66760.html      应用try-finallyQ我们可以在异常满天飞的E序里保证我们的关键资源被按时正清理。一个最常见的应用就是jdbc的Connection, Statement, ResultSet{?

但是Q我最q惊奇地发现Q不知道怎么正确清理资源的h大有人在Q即使是一些java老手?

看一个例子先Q?

java代码: 

void f(){
  Connection conn = ...;
  Statement stmt = conn.createStatement();
  ResultSet rset = ...;
  ...
}


典型的jdbcE序。但是也是典型的光着屁股Q其臭如兰地走出厕所的典范。哎Q你擦屁股了吗?
有的哥们振振有辞Q我不用,我的jdbc driver/我的应用服务?garbage collector会处理的?
q是典型的糊涂蛋逻辑。没有close()Qjdbc driver, 应用服务器怎么知道你是拉完了,q是光着屁股出去接个电话先?难不成这driver都智能地会算命了Q?
garbage collector倒确实管得了。不q,garbage collector不一定运行啊。你要是?0G得内存,要是你的E序q?0MQgarbage collector说不定就一直睡大觉。而且Q就它,也许{你光着屁股上班被警察抓h之后才匆匆赶刎ͼ你等的v吗?


好,有h_那我擦,我擦Q我擦擦擦。行了吧Q?


java代码: 

void f(){
  Connection conn = ...;
  Statement stmt = conn.createStatement();
  ResultSet rset = ...;
  rset.close();
  conn.close();
  ...
}



呵呵。我的傻哥们Q你只擦了靠q后背的那三公分Q剩下的嘛,别h看不见你׃得省土块儿了是么Q?

按jdbc标准QResultSet, Statement, Connection都要close()Q也许有的driver会在Connection关闭的时候同时正清理ResultSet, StatementQ但是,q没有一条规定让所有的driver都这么做?
另外Q也怽的Connection是从一个池里面来的Q它只是回到池中去,如果你不关闭Statement, ResultSetQ下一个拿到这个Connection的h也许倒霉了!
做事要有始有l,既然开始擦了,擦q净点儿Q行不?Q那个,谁谁谁,借我个防毒面具先Q)


okQ有个讲卫生的小dq样擦:


java代码: 

void f(){
  Connection conn = ...;
  Statement stmt = conn.createStatement();
  ResultSet rset = ...;
  rset.close();
  stmt.close();
  conn.close();
  ...
}



然后z洋得意地说Q我是好孩子Q我天天擦屁屁?


是啊Q多听话的孩子呀。可惜,某天Q这孩子正坐在马桶上着呢,妈妈喊了嗓子Q二dQ吃饭啦?
哦!吃饭。二d裤子都没提就H出来了Q熏得妈妈一个跟头?

什么问题,d做事一根筋Q不能打扎ͼ一旦有异常情况出现Q屁股就忘了擦了?



所以,我这里郑重提醒大ӞL"try-finally"Q它独有ҎQ防止侧?..Q糟了,串台了)

是啊Qjava老手们都不是dQ都知道用try-finally的,可是Q别,你现在就保不齐擦没擦屁股呢!


常见擦法Q?
java代码: 

void f(){
  Connection conn = null;
  Statement stmt = null;
  ResultSet rset = null;
  try{
    conn = ...;
    stmt = ...;
    rset = ...;
    ...
  }
  finally{
      if(rset!=null)rset.close();
      if(stmt!=null)stmt.close();
      if(conn!=null)conn.close();

  }
}



嗯。怎么说呢。挺聪明的。都学会if(xxx!=null)q种传说中条件判断的上古l学了?
可惜Q你屁股大,一张纸不够Q你用了W一张纸Q满意地看着它圆满地完成了金灿灿的Q务,再用W二张,靠,只太薄,破了Q一手金灿灿圎ͼ象带了个金戒指。你大怒,Pl尘而去。于是也忘了W三张纸Q?
哥们儿,close()是可以出异常的,你rset关了Qstmt.close()出现了异常,但是conn׃了Q?


q日有位室外高hQ据说是D子高徒,鉴于怜我世hQ不擦屁股的实多的高情操,亲手赚写一本绝世擦功秘c,其文,其意高,除了擦不q净之外Q真可以说是U霸擦林?

java代码: 


void close(Connection conn){
  try{
    if(conn!=null) conn.close();
  }
  catch(Exception e){
    e.printStackTrace();
  }
}
void close(ResultSet rset){
  ...
}
void close(Statement rset){
  ...
}
void f(){
  Connection conn = null;
  Statement stmt = null;
  ResultSet rset = null;
  try{
    conn = ...;
    stmt = ...;
    rset = ...;
    ...
  }
  finally{
     close(rset);
     close(stmt);
     close(conn);

  }
}



哈,你们不能U擦破了׃接着擦啊Q甚臛_而化之,不能擦股用具有了问题半途而废呀Q?

具信Q该高h以此法擦遍天下凡十数载,未有擦而无功者?

可惜Q高人却忽视了,除了U怼出故障,甚至大而化之,一切擦P如土块儿Q木条儿Q手指)都可能出现故障,q有别的地方也会出故障地Q?
除了ExceptionQ还有Error啊,我的高hQ如果close(rset)抛了一个ErrorQ你的close(stmt), close(conn)不都歇菜了?

后来Q高人在《绝世武功补遗》里面解释说QError代表不可恢复错误Q说明整个排泄大业都受阻了,所以根本不应该试图对这U情况做M处理Q你也处理不了(自然也隐含此时你也根本无法擦屁股了的论断Q。Q何试囑֜q种情况下仍然固执擦屁股的做法都是倒行逆施Q螳臂当车,必然被历史的车轮所늢?

此书一处,天下辟易。其革命性之pQ难以估量。具有关斚w评论QSunq个公共厕所的try-finallyq个工具的设定本w就是不合理的,应该被历史R轮撵的Q因为try-finally居然试图在出现Error的时候去做一些事情!是可忍,C可忍Q?
可以预见Qtry-finally被sund废弃Qƈ且向q大公众做公开道歉以检讨多q来的欺骗造成的恶劣媄响?
另外Q公厕的构造也受到质疑Q因Z旦有一个拉客在擦的时候某一步无可挽回地p|Q比如,太紧张,手一抖,U掉C坑里Q又L伸手捞不着Q,那么他就大摇大摆不再l箋擦,而如果碰巧此人刚吃了萝卜Q就会把整个厕所里的其它拉客都熏得无法l。(x一个app server吧。你一个程序歇菜,乐得L假不擦了Q别Z跟着倒霉Q)


嘿嘿Q那么,你擦了吗Q你肯定你擦了?擦干净了?

q好Q我们翻遍上古秘c,最l在北京山顶zh的失传宝典《呼|擦!》中发现了一个据U绝对干净的擦法,那就是-Q-Q-Q-Q-Q-Q?

一下一下擦Q?

具体操作办法如下Q?

java代码: 


void f(){
  finalConnection conn = ...;
  try{
    finalStatement stmt = ...;
    try{
      finalResultSet rset = ...;
      try{
        ...
      }
      finally{rset.close();}
    }
    finally{stmt.close();}
  }
  finally{conn.close();}
}




其诀H就是,每徏立一个需要清理的资源Q就用一个try-finally来保证它可以被清理掉?

如此QQ何时候,你都是屁股干q静静地d卫生间?


哪。好多圣人门徒跟我说Q这样一下一下擦Q姿劉K怸雅观Q看看那嵌套的try块吧Q,有违古礼。我们反对!


靠,你说孔丑儿古q是山顶zh古?Q?
屁股q泛着呛_呢,q拽什么“雅”?

而且Q要是死要面子,也可以拉个帘子,擦的时候别让h看见嘛。比如:

java代码: 


interface ResultListener{
  void call(ResultSet rset);
}
class SqlReader{
void read(ResultListener l){
    finalConnection conn = ...;
    try{
      finalStatement stmt = ...;
      try{
        finalResultSet rset = ...;
        try{
          l.call(rset);
        }
        finally{rset.close();}
      }
      finally{stmt.close();}
    }
    finally{conn.close();}
  }
}



q一下一下擦的动作都藏在SqlReaderq个帘子里,你直接在ResultListener里面拉不p了?

那位高h说了Q这太复杂,׃ؓ了擦个屁股不倹{?

q个嘛,g值的另说Q你那个单,是单单地擦不干净屁股。要不您q脆别擦得了Q更单呢q。反正您出门儿就愣说擦的是Chanel香水儿就是了。有啥比瞪眼儿说白话儿简单?

对了Q?我还忘了一个条ƾ:
是擦屁股的时候按序擦。谁?/span>q厕所的,要让人家?/span>出去?

“什么狗屁规则?“那位问了?

q个q个--Q啊Q你猜猜~~~Q?

嗯,对了Q是q样的,上厕所都不着急,姗姗来迟Q上课更不着急,更喜Ƣ迟CQ对不对Q而谁上课天天q到早退q不担心毕业Q当然是太子党了Q是不?
人家都太子党了,你还不让人家先出去?z腻味了你?Q此处尾韌拉长Q而且向上拐)


反正啊,具体_ResultSet最后创建,但是要先兟?

Statement其次。Connection最后?


当然了,也许在你的环境下Q次序错了也没出事情。但是,׃吃Y饭的Q吃软gq口饭的Q图啥?不就图个攑ֿ吗?上厕所囑֕Q不图个别让太子党抓去当兔子吗Q?
也许某个driverҎ序不敏感Q但是不好说哪天你换个环境就忽然她奶奶的敏感了呢Q?
比如吧,你有connection pool, conn.close()把connectionq回到connection?

你要是先conn.close()Q好嘛,connection先回到pool了,正好别的U程里面{着要connectionQ立马这个connection又给分配出去了?
q下齐了Q你statement, resultsetq没兛_Q那边事故单位领导就找上门了。什么香Ҏa的桌子,什么桐油炸丸子Q全l你送来了。这不添堵吗Q?

好在Q在我们《呼|擦!》宝怸记蝲的“一下一下擦”神功,老少咸宜Q童叟无ƺ,有道是:法擦大法好,不如法擦冰箱好!

跑题了。反正是Q只要你一个try-finally对应一个资源,你就不可能在ơ序上出错。自然而然的就是后入先出的堆栈l构?
反观别的擦法Q就没有q个效果Q次序如何,全靠你自己掌握。弄错了Q系l也不告诉你。等着吃桐油炸丸子吧?

q也是我们推q一下一下擦的一个原因?/span>

上一ơ由ajoo?005-6-09 周四, 下午12:45修改Qd修改??/span>

]]>
提升JSP应用E序的七大绝?/title><link>http://www.aygfsteel.com/nomigd/articles/60887.html</link><dc:creator>何以解忧Q唯有学习!让每一个h都能Open Source </dc:creator><author>何以解忧Q唯有学习!让每一个h都能Open Source </author><pubDate>Sun, 30 Jul 2006 12:51:00 GMT</pubDate><guid>http://www.aygfsteel.com/nomigd/articles/60887.html</guid><wfw:comment>http://www.aygfsteel.com/nomigd/comments/60887.html</wfw:comment><comments>http://www.aygfsteel.com/nomigd/articles/60887.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/nomigd/comments/commentRss/60887.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/nomigd/services/trackbacks/60887.html</trackback:ping><description><![CDATA[ <font face="Verdana"> <font color="#3399cc"> <font color="#ff0000">Ҏ一Q在servlet的init()Ҏ中缓存数?/font> <br /> </font>   当应用服务器初始化servlet实例之后Qؓ客户端请求提供服务之前,它会调用q个servlet的init()Ҏ。在一个servlet的生命周期中Qinit()Ҏ只会被调用一ơ。通过在init()Ҏ中缓存一些静态的数据或完成一些只需要执行一ơ的、耗时的操作,可大大地提高系l性能?br />  例如Q通过在init()Ҏ中徏立一个JDBCq接池是一个最佳例子,假设我们是用jdbc2.0的DataSource接口来取得数据库q接Q在通常的情况下Q我们需要通过JNDI来取得具体的数据源。我们可以想象在一个具体的应用中,如果每次SQLh都要执行一ơJNDI查询的话Q那pȝ性能会急剧下降。解x法是如下代码Q它通过~存DataSourceQ得下一ơSQL调用时仍然可以l利用它Q?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提供了一个实用的技术,卌动重载技术,它ؓ开发h员提供了一个好的开发环境,当你改变servlet和JSP面后而不必重启应用服务器。然而,q种技术在产品q行阶段对系l的资源是一个极大的损耗,因ؓ它会lJSP引擎的类装蝲?classloader)带来极大的负担。因此关闭自动重载功能对pȝ性能的提升是一个极大的帮助?br /><br /><font color="#ff0000">Ҏ 3: 不要滥用HttpSession</font><br />  在很多应用中Q我们的E序需要保持客L的状态,以便面之间可以怺联系。但不幸的是׃HTTPh天生无状态性,从而无法保存客L的状态。因此一般的应用服务器都提供了session来保存客L状态。在JSP应用服务器中Q是通过HttpSession对像来实现session的功能的Q但在方便的同时Q它也给pȝ带来了不的负担。因为每当你获得或更新sessionӞpȝ者要对它q行Ҏ的序列化操作。你可以通过对HttpSession的以下几U处理方式来提升pȝ的性能Q?br /><br />  1?如果没有必要Q就应该关闭JSP面中对HttpSession的缺省设|: 如果你没有明指定的话,每个JSP面都会~省地创Z个HttpSession。如果你的JSP中不需要用session的话Q那可以通过如下的JSP面指示W来止它:<br />Q?@ page session="false"%Q?<br /><br />  2?不要在HttpSession中存攑֤的数据对像:如果你在HttpSession中存攑֤的数据对像的话,每当对它q行dӞ应用服务器都对其进行序列化Q从而增加了pȝ的额外负担。你在HttpSession中存攄数据对像大Q那pȝ的性能׃降得快?br /><br />  3、当你不需要HttpSessionӞ快地释攑֮Q当你不再需要sessionӞ你可以通过调用HttpSession.invalidate()Ҏ来释攑֮?br /><br />  4、尽量将session的超时时间设得短一点:在JSP应用服务器中Q有一个缺省的session的超时时间。当客户在这个时间之后没有进行Q何操作的话,pȝ会将相关的session自动从内存中释放。超时时间设得越大,pȝ的性能׃低Q因此最好的Ҏ是量使得它的g持在一个较低的水^?br /><br /><font color="#ff0000">Ҏ 4: 页面输行压~?br /></font><br />  压羃是解x据冗余的一个好的方法,特别是在|络带宽不够发达的今天。有的浏览器支持gzip(GNU zip)q行来对HTML文gq行压羃Q这U方法可以戏剧性地减少HTML文g的下载时间。因此,如果你将servlet或JSP面生成的HTML面q行压羃的话Q那用户׃觉得面览速度会非常快。但不幸的是Q不是所有的览器都支持gzip压羃Q但你可以通过在你的程序中查客L览器是否支持它。下面就是关于这U方法实现的一个代码片D:<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 && encoding.indexOf("gzip") != -1)<br /> {<br />  request.setHeader("Content-Encoding" , "gzip");<br />  out = new GZIPOutputStream(request.getOutputStream());<br /> }<br /> else if (encoding != null && 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: 使用U程?/font><br />  应用服务器缺省地为每个不同的客户端请求创Z个线E进行处理,qؓ它们分派service()ҎQ当service()Ҏ调用完成后,与之相应的线E也随之撤消。由于创建和撤消U程会耗费一定的pȝ资源Q这U缺省模式降低了pȝ的性能。但所q的是我们可以通过创徏一个线E池来改变这U状c另外,我们q要个线E池讄一个最线E数和一个最大线E数。在应用服务器启动时Q它会创建数量等于最线E数的一个线E池Q当客户有请求时Q相应地从池从取Z个线E来q行处理Q当处理完成后,再将U程重新攑օ到池中。如果池中的U程不够地话Q系l会自动地增加池中线E的数量Q但总量不能过最大线E数。通过使用U程池,当客Lh急剧增加Ӟpȝ的负载就会呈现的qx的上升曲U,从而提高的pȝ的可伸羃性?br /><br /><font color="#ff0000">Ҏ 6: 选择正确的页面包含机?/font><br />  在JSP中有两种Ҏ可以用来包含另一个页面:1、用include指示W?Q?@ includee file=”test.jsp?%Q??、用jsp指示W?Qjsp:includee page=”test.jsp?flush=”true?Q?。在实际中我发现Q如果用第一U方法的话,可以使得pȝ性能更高?br /><br /><font color="#ff0000">Ҏ 7:正确地确定javabean的生命周?/font><br />  JSP的一个强大的地方是对javabean的支持。通过在JSP面中用<jsp:useBeanQ标{,可以javabean直接插入C个JSP面中。它的用方法如下:<br />Qjsp:useBean id="name" scope="page|request|session|application" class=<br />"package.className" type="typeName"Q?br />Q?jsp:useBeanQ?<br /><br />  其中scope属性指Zq个bean的生命周期。缺省的生命周期为page。如果你没有正确地选择bean的生命周期的话,它将影响pȝ的性能?br />  举例来说Q如果你只想在一ơ请求中使用某个beanQ但你却这个bean的生命周期设|成了sessionQ那当这ơ请求结束后Q这个bean仍然保留在内存中,除非session时或用户关闭浏览器。这样会耗费一定的内存Qƈ无谓的增加了JVM垃圾攉器的工作量。因此ؓbean讄正确的生命周期,q在bean的命结束后快地清理它们,会用系l性能有一个提高?br /><br /><font color="#ff0000">其它一些有用的Ҏ</font><br />  1、在字符串连接操作中量不用“+”操作符Q在java~程中,我们常常使用“+”操作符来将几个字符串连接v来,但你或许从来没有惛_q它居然会对pȝ性能造成影响吧?׃字符串是帔RQ因此JVM会生一些时的对像。你使用的“+”越多,生成的时对像就多Q这样也会给pȝ性能带来一些媄响。解决的Ҏ是用StringBuffer对像来代曎쀜+”操作符?br /><br />  2?避免使用System.out.println()ҎQ由于System.out.println()是一U同步调用,卛_调用它时Q磁盘I/O操作必须{待它的完成Q因此我们要量避免对它的调用。但我们在调试程序时它又是一个必不可的方便工具Qؓ了解册个矛盾,我徏议你最好用Log4j工具(<a target="_blank">http://Jakarta.apache.org</a> )Q它既可以方便调试,而不会生System.out.println()q样的方法?br /><br />  3?ServletOutputStream ?PrintWriter的权?使用PrintWriter可能会带来一些小的开销Q因为它所有的原始输出都{换ؓ字符来输出Q因此如果用它来作为页面输出的话,pȝ要负担一个{换过E。而用ServletOutputStream作ؓ面输出的话׃存在一个问题,但它是以二进制进行输出的。因此在实际应用中要权衡两者的利弊?br /><br />  <font size="5"><font color="#ff9900">ȝ</font></font><br />  本文的目的是通过对servlet和JSP的一些调优技术来极大地提高你的应用程序的性能Qƈ因此提升整个J2EE应用的性能。通过q些调优技术,你可以发现其实ƈ不是某种技术^収ͼ比如J2EE?NET之争Q决定了你的应用E序的性能Q重要是你要对这U^台有一个较为深入的了解Q这样你才能从根本上对自q应用E序做一个优化!</font> <img src ="http://www.aygfsteel.com/nomigd/aggbug/60887.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/nomigd/" target="_blank">何以解忧Q唯有学习!让每一个h都能Open Source </a> 2006-07-30 20:51 <a href="http://www.aygfsteel.com/nomigd/articles/60887.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用JAVA实现UBB代码http://www.aygfsteel.com/nomigd/articles/57617.html何以解忧Q唯有学习!让每一个h都能Open Source 何以解忧Q唯有学习!让每一个h都能Open Source Tue, 11 Jul 2006 03:11:00 GMThttp://www.aygfsteel.com/nomigd/articles/57617.htmlhttp://www.aygfsteel.com/nomigd/comments/57617.htmlhttp://www.aygfsteel.com/nomigd/articles/57617.html#Feedback0http://www.aygfsteel.com/nomigd/comments/commentRss/57617.htmlhttp://www.aygfsteel.com/nomigd/services/trackbacks/57617.html      怿大家一定可以想到UBB代码的解析,其实是“[b][/b]”这L格式转换成““”就可以了,但是怎么转换呢?{案是用正则表达式。利用上一期讲到的正则表达式类(sony.utils.Regex)中的eregi_replace替换ҎQ可以很L地做到。下面是一D늤例?
  String s="[b]q是_体[/b]";
  String result;
  result = Regex.eregi_replace("[b](.+?)[/b]","?1?, s);
  System.out.println(result);
  //打印l果是:
  //“这是粗体“?
q么单吗Q是的,我们只需要将其它的UBB Tag作类似的替换实CUBB代码的解析了?
下面l出一个UBBc?

/***************************UbbCode.java****************************************/
import java.util.regex.Matcher; //导入所需要的c?br />import java.util.regex.Pattern;
public class UbbCode //cd?br />{
private String source; //待{化的HTML代码字符?br />private String ubbTags[]; //UBB标记数组
private String htmlTags[]; //HTML标记数组

//初始?分别为UBB标记数组和HTML标记数组赋?br />public UbbCode()
{
byte byte0 = 74;
source = new String();
ubbTags = new String[byte0];
htmlTags = new String[byte0];
ubbTags[0] = "[b]";
htmlTags[0] = "<b>";
ubbTags[1] = "[/b]";
htmlTags[1] = "</b>";
ubbTags[2] = "[i]";
htmlTags[2] = "<em>";
ubbTags[3] = "[/i]";
htmlTags[3] = "</em>";
ubbTags[4] = "[quote]";
htmlTags[4] = "<div style=\"border-style:dashed;background-color:#CCCCCC;border-width:thin;border-color:#999999\"><br><em>";
ubbTags[5] = "[/quote]";
htmlTags[5] = "</em><br><br></div>";
ubbTags[6] = "[/size]";
htmlTags[6] = "</font>";
ubbTags[7] = "[size=6]";
htmlTags[7] = "<font style=\"font-size:6px\">";
ubbTags[8] = "[size=8]";
htmlTags[8] = "<font style=\"font-size:8px\">";
ubbTags[9] = "[size=10]";
htmlTags[9] = "<font style=\"font-size:10px\">";
ubbTags[10] = "[size=12]";
htmlTags[10] = "<font style=\"font-size:12px\">";
ubbTags[11] = "[size=14]";
htmlTags[11] = "<font style=\"font-size:14px\">";
ubbTags[12] = "[size=18]";
htmlTags[12] = "<font style=\"font-size:18px\">";
ubbTags[13] = "[size=24]";
htmlTags[13] = "<font style=\"font-size:24px\">";
ubbTags[14] = "[size=36]";
htmlTags[14] = "<font style=\"font-size:36px\">";

//字体
ubbTags[15] = "[/font]";
htmlTags[15] = "</font>";
ubbTags[16] = "[font=Arial]";
htmlTags[16] = "<font face=\"Arial\">";
ubbTags[17] = "[font=Arial Black]";
htmlTags[17] = "<font face=\"Arial Black\">";
ubbTags[18] = "[font=Verdana]";
htmlTags[18] = "<font face=\"Verdana\">";
ubbTags[19] = "[font=Times New Roman]";
htmlTags[19] = "<font face=\"Times New Roman\">";
ubbTags[20] = "[font=Garamond]";
htmlTags[20] = "<font face=\"Garamond\">";
ubbTags[21] = "[font=Courier New]";
htmlTags[21] = "<font face=\"Courier New\">";
ubbTags[22] = "[font=Webdings]";
htmlTags[22] = "<font face=\"Webdings\">";
ubbTags[23] = "[font=Wingdings]";
htmlTags[23] = "<font face=\"Wingdings\">";
ubbTags[24] = "[font=隶书]";
htmlTags[24] = "<font face=\"隶书\">";
ubbTags[25] = "[font=q圆]";
htmlTags[25] = "<font face=\"q圆\">";
ubbTags[26] = "[font=Ҏ舒体]";
htmlTags[26] = "<font face=\"Ҏ舒体\">";
ubbTags[27] = "[font=Ҏ姚体]";
htmlTags[27] = "<font face=\"Ҏ姚体\">";
ubbTags[28] = "[font=仿宋_GB2312]";
htmlTags[28] = "<font face=\"仿宋_GB2312\">";
ubbTags[29] = "[font=黑体]";
htmlTags[29] = "<font face=\"黑体\">";
ubbTags[30] = "[font=华文彩云]";
htmlTags[30] = "<font face=\"华文彩云\">";
ubbTags[31] = "[font=华文l黑]";
htmlTags[31] = "<font face=\"华文l黑\">";
ubbTags[32] = "[font=华文新魏]";
htmlTags[32] = "<font face=\"华文新魏\">";
ubbTags[33] = "[font=华文中宋]";
htmlTags[33] = "<font face=\"华文中宋\">";
ubbTags[34] = "[font=华文行楷]";
htmlTags[34] = "<font face=\"华文行楷\">";
ubbTags[35] = "[font=楷体_GB2312]";
htmlTags[35] = "<font face=\"楷体_GB2312\">";
ubbTags[36] = "[font=隶书]";
htmlTags[36] = "<font face=\"隶书\">";
ubbTags[37] = "[font=华文楷体]";
htmlTags[37] = "<font face=\"华文楷体\">";
ubbTags[38] = "[font=宋体]";
htmlTags[38] = "<font face=\"宋体\">";
ubbTags[39] = "[font=新宋?;
htmlTags[39] = "<font face=\"新宋体\">";
ubbTags[40] = "[font=q圆";
htmlTags[40] = "<font face=\"q圆\">";

//字体颜色
ubbTags[41] = "[red]";
htmlTags[41] = "<font color=\"red\">";
ubbTags[42] = "[/red]";
htmlTags[42] = "</font>";
ubbTags[43] = "[blue]";
htmlTags[43] = "<font color=\"blue\">";
ubbTags[44] = "[/blue]";
htmlTags[44] = "</font>";
ubbTags[45] = "[yellow]";
htmlTags[45] = "<font color=\"yellow\">";
ubbTags[46] = "[/yellow]";
htmlTags[46] = "</font>";
ubbTags[47] = "[green]";
htmlTags[47] = "<font color=\"green\">";
ubbTags[48] = "[/green]";
htmlTags[48] = "</font>";

ubbTags[49] = "[f]";
htmlTags[49] = "<marquee width=\"400\" scrolldelay=\"30\" scrollamount=\"1\" onmouseover=\"this.stop()\" onmouseout=\"this.start()\">";

//标题
ubbTags[50] = "[h1]";
htmlTags[50] = "<h1>";
ubbTags[51] = "[/h1]";
htmlTags[51] = "</h1>";
ubbTags[52] = "[h2]";
htmlTags[52] = "<h2>";
ubbTags[53] = "[/h2]";
htmlTags[53] = "</h2>";
ubbTags[54] = "[h3]";
htmlTags[54] = "<h3>";
ubbTags[55] = "[/h3]";
htmlTags[55] = "</h3>";
ubbTags[56] = "[h4]";
htmlTags[56] = "<h4>";
ubbTags[57] = "[/h4]";
htmlTags[57] = "</h4>";
ubbTags[58] = "[h5]";
htmlTags[58] = "<h5>";
ubbTags[59] = "[/h5]";
htmlTags[59] = "</h5>";
ubbTags[60] = "[h6]";
htmlTags[60] = "<h6>";
ubbTags[61] = "[/h6]";
htmlTags[61] = "</h6>";
ubbTags[62] = "[hr]";
htmlTags[62] = "<hr>";
ubbTags[63] = "[img]";
htmlTags[63] = "<br><img src=\"";
ubbTags[64] = "[/img]";
htmlTags[64] = "\"><br>";
ubbTags[65] = "[center]";
htmlTags[65] = "<div align=\"center\">";
ubbTags[66] = "[/center]";
htmlTags[66] = "</div>";

ubbTags[67] = "[/f]";
htmlTags[67] = "</marquee>";
ubbTags[68] = "[left]";
htmlTags[68] = "<div align=\"left\">";
ubbTags[69] = "[/left]";
htmlTags[69] = "</div>";
ubbTags[70] = "[right]";
htmlTags[70] = "<div align=\"right\">";
ubbTags[71] = "[/right]";
htmlTags[71] = "</div>";
ubbTags[72] = "[u]";
htmlTags[72] = "<u>";
ubbTags[73] = "[/u]";
htmlTags[73] = "</u>";

}

private String replace(String s, String s1, String s2) {
  StringBuffer stringbuffer = new StringBuffer();
  for(int i = 0; i < s1.length(); i++) {
  char c = s1.charAt(i);
  switch(c) {
   case 91: // '['
    stringbuffer.append("\\[");
    break;

   case 93: // ']'
     stringbuffer.append("\\]");
     break;

   default:
     stringbuffer.append(c);
     break;
   }
}

Pattern pattern = Pattern.compile(stringbuffer.toString());
Matcher matcher = pattern.matcher(s);
StringBuffer stringbuffer1 = new StringBuffer();
for(boolean flag = matcher.find(); flag; flag = matcher.find())
matcher.appendReplacement(stringbuffer1, s2);

return matcher.appendTail(stringbuffer1).toString();
}

private String replaceNormalUBBCode(String s)
{
String s1 = new String(s);
for(int i = 0; i < ubbTags.length; i++)
s1 = replace(s1, ubbTags[i], htmlTags[i]);

return s1;
}

private String replaceURL(String s)
{
StringBuffer stringbuffer = new StringBuffer(s);
String s1 = new String();
int i = s.indexOf("[url]");
int j = s.indexOf("[/url]");
if(i != -1 && j != -1 && i < j)
{
String s2 = s.substring(i + 5, j);
String s3 = "<a href=\"" + s2 + "\">" + s2 + "</a>";
stringbuffer.replace(i, j + 6, s3);
}
return stringbuffer.toString();
}

private String replaceEmail(String s)
{
StringBuffer stringbuffer = new StringBuffer(s);
String s1 = new String();
int i = s.indexOf("[email]");
int j = s.indexOf("[/email]");
if(i != -1 && j != -1 && i < j)
{
String s2 = s.substring(i + 7, j);
String s3 = "<a href=\"mailto:" + s2 + "\">" + s2 + "</a>";
stringbuffer.replace(i, j + 8, s3);
}
return stringbuffer.toString();
}

public void setSource(String s)
{
source = s;
}

public String getResult()
{
return source;
}

public void run()
{
for(source = replaceNormalUBBCode(source); source.indexOf("[url]") != -1 && source.indexOf("[/url]") != -1;
  source = replaceURL(source));
for(; source.indexOf("[email]") != -1 && source.indexOf("[/email]") != -1; source = replaceEmail(source));
}
}

 



何以解忧Q唯有学习!让每一个h都能Open Source 2006-07-11 11:11 发表评论
]]>
JAVA中的指针,引用及对象的clonehttp://www.aygfsteel.com/nomigd/articles/47881.html何以解忧Q唯有学习!让每一个h都能Open Source 何以解忧Q唯有学习!让每一个h都能Open Source Wed, 24 May 2006 12:03:00 GMThttp://www.aygfsteel.com/nomigd/articles/47881.htmlhttp://www.aygfsteel.com/nomigd/comments/47881.htmlhttp://www.aygfsteel.com/nomigd/articles/47881.html#Feedback0http://www.aygfsteel.com/nomigd/comments/commentRss/47881.htmlhttp://www.aygfsteel.com/nomigd/services/trackbacks/47881.html看到q个标题Q是不是有点困惑QJava语言明确说明取消了指针,因ؓ指针往往是在带来方便的同时也是导致代码不安全的根源,同时也会使程序的变得非常复杂难以理解Q滥用指针写成的代码不亚于用早已臭名昭著的"GOTO"语句。Java攑ּ指针的概늻Ҏ极其明智的。但q只是在Java语言中没有明的指针定义Q实质上每一个new语句q回的都是一个指针的引用Q只不过在大多时候Java中不用关心如何操作这?指针"Q更不用象在操作CQ+的指针那栯战心惊。唯一要多多关心的是在l函C递对象的时候。如下例E:

												
														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

*
*/

												
										

q段代码的主要部分调用了两个很相q的ҎQchangeObj()和changePri()。唯一不同的是它们一个把对象作ؓ输入参数Q另一个把Java中的基本cdint作ؓ输入参数。ƈ且在q两个函C内部都对输入的参数进行了改动。看gLҎQ程序输出的l果却不太一栗changeObj()Ҏ真正的把输入的参数改变了Q而changePri()Ҏ对输入的参数没有M的改变?/p>

从这个例子知道Java对对象和基本的数据类型的处理是不一L。和C语言一P当把Java的基本数据类型(如intQcharQdouble{)作ؓ入口参数传给函数体的时候,传入的参数在函数体内部变成了局部变量,q个局部变量是输入参数的一个拷贝,所有的函数体内部的操作都是针对q个拯的操作,函数执行l束后,q个局部变量也完成了它的使命Q它影响不到作ؓ输入参数的变量。这U方式的参数传递被UCؓ"g?。而在Java中用对象的作为入口参数的传递则~省?引用传?Q也是说仅仅传递了对象的一?引用"Q这?引用"的概念同C语言中的指针引用是一L。当函数体内部对输入变量改变Ӟ实质上就是在对这个对象的直接操作?/p>

除了在函C值的时候是"引用传?Q在M?Q?向对象变量赋值的时候都?引用传?。如Q?/p>
												
														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
*/

												
										

W一句是在内存中生成一个新的PassObj对象Q然后把q个PassObj的引用赋l变量objAQ第二句是把PassObj对象的引用又赋给了变量objB。此时objA和objB是两个完全一致的变量Q以后Q何对objA的改变都{同于对objB的改变?/p>

即明白了Java语言中的"指针"概念也许q会不经意间犯下面的错误?/p>

Hashtable真的能存储对象吗Q?/font>

看一看下面的很简单的代码Q先是声明了一个Hashtable和StringBuffer对象Q然后分四次把StriingBuffer对象攑օ到Hashtable表中Q在每次攑օ之前都对q个StringBuffer对象append()了一些新的字W串Q?/p>
												
														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());
        }
    }
}

												
										

如果你认出的l果是:
get StringBufffer 1 from Hashtable: abc,
get StringBufffer 2 from Hashtable: abc,defQ?
get StringBufffer 3 from Hashtable: abc,def,mno,
get StringBufffer 4 from Hashtable: abc,def,mno,xyz.

那么你就要回q头再仔l看一看上一个问题了Q把对象时作为入口参Cl函敎ͼ实质上是传递了对象的引用,向Hashtable传递StringBuffer对象也是只传递了q个StringBuffer对象的引用!每一ơ向Hashtable表中put一ơStringBufferQƈ没有生成新的StringBuffer对象Q只是在Hashtable表中又放入了一个指向同一StringBuffer对象的引用而已?/p>

对Hashtable表存储的M一个StringBuffer对象Q更切的说应该是对象的引用Q的改动Q实际上都是对同一?StringBuffer"的改动。所以Hashtableq不能真正存储能对象Q而只能存储对象的引用。也应该知道q条原则对与Hashtable怼的Vector, List, Map, Set{都是一L?/p>

上面的例E的实际输出的结果是Q?/p>
												
														/* 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>


c,对象与引?/font>

Java最基本的概念就是类Q类包括函数和变量。如果想要应用类Q就要把cȝ成对象,q个q程被称?cȝ实例?。有几种Ҏ把类实例化成对象Q最常用的就是用"new"操作W。类实例化成对象后,意味着要在内存中占据一块空间存攑֮例。想要对q块I间操作p应用到对象的引用。引用在Java语言中的体现是变量Q而变量的cd是q个引用的对象。虽然在语法上可以在生成一个对象后直接调用该对象的函数或变量,如:

												
														new String("Hello NDP")).substring(0,3)  //RETURN RESULT: Hel

												
										

但由于没有相应的引用Q对q个对象的用也只能局限这条语句中了?/p>

  1. 产生Q引用L在把对象作参?传?的过E中自动发生Q不需要h为的产生Q也不能Zؓ的控制引用的产生。这个传递包括把对象作ؓ函数的入口参数的情况Q也包括?Q?q行对象赋值的时候?
  2. 范围Q只有局部的引用Q没有局部的对象。引用在Java语言的体现就是变量,而变量在Java语言中是有范围的Q可以是局部的Q也可以是全局的?
  3. 生存期:E序只能控制引用的生存周期。对象的生存期是由Java控制。用"new Object()"语句生成一个新的对象,是在计算机的内存中声明一块区域存储对象,只有Java的垃圾收集器才能军_在适当的时候回收对象占用的内存?
  4. 没有办法L对引用的改动?




回页?/font>


什么是"clone"Q?/font>

在实际编E过E中Q我们常常要遇到q种情况Q有一个对象AQ在某一时刻A中已l包含了一些有效|此时可能会需要一个和A完全相同新对象BQƈ且此后对BM改动都不会媄响到A中的|也就是说QA与B是两个独立的对象Q但B的初始值是由A对象定的。在Java语言中,用简单的赋D句是不能满q种需求的。要满q种需求虽然有很多途径Q但实现cloneQ)Ҏ是其中最单,也是最高效的手Dc?/p>

Java的所有类都默认承java.lang.Objectc,在java.lang.ObjectcM有一个方法clone()。JDK API的说明文档解释这个方法将q回Object对象的一个拷贝。要说明的有两点Q一是拷贝对象返回的是一个新对象Q而不是一个引用。二是拷贝对象与用new操作W返回的新对象的区别是q个拯已经包含了一些原来对象的信息Q而不是对象的初始信息?/p>



回页?/font>


怎样应用clone()ҎQ?/font>

一个很典型的调用clone()代码如下Q?/p>
												
														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;
    }
?

												
										

有三个值得注意的地方,一是希望能实现clone功能的CloneClasscdCCloneable接口Q这个接口属于java.lang包,java.lang包已l被~省的导入类中,所以不需要写成java.lang.Cloneable。另一个值得h意的是重载了clone()Ҏ。最后在clone()Ҏ中调用了super.clone()Q这也意味着无论clonecȝl承l构是什么样的,super.clone()直接或间接调用了java.lang.Objectcȝclone()Ҏ。下面再详细的解释一下这几点?/p>

应该说第三点是最重要的,仔细观察一下Objectcȝclone()一个nativeҎQnativeҎ的效率一般来说都是远高于java中的非nativeҎ。这也解释了Z么要用Object中clone()Ҏ而不是先new一个类Q然后把原始对象中的信息赋到新对象中Q虽然这也实Cclone功能。对于第二点Q也要观察ObjectcM的clone()q是一个protected属性的Ҏ。这也意味着如果要应用clone()ҎQ必ȝ承Objectc,在Java中所有的cL~省l承ObjectcȝQ也׃用关心这点了。然后重载clone()Ҏ。还有一点要考虑的是Z让其它类能调用这个clonecȝclone()ҎQ重载之后要把clone()Ҏ的属性设|ؓpublic?/p>

那么clonecMؓ什么还要实现Cloneable接口呢?E微注意一下,Cloneable接口是不包含MҎ的!其实q个接口仅仅是一个标志,而且q个标志也仅仅是针对ObjectcMclone()Ҏ的,如果clonecL有实现Cloneable接口Qƈ调用了Object的clone()ҎQ也是调用了super.Clone()ҎQ,那么Object的clone()Ҏ׃抛出CloneNotSupportedException异常?/p>

以上是clone的最基本的步骤,惌完成一个成功的cloneQ还要了解什么是"影子clone"?深度clone"?/p>



回页?/font>


什么是影子cloneQ?/font>

下面的例子包含三个类UnCloneAQCloneBQCloneMain。CloneBcd含了一个UnCloneA的实例和一个intcd变量Qƈ且重载clone()Ҏ。CloneMaincd始化UnCloneAcȝ一个实例b1Q然后调用clone()Ҏ生成了一个b1的拷贝b2。最后考察一下b1和b2的输出:

												
														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
*/

												
										

输出的结果说明intcd的变量aInt和UnCloneA的实例对象unCA的clonel果不一_intcd是真正的被clone了,因ؓ改变了b2中的aInt变量Q对b1的aInt没有产生影响Q也是_b2.aInt与b1.aInt已经占据了不同的内存I间Qb2.aInt是b1.aInt的一个真正拷贝。相反,对b2.unCA的改变同时改变了b1.unCAQ很明显Qb2.unCA和b1.unCA是仅仅指向同一个对象的不同引用Q从中可以看出,调用ObjectcMclone()Ҏ产生的效果是Q先在内存中开辟一块和原始对象一LI间Q然后原h贝原始对象中的内宏V对基本数据cdQ这L操作是没有问题的Q但寚w基本cd变量Q我们知道它们保存的仅仅是对象的引用Q这也导致clone后的非基本类型变量和原始对象中相应的变量指向的是同一个对象?/p>

大多时候,q种clone的结果往往不是我们所希望的结果,q种clone也被UCؓ"影子clone"。要惌b2.unCA指向与b2.unCA不同的对象,而且b2.unCA中还要包含b1.unCA中的信息作ؓ初始信息Q就要实现深度clone?/p>



回页?/font>


怎么q行深度cloneQ?/font>

把上面的例子Ҏ深度clone很简单,需要两个改变:一是让UnCloneAcM实现和CloneBcMLclone功能Q实现Cloneable接口Q重载clone()ҎQ。二是在CloneB的clone()Ҏ中加入一句o.unCA = (UnCloneA)unCA.clone();

E序如下Q?/p>
												
														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
*/

												
										

可以看出Q现在b2.unCA的改变对b1.unCA没有产生影响。此时b1.unCA与b2.unCA指向了两个不同的UnCloneA实例Q而且在CloneB b2 = (CloneB)b1.clone();调用的那一刻b1和b2拥有相同的|在这里,b1.i = b2.i = 11?/p>

要知道不是所有的c都能实现深度clone的。例如,如果把上面的CloneBcM的UnCloneAcd变量ҎStringBuffercdQ看一下JDK API中关于StringBuffer的说明,StringBuffer没有重蝲clone()ҎQ更Z重的是StringBufferq是一个finalc,q也是说我们也不能用l承的办法间接实现StringBuffer的clone。如果一个类中包含有StringBuffercd对象或和StringBuffer怼cȝ对象Q我们有两种选择Q要么只能实现媄子cloneQ要么就在类的clone()Ҏ中加一句(假设是SringBuffer对象Q而且变量名仍是unCAQ: o.unCA = new StringBuffer(unCA.toString()); //原来的是Qo.unCA = (UnCloneA)unCA.clone();

q要知道的是除了基本数据cd能自动实现深度clone以外QString对象是一个例外,它clone后的表现好象也实C深度cloneQ虽然这只是一个假象,但却大大方便了我们的~程?/p>



回页?/font>


Clone中String和StringBuffer的区?/font>

应该说明的是Q这里不是着重说明String和StringBuffer的区别,但从q个例子里也能看出Stringcȝ一些与众不同的地方?/p>

下面的例子中包括两个c,CloneCcd含一个Stringcd变量和一个StringBuffercd变量Qƈ且实Cclone()Ҏ。在StrClonecM声明了CloneCcd变量c1Q然后调用c1的clone()Ҏ生成c1的拷贝c2Q在对c2中的String和StringBuffercd变量用相应的Ҏ改动之后打印l果Q?/p>
												
														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
*
*/

												
										

打印的结果可以看出,Stringcd的变量好象已l实C深度cloneQ因为对c2.str的改动ƈ没有影响到c1.strQ难道Java把Sringcȝ成了基本数据cdQ其实不Ӟq里有一个小的把戏Q秘密就在于c2.str = c2.str.substring(0,5)q一语句Q实质上Q在clone的时候c1.str与c2.str仍然是引用,而且都指向了同一个String对象。但在执行c2.str = c2.str.substring(0,5)的时候,它作用相当于生成了一个新的StringcdQ然后又赋回lc2.str。这是因为String被Sun公司的工E师写成了一个不可更改的c(immutable classQ,在所有StringcM的函数都不能更改自n的倹{下面给出很单的一个例子:

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 */

例子中,虽然str1调用了substring()ҎQ但str1的值ƈ没有改变。类似的QStringcM的其它方法也是如此。当然如果我们把最上面的例子中的这两条语句

												
														c2.str = c2.str.substring(0,5);
c2.strBuff = c2.strBuff.append(" change strBuff clone");
       
												
										

Ҏ下面q样Q?/p>
												
														c2.str.substring(0,5);
c2.strBuff.append(" change strBuff clone");

												
										

L了重新赋值的q程Qc2.str也就不能有变化了Q我们的把戏也就露馅了。但在编E过E中只调?/p>
												
														c2.str.substring(0,5);

												
										

语句是没有Q何意义的?/p>

应该知道的是在Java中所有的基本数据cd都有一个相对应的类Q象Integercd应intcdQDoublecd应doublecd{等Q这些类也与Stringcȝ同,都是不可以改变的cR也是_q些的类中的所有方法都是不能改变其自n的值的。这也让我们在编clonecȝ时候有了一个更多的选择。同时我们也可以把自qcȝ成不可更改的cR?/p>




 


 

 




]]>
վ֩ģ壺 | | | Դ| ɽ| Ӣ| | | ƽ| | | ɿ| | | ̩| | ̩| | | | ζ| ʡ| Ӫɽ| | | 㶫ʡ| | | | | ͨ| | ͳ| | | | | ƽ| ױ| ϳ| |