﻿<?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-zhb8015-文章分类-interview</title><link>http://www.blogjava.net/zhb8015/category/50985.html</link><description /><language>zh-cn</language><lastBuildDate>Thu, 11 Apr 2013 15:37:43 GMT</lastBuildDate><pubDate>Thu, 11 Apr 2013 15:37:43 GMT</pubDate><ttl>60</ttl><item><title>Nutch vs Lucene(转)</title><link>http://www.blogjava.net/zhb8015/articles/397665.html</link><dc:creator>zhb8015</dc:creator><author>zhb8015</author><pubDate>Wed, 10 Apr 2013 13:53:00 GMT</pubDate><guid>http://www.blogjava.net/zhb8015/articles/397665.html</guid><wfw:comment>http://www.blogjava.net/zhb8015/comments/397665.html</wfw:comment><comments>http://www.blogjava.net/zhb8015/articles/397665.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zhb8015/comments/commentRss/397665.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zhb8015/services/trackbacks/397665.html</trackback:ping><description><![CDATA[<div>原文：：：<br />http://wangfei4553693.blog.163.com/blog/static/270104772011451312819/</div><div><p><br /></p><p>&nbsp;Lucene其实是一个提供全文文本搜索的函数库，它不是一个应用软件。它提供很多API函数让你可以运用到各种实际应用程序中。现在，它已经成为Apache的一个项目并被广泛应用着。这里列出一些已经使用Lucene的系统。</p>  <p>Nutch 是一个建立在Lucene核心之上的Web搜索的实现，它是一个真正的应用程序。也就是说，你可以直接下载下来拿过来用。它在Lucene的基础上加了网 络爬虫和一些和Web相关的东东。其目的就是想从一个简单的站内索引和搜索推广到全球网络的搜索上，就像Google和Yahoo一样。当然，和那些巨人 竞争，你得动一些脑筋，想一些办法。我们已经测试过100M的网页，并且它的设计用在超过1B的网页上应该没有问题。当然，让它运行在一台机器上，搜索一 些服务器，也运行的很好。</p>  <p>&nbsp;&nbsp; 总的来说，我认为LUCENE会应用在本地服务器的网站内部搜索，而Nutch则扩展到整个网络、Internet的检索。当然LUCENE加上爬虫程序等就会成为Nutch，这样理解应该没错吧。</p>  <p>&nbsp;</p>  <p>本文来自CSDN博客，转载请标明出处：<a rel="nofollow" href="http://blog.csdn.net/rokii/archive/2008/03/01/2137450.aspx">http://blog.csdn.net/rokii/archive/2008/03/01/2137450.aspx</a></p>  <p>简单的说:&nbsp; <br />z&nbsp; Lucene 不是完整的应用程序，而是一个用于实现全文检索的软件库。 <br />z&nbsp; Nutch&nbsp; 是一个应用程序，可以以 Lucene 为基础实现搜索引擎应用。 <br />Lucene 为 Nutch 提供了文本索引和搜索的 API。一个常见的问题是；我应<br />该使用 Lucene 还是Nutch？最简单的回答是：如果你不需要抓取数据的话，应该<br />使用Lucene。常见的应用场合是：你有数据源，需要为这些数据提供一个搜索页<br />面。在这种情况下，最好的方式是直接从数据库中取出数据并用 Lucene API 建立<br />索引。 <br />&nbsp;</p></div><img src ="http://www.blogjava.net/zhb8015/aggbug/397665.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zhb8015/" target="_blank">zhb8015</a> 2013-04-10 21:53 <a href="http://www.blogjava.net/zhb8015/articles/397665.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ArrayList空间增长是怎么样的</title><link>http://www.blogjava.net/zhb8015/articles/395964.html</link><dc:creator>zhb8015</dc:creator><author>zhb8015</author><pubDate>Sat, 02 Mar 2013 05:49:00 GMT</pubDate><guid>http://www.blogjava.net/zhb8015/articles/395964.html</guid><wfw:comment>http://www.blogjava.net/zhb8015/comments/395964.html</wfw:comment><comments>http://www.blogjava.net/zhb8015/articles/395964.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zhb8015/comments/commentRss/395964.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zhb8015/services/trackbacks/395964.html</trackback:ping><description><![CDATA[题目：RT<br />分析源码：ensureCapacity会保证ArrayList每次的增长不小于minCapacity，大概增长为原容量的2/3<br />ArrayList.add(E e)<br /><br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008080; ">1</span>&nbsp;<span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">boolean</span><span style="color: #000000; ">&nbsp;add(E&nbsp;e)&nbsp;{<br /></span><span style="color: #008080; ">2</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;ensureCapacity(size&nbsp;</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">1</span><span style="color: #000000; ">);&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;Increments&nbsp;modCount!!</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">3</span>&nbsp;<span style="color: #008000; "></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;elementData[size</span><span style="color: #000000; ">++</span><span style="color: #000000; ">]&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;e;<br /></span><span style="color: #008080; ">4</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">return</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">true</span><span style="color: #000000; ">;<br /></span><span style="color: #008080; ">5</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;}</span></div><br />ArrayList.ensureCapacity(int minCapacity)<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008080; ">&nbsp;1</span>&nbsp;<span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;ensureCapacity(</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;minCapacity)&nbsp;{<br /></span><span style="color: #008080; ">&nbsp;2</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;modCount</span><span style="color: #000000; ">++</span><span style="color: #000000; ">;<br /></span><span style="color: #008080; ">&nbsp;3</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;oldCapacity&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;elementData.length;<br /></span><span style="color: #008080; ">&nbsp;4</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(minCapacity&nbsp;</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">&nbsp;oldCapacity)&nbsp;{<br /></span><span style="color: #008080; ">&nbsp;5</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Object&nbsp;oldData[]&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;elementData;<br /></span><span style="color: #008080; ">&nbsp;6</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;newCapacity&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;(oldCapacity&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">3</span><span style="color: #000000; ">)</span><span style="color: #000000; ">/</span><span style="color: #000000; ">2</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">1</span><span style="color: #000000; ">;<br /></span><span style="color: #008080; ">&nbsp;7</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(newCapacity&nbsp;</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">&nbsp;minCapacity)<br /></span><span style="color: #008080; ">&nbsp;8</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;newCapacity&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;minCapacity;<br /></span><span style="color: #008080; ">&nbsp;9</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;minCapacity&nbsp;is&nbsp;usually&nbsp;close&nbsp;to&nbsp;size,&nbsp;so&nbsp;this&nbsp;is&nbsp;a&nbsp;win:</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">10</span>&nbsp;<span style="color: #008000; "></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;elementData&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;Arrays.copyOf(elementData,&nbsp;newCapacity);<br /></span><span style="color: #008080; ">11</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;}<br /></span><span style="color: #008080; ">12</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;}</span></div><img src ="http://www.blogjava.net/zhb8015/aggbug/395964.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zhb8015/" target="_blank">zhb8015</a> 2013-03-02 13:49 <a href="http://www.blogjava.net/zhb8015/articles/395964.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>手工打包（jar）</title><link>http://www.blogjava.net/zhb8015/articles/385075.html</link><dc:creator>zhb8015</dc:creator><author>zhb8015</author><pubDate>Wed, 08 Aug 2012 07:59:00 GMT</pubDate><guid>http://www.blogjava.net/zhb8015/articles/385075.html</guid><wfw:comment>http://www.blogjava.net/zhb8015/comments/385075.html</wfw:comment><comments>http://www.blogjava.net/zhb8015/articles/385075.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zhb8015/comments/commentRss/385075.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zhb8015/services/trackbacks/385075.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; <br />一个小工具用到了手工打包，头疼了一段时间，现在把自己的经验记录一下，希望对遇到同样问题的朋友有帮助。<br /><div>一、需求<br />二、手工打包<br />三、fat jar 上场<br /><div>所有文件及脚本，fat jar 都可下载(<div>http://www.blogjava.net/zhb8015/admin/Files.aspx)</div>************<br /> 一、需求：包涉及到三个类(src)，几个jar包(lib)，两个属性配置文件，一个jar包内(config/db.properties)一个jar包外(bams.properties)，简单路径如下,<br />全路径在最后。我遇到的难点：A 属性文件的读取，包内包外相对路径获取。B 三方jar包如何打入。<br /><br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">C:\TEST\JARTEST<br />&#9500;&#9472;</span><span style="color: #000000; ">1.5</span><span style="color: #000000; "><br />&#9500;&#9472;build<br />&#9474;&nbsp;&nbsp;&#9500;&#9472;classes<br />&#9474;&nbsp;&nbsp;&#9474;&nbsp;&nbsp;&#9500;&#9472;com<br />&#9474;&nbsp;&nbsp;&#9474;&nbsp;&nbsp;&#9474;&nbsp;&nbsp;&#9492;&#9472;vanceinfo<br />&#9474;&nbsp;&nbsp;&#9474;&nbsp;&nbsp;&#9474;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#9492;&#9472;jvmmem<br />&#9474;&nbsp;&nbsp;&#9474;&nbsp;&nbsp;&#9500;&#9472;config<br />&#9474;&nbsp;&nbsp;&#9474;&nbsp;&nbsp;&#9492;&#9472;lib<br />&#9474;&nbsp;&nbsp;&#9492;&#9472;jar<br />&#9500;&#9472;config<br />&#9500;&#9472;lib<br />&#9500;&#9472;src<br />&#9474;&nbsp;&nbsp;&#9492;&#9472;com<br />&#9474;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#9492;&#9472;vanceinfo<br />&#9474;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#9492;&#9472;jvmmem</span></div><br /> </div></div><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">C:\test\jartest</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">tree&nbsp;</span><span style="color: #000000; ">/</span><span style="color: #000000; ">F&nbsp;src<br />卷&nbsp;system&nbsp;的文件夹&nbsp;PATH&nbsp;列表<br />卷序列号为&nbsp;</span><span style="color: #000000; ">2099</span><span style="color: #000000; ">-</span><span style="color: #000000; ">0161</span><span style="color: #000000; "><br />C:\TEST\JARTEST\SRC<br />&#9492;&#9472;com<br />&nbsp;&nbsp;&nbsp;&nbsp;&#9492;&#9472;vanceinfo<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#9492;&#9472;jvmmem<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MessageData.java<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ParsingLogFile.java<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ParsingLogFileTest.java</span></div><br />二、手工打包：<br />打包前先讲一下文件的读取，包内和包外相对路径：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF; ">if</span><span style="color: #000000; ">(isDir)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">read&nbsp;from&nbsp;user.dir</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;inputStream&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;FileInputStream(</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;File(fileName));&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="color: #0000FF; ">else</span><span style="color: #000000; ">&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">read&nbsp;from&nbsp;jar</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;inputStream&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;getClass().getResourceAsStream(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">/</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;fileName);&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></div>说明：//read from jar是从jar包中读取congfig/db.properties属性文件&nbsp; fileName= "config/db.properties";<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //read from user.dir 这里采用的是从绝对路径读取的fileName = System.getProperty("user.dir") + "/";读取bams.properties<br />A、命令行编译:&nbsp; C:\test\jartest&gt;javac -cp&nbsp; (第三方jar路径)&nbsp; src\com\vanceinfo\jvmmem\*.java<br />&nbsp;&nbsp;&nbsp;&nbsp; 进入C:\test\jartest\src,并拷贝必须的属性文件进行打包，属性文件为 config/db.properties--&gt;.../src/<br />&nbsp;&nbsp;&nbsp;&nbsp; 编写MANIFEST.MF,这里一定要注意格式（这里不再详述，网上文章很多）<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">Manifest</span><span style="color: #000000; ">-</span><span style="color: #000000; ">Version:&nbsp;</span><span style="color: #000000; ">1.0</span><span style="color: #000000; "><br />Ant</span><span style="color: #000000; ">-</span><span style="color: #000000; ">Version:&nbsp;Apache&nbsp;Ant&nbsp;</span><span style="color: #000000; ">1.7</span><span style="color: #000000; ">.</span><span style="color: #000000; ">1</span><span style="color: #000000; "><br />Created</span><span style="color: #000000; ">-</span><span style="color: #000000; ">By:&nbsp;</span><span style="color: #000000; ">20.2</span><span style="color: #000000; ">-</span><span style="color: #000000; ">b06&nbsp;(Sun&nbsp;Microsystems&nbsp;Inc.)<br />Main</span><span style="color: #000000; ">-</span><span style="color: #000000; ">Class:&nbsp;com.vanceinfo.jvmmem.ParsingLogFile<br />Class</span><span style="color: #000000; ">-</span><span style="color: #000000; ">Path:&nbsp;lib</span><span style="color: #000000; ">/</span><span style="color: #000000; ">junit&nbsp;lib</span><span style="color: #000000; ">/</span><span style="color: #000000; ">junit</span><span style="color: #000000; ">-</span><span style="color: #000000; ">3.8</span><span style="color: #000000; ">.</span><span style="color: #000000; ">1</span><span style="color: #000000; ">.jar&nbsp;config</span><span style="color: #000000; ">/</span><span style="color: #000000; ">db.properties&nbsp;lib</span><span style="color: #000000; ">/</span><span style="color: #000000; ">ojd<br />&nbsp;bc14.jar&nbsp;lib</span><span style="color: #000000; ">/</span><span style="color: #000000; ">log4j</span><span style="color: #000000; ">-</span><span style="color: #000000; ">1.2</span><span style="color: #000000; ">.</span><span style="color: #000000; ">8</span><span style="color: #000000; ">.jar&nbsp;lib</span><span style="color: #000000; ">/</span><span style="color: #000000; ">mysql</span><span style="color: #000000; ">-</span><span style="color: #000000; ">connector</span><span style="color: #000000; ">-</span><span style="color: #000000; ">java</span><span style="color: #000000; ">-</span><span style="color: #000000; ">5.0</span><span style="color: #000000; ">.</span><span style="color: #000000; ">8</span><span style="color: #000000; ">-</span><span style="color: #000000; ">bin.jar&nbsp;l<br />&nbsp;ib</span><span style="color: #000000; ">/</span><span style="color: #000000; ">ojdbc14.jar<br /><br /></span></div><br />&nbsp;&nbsp;&nbsp;&nbsp; 运行打包命令&nbsp;&nbsp; java cvfm parsing.jar MANIFEST.MF com config lib 生成parsing.jar ，至此包已打完。<br />&nbsp;&nbsp;&nbsp; 注意：运行java -jar parsing.jar是找不到jar包的，也就是它不能读到jar包中的第三方包。<br />B、上面的文件路径其实是为Ant的准备的，有兴趣的朋友可以看一下 下载下build.xml研究一下。<br />三、fat jar打包工具<br />查了好多资料还是没有解决，不过找到了一个比较好的打包工具 fat jar。<br />这个插件的介绍：<div>http://fhqdddddd.blog.163.com/blog/static/186991542011427104124407/</div>真的很方便，几步就搞定了。最好新建一个工程，拷贝所需要的文件.截图如下：<br /><div><img src="data:image/png;base64,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" alt="" /><br />选择第三方包，还能导出ant</div><div><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgUAAAGzCAIAAAAwhfOvAAAbpUlEQVR4nO3dr4/c5r7H8YGFgYEBF9xIB7SslQ5IpIuiA6rASJeE3dDA1QHRqiBaBVTagEgpqJSSKio4oCDS9g+40pYtDVxQsOCABSF7wMx6bD8//Pjxx2Pv9/sevWQ5Xs9jj2f8+Yxnf2Rz8efZ1eXniz/PLv4827w63rw6fvbo9Pmj0+ePTr/727Ojfx4//f75d18//fz58/n/nz/+9unz/33x4v9efvffT5/9/eT5o9Pn/3O6+efR5tXx5lV7ehzMH3/Vncb90J0Oudedxr1OT2Pud6Yn918f3zqJT990p2/a063jB29O7r85aabDfkxPbz3sToe9TU/fnnwTm7acBvPB9N1++t2702/etaenzfw4P+2nj3vTn/bTcX7eT5/0pj/vpwnvB6dPf+lOf9lPb7Xnizz7NTmt9rw9/a0zTfgQzPenL9rTf+2mL8LpGC/b098/vExNxzjqTvc+dadxH4P5j0efPhx3p8fN9I/e9ON+/o+Pm5lvo7cS9sHj70+fPTp99uj02d9Pn3x9/OTro8d/e/n0Hy+e/uP5N//17Om3J0++Pnr67fF2ncffn25eHe8q4Z9HXzXzr3bzXzXzzfSHYP62ANrzX93O3wvm74Vl8PqkP78L/c58Uwb3d/Mnzfz91yfbAujMN9M3u+n9YL6ZPgjmHzRl0J5vpj/u5h808/vo380//PHkwZvjh5n5bSW8uS2Gt6f7etjO70L/tCmAb96ePvzx5JvOfHf6Nphvhf7DVAHkp++C+V09nHz3037+8U+7JbfRf/J4eL5VD++a0H/fVMWTn9+3CuB9qwDC+e705/38Nu4fd0M/XgDF06edqjh99mtTFbv5VvSXzO+zvpl//uuHfQH89qEV+uF8crqL+187of+8HfrdAiiZduvh/cv2/O+3S/71YTf/e9F8rx6OOvMf9wXwKZj/1J7/eBTMN9PjZr5XAH8E893pcTC/TpE+GO9oXwmRK4Nt9O/nv4peJfzQnf9h4CrhXnf+XvQq4XX6KuF15CphG/33ulcGiauE49iVwUl//vbKoJl/sLtKOB64MoheJWSvDHJXCW/TVwlvm5JoXxnsrgYexq8Mgvl33auErbfxK4PuVUL6iuGn/fzj3lVCL/qrrhKe9K4Sft5fJTzZXyW8D64MUvOxkvjlfSv632evEpJXDNtwj14l9KJ/7JXBs/aVwe38zq/Rq4HcfKYkXvz2oX9l0LlKSF4xvGzP/56+Svh9xFXCUXf+aF8M3auET81VQng10J8/7s4ft4rh+NPH1lVC58pgnTp9AABwq9MH53+dAwAG3Vi80QcAMNrS0S29fbm5vr65+jd9AADjLR3hituXm+vbJri6urm6og8AYLyls3zSbVsD7SagDwCg0tKRXnlrmuD6utME9AEAVFo62EfevnSb4N+RMqAPAKDG0gE/4nb95VZTBvQBAKgsHfJFt30TtL91TB8AgNDSUT90yzTBwfpg+zeR5jj6vT+7JNxWe0wAKLF03uduucuCiX0QBnFGdbDm79j+qrYPpg8S/onAiQ+TcgLWb+nMT9y+lJVBXR+E2TQl76rvGP3qqvpAuDJ9AKzf0sEfufWbIFMG8j6IvikO58M3vKl7pd4a974UzozaVmbkwQeV2b3qwQeP+dj9AXAAS4d/9xY2Qb4MVH0QXZ4P6/zy/IbCr07f1uDI0XFSOZ5aWLKJkgc7dn8AHMDSDdC6VZSB9vsHqj4IV8jsQ9228ok56kGVH5/CTQzuUnQ5NQAsbukS2N0iTVBSBpKfLwqjtheF5SukRs5vN9xEZlu9L5WPnNrQ4Ai9han9KTzIqXFKBgEwq6WLIHFZUFgG1Z8X9f5ZGOtjc788c8NNDOZjphLm6IPUOCW7mtkufQCsx+JlkOqDojKYuw8GMzqVcb2Ro8b2QbM8OsLgyIMPNjVCfpzBofLbpQ+A9Vi8DCq/bTDT7x9El4fz+TtGN5Tah978lG1FRy55UIMjRMeJbiJzl/w4+f0BcACLl0H0Vw1m7wMAQM/iZRD+RQr6AAAWsGwT9Pvgmj4AgIUsXgb0AQCswuJlcBMrg4o+uLy6ufzr5vKvm8+X9AEAjLd4GdzEyqD8lw+aDmijDwBgtMXL4CZWBoN/s2hbAzuX9AEATLZ8GZT3QetDIfoAAMTWWQb9PojWAH0AAEILlkHqk6J2H1xe3aIPAGBWS5ZB9pOifRPQBwBwAEv1Qe5nipqfHz1MH2T+Jk+4juq4ywccu/XFX3l3fQ8BexYpg+gnRb1fLjvo9UH7r7yVrDbRXQy7kn2ue1x38WgAJi1TBtFfRb5aug8Gg4k+mONx3cWjAZh0+D5I/tG6Zfsg+jeZw9WidwzHGfxT0pnNlfwJ6HCQ1L3CQcqX9AYfvHgaHDm126P2sOT4AKiwQB+kf71gXdcHg33QTqjUXTKby48zOFTJvVI71svokodT8tDqjs/gwrrjA2CsA/dB7v+6WbwPBhem3kTn348PjlzXKyX3KuyD8D174SGSHJ+SzZXsIYCJDtkHA/8L5l3sg1EDDo6zVB/UHY3yx5Vfs+76YHBnAIx1sD64vr65HvOXqxf4edPMwk33VrLa4OZS75oHR8hvOrpauDB/BDLHpGSvxh6f6JLUQSs8PgDGOkAflP4XmAteH9xFUwJx/WG6/j0E7Jm7D/Y/TTTyf7ahD3Lq3iOv/531+vcQMGy+Phj9X9zQBwCwoJn6oOa/uKEPAGBBc/TBiP/SgD4AgJXQdsF14j9Dpg8AYO1kVfClVQb0AQDcObOUAX0AAHfOLGVAHwDAnTNLGdAHAHDnTGmCZBnQBwBw50wpA/oAAOyYUgajPiyiDwBg1aaUAX0AAHZMKYPynyyiDwBg7aaUAX0AAHZMKYPCX0OjDwDgDqAPAADn5/QBAGBL2QfZMqAPAGDVuD4AAJyf0wcAgC36AABwfk4fAAC26AMAwPn55D4Y9SNG9AEArBfXBwCA83P6AACwZb8PPrx5AQDwqdMHV5efAQA+dfoAAOAWfQAAOLugDwAAW/QBAODsgj4AAGzRBwCAswv6AACwRR8AAM4u6AMAwBZ9AAA4u/DWB4v/eRAAB+Mn2VTc9cGGGzduDm6ukk3F11Hb9sHifykXwNxcJZsKfQDAIFfJpkIfVCq5Yl38lBh8CIvvw5r3B3eaq2RToQ8qje2DiT0xR1bOnb9jx6cPIOQq2VTog73MDyqEK++S/eo8Kpr7zZLDBF9+K6mvLlVX2mOyntLFUlwlmwp9sBfN/dTyVB9sF66/D9ZwLxuPHevkKtlU6IO9du63Vyvvg2Zhqg/ay5v53sqpz5pKlvQGr/jEZnBb4QdfJffqLUk99vKdzIyT2r1R98Jd5yrZVOiDveo+2LQ7oODzov4gsXVSy6PrRO9VF22D+xMddnBhdJyKPax77LMeMayTq2RToQ/2trm/6d7Oy/qg/c9RfZBaku+D8A1vdA8rzqJwu+Eb50yNlQwl2T36AHmukk2FPtib8nlRe/4AfTA4TmrhoJKgL9ml1Ar0AQ7DVbKp0Ad7079/kOmD1LvsaLgPJn7haNGhBuVHbl0wDH/DILrPqRHqdi+1S9F9HnUv3Gmukk2FPtiT/HxR5vpgirsYUuvZ5/XsCQ7GVbKp0Ad7Fb9/kL9Nf00LhzqYte3z2vYHh+Eq2VTog0qH6QMAdVwlmwp9AMAgV8mmQh8AMMhVsqnQBwAMcpVsKvRBJb5/AKyZq2RToQ8qVfdBxQ5U7zOdBLdcJZsKfVBpl/iH+v2DcOuLn2/AmrlKNhX6oFKqD7YL6QNgWa6STYU+qBTtg2Zhqg/ay5v53kzvvuFQhd+fSN0xtXXAElfJpkIfVGr3QacDhj4v6mX94Mx57Gqg8FEMbosmgFWukk2FPqgUpn/7cmGFfXAeXFhQBjDMVbKp0AeVwgIo/H7yqq4PFj9pgZm4SjYV+qBSrw/Kf74o9Z69fTtvfZjTe1Pf34HYmGO3BdjjKtlU6INKqj6YFXEPt1wlmwp9UCn6Xjvz1vuQ78d57w+4SjYV+qDS2D4AcEiukk2FPgBgkKtkU6EPABjkKtlU6AMABrlKNhX6oBLfPwDWzFWyqdAHlZbqA5qm5OEPrlP3HIX3kiyJvmyiexj+c3CcwXsVLpnydCzCVbKp0AeVdmfLEn/vevEzcMEdKDmwg+tksnLUveZYktnDTMr3xgmTfeKjuItcJZsKfVAp1Qebzex/73rxU3TZHZj+pvWO9kHhfP6f9AEy6INK0T5oFqb6oL28mU9dqqd2NfrVcOTUOr2NRree2Zn8vmV2svyxD45c8uwUfrXkIIc7mRqnekl4kAf3tmS+ZM2SJflnObUkdQAPw1WyqdAHlXYv8TF/7zo826On0+B5GB0nPJ9753bd1qO7UR7ZE7eeH7x6ncK8q0jnVG302iWz9fw6a+uDzENOPcsH4yrZVOiDSmH6N/8c1QfJkQvOwN6p2EucVB9kTvVecqX2Z1RGlD/26NZLBh+7zqg+yKw8NknN90H7SSx/smbiKtlU6INKYQEMfj+5MBNLNp2fmdIHJaf9fH1QeOQnrlP+WPLRVpik0Wdn7JK6+ZI1hX1Q8iwfjKtkU6EPKvX6oPDni3r5Eq62ad2iZ1T7q9HR2l8NT9fefaPZkRo280BSjzTceuaxZ5bnh51pndTRyz+QZZfkXzATl6SekejmwmN1YK6STYU+qLR7oat/3rTkDATWY7WvUlfJpkIf1J8Gg7eJIy9+Ri1rJW8zEbX+J8VVsqnQB1PPB3kfAJjOVbKp0AcADHKVbCr0AQCDXCWbCn0AwCBXyaZCH1Ti+wfAmrlKNhX6oNLYPphYEuEdB4cqWWFwl8p3m/7DqrhKNhX6oNIuJcf/Plr9tqR32RT8okPJOsA6uUo2FfqgUqoPtguFfbAJfs141B1LvkofwB5XyaZCH1SK9kGzsLwPMp8stZsguk64fkWCSz4vSj2K3nzFhQ5Qx1WyqdAHldp90OmAMZ8XtRMzOhMuTw01uK2KdUa1S3TlsBKAw3CVbCr0QaUw/duXC9V9cB5EZ/S9fzjU4LYmrjB2tN4+UwY4MFfJpkIfVAoLoOL7yZnrg/wdM2sWrjD26mH69cFMpz0Q5SrZVOiDSr0+GPz5ok331h8ntlpkc90lg7uXCfTo/kRbJz9O4fipggRm4irZVOiDSmP7oHzY6Hx+zTVY2/7AOVfJpkIfVIq+/5W8Hc7ffW3vtde2P8CWq2RToQ8qzdcHAKZzlWwq9AEAg1wlmwp9AMAgV8mmQh8AMMhVsqnQB5X4/gGwZq6STYU+qCTsg3DN5u7l40RXK7kvvQWTXCWbCn1QaZfU6t8/aI/fmxnemYKFgBOukk2FPqiU6oNN9u+bjhq/N1O4fvuf9AHccpVsKvRBpWgfNAtTfRAuTy1p98HgOue1fZDfn4qPrYCVcJVsKvRBpXYfdDog/XlR6i1/NNZHzQwOkn8g+a3TBLiLXCWbCn1QKUz/9uXCYfogNUizeyVpPnh1sviJDVRwlWwq9EGlsAAGv598yD7ILMysU7gtYP1cJZsKfVCp1weFP1+U74n2Os2a0bf54bv41MiDyZ7ZeuEVBrBCrpJNhT6oVNcHqaEWPG2Ie5jkKtlU6INK0ffRo95WL/vum/f+sM1VsqnQB5Wm9wGA+bhKNhX6AIBBrpJNhT4AYJCrZFOhDwAY5CrZVOgDAAa5SjYV+gCAQa6STYU+AGCQq2RToQ8AGOQq2VToAwAGuUo2FfoAgEGukk2FPgBgkKtkU6EPABjkKtlU6AMABrlKNhX6AIBBrpJNhT4AYJCrZFOhDwAY5CrZVOgDAAa5SjYV+gCAQa6STYU+AGCQq2RToQ8AGOQq2VToAwAGuUo2FfoAgEGukk2FPgBgkKtkU6EPABjkKtlU6AMABrlKNhX6AIBBrpJNhT4AYJCrZFOhDwAY5CrZVOgDAAa5SjYV+gCAQa6STYU+AGCQq2RToQ8AGOQq2VToAwAGuUo2FfoAgEGukk2FPgBgkKtkU6EPABjkKtlU6AMABrlKNhX6AIBBrpJNhT4AYJCrZFOhDwAY5CrZVOgDAAa5SjYV+gCAQa6STYU+AGCQq2RToQ8AGOQq2VToAwAGuUo2FfoAgEGukk2FPgBgkKtkU6EPABjkKtlU6AMABrlKNhX6AIBBrpJNhT4AYJCrZFOhDwAY5CrZVOgDAAa5SjYV+gCAQa6STYU+AGCQq2RToQ8AGOQq2VToAwAGuUo2FfoAgEGukk2FPgBgkKtkU6EPABjkKtlU6AMABrlKNhX6AIBBrpJNhT4AYJCrZFOhDwAY5CrZVOgDAAa5SjYV+gCAQa6STYU+AGCQq2RToQ8AGOQq2VToAwAGuUo2FfoAgEGukk2FPgBgUDTZri4/27PZbOgD+gBAUqoPFk+hOTJNNRp9AMCgaLLZyzr6YOqxW/yVCmBu0WSzl3X0wdRjt/grFcDcoslmL+vog6nHbvFXKoC5RZPNXtbRB1OP3eKvVABziyZbKuuikbrZbHrLwyW9L0XvcoBMU402og823Vv0AUePSPnIJU/S9GO3+CsVwNyiyTaqD6LLM6HUfGnuDggzTTXauOuDwgdcsX/VD2nUHekDwIlosmX6IHWJUB44TvtgcPPL9kFmKPoAcCKabNGsi8Za9IOQ/IcfYR9ERwiXT7FwH6Qe4WBG945Rb6j8XcI7Fj5D0WO3+CsVwNyiyVbYB9FkTyVV5l7h+sImaGeaajTB9cFgH4w6lCXjDC7MH7vFX6kA5hZNtlQfpN6eztEHkuDuZZpqtMrvH+QXDr6vnzLylONLHwBORJMtc30wdqZknGgYSoK7l2mq0Q7UB6NGHjz0mcNdcuwWf6UCmFs02cIl4efP7fn8knCc3ldTI4zKz3zKLf/zppmFm+4tf9/ooWxWywwS3YfyY7f4KxXA3Ar74K7j99GmHrvFX6kA5hZNNntZRx9MPXaLv1IBzC2abPayjj6YeuwWf6UCmFs02exlHX0w9dgt/koFMLdostnLOvpg6rFb/JUKYG7RZLOXdfTB1GO3+CsVwNyiyXZ1+fnDmxfG0Af0AYCcaLKFP9pu40Yf0AcAklwlmwp9AMAgV8mmQh8AMMhVsqnQBwAMcpVsKvQBAINcJZsKfQDAIFfJpkIfADDIVbKp0AcADHKVbCr0AQCDXCWbCn0AwCBXyaZCHwAwyFWyqdAHAAxylWwq9AEAg1wlmwp9AMAgV8mmQh8AMMhVsqnQBwAMcpVsKvQBAINcJZsKfQDAIFfJpkIfADDIVbKp0AcADHKVbCr0AQCDXCWbCn0AwCBXyaZCHwAwyFWyqdAHAAxylWwq9AEAg1wlmwp9AMAgV8mmQh8AMMhVsqnQBwAMcpVsKvQBAINcJZsKfQDAIFfJpkIfADDIVbKp0AcADHKVbCr0AQCDXCWbCn0AwCBXyaZCHwAwyFWyqdAHAAxylWwq9AEAg1wlmwp9AMAgV8mmQh8AMMhVsqnQBwAMcpVsKvQBAINcJZsKfQDAIFfJpkIfADDIVbKp0AcADHKVbCr0AQCDXCWbCn0AwCBXyaZCHwAwyFWyqdAHAAxylWwq9AEAg1wlmwp9AMAgV8mmQh8AMMhVsqnQBwAMcpVsKvQBAINcJZsKfQDAIFfJpkIfADDIVbKp0AcADHKVbCr0AQCDXCWbCn0AwCBXyaZCHwAwyFWyqdAHAAxylWwq9AEAg1wlmwp9AMAgV8mmQh8AMMhVsqnQBwAMcpVsKvQBAINcJZsKfQDAIFfJpkIfADDIVbKp0AcADHKVbCr0AQCDXCWbCn0AwCBXyaZCHwAwyFWyqdAHAAxylWwq9AEAg1wlmwp9AMAgV8mmQh8AMMhVsqnQBwAMcpVsKvQBAINcJZsKfQDAIFfJpkIfADDIVbKp0AcADHKVbCr0AQCDXCWbCn0AwCBXyaZCHwAwyFWyqdAHAAxylWwq9AEAg1wlmwp9AMAgV8mmQh8AMMhVsqnQBwAMcpVsKvQBAINcJZsKfQDAIFfJpkIfADDIVbKp0AcADHKVbCr0AQCDXCWbCn0AwCBXyaZCHwAwyFWyqdAHAAxylWwq9AEAg1wlmwp9AMAgV8mmQh8AMMhVsqnQBwAMcpVsKvQBAINcJZsKfQDAIFfJpkIfADDIVbKp0AcADHKVbCr0AQCDXCWbCn0AwCBXyaZCHwAwyFWyqdAHAAxylWwq9AEAg1wlmwp9AMAgV8mmQh8AMMhVsqnQBwAMcpVsKvQBAINcJZsKfQDAIFfJpkIfADDIVbKp0AcADHKVbCr0AQCDXCWbCn0AwCBXyaZCHwAwyFWyqdAHAAxylWwq9AEAg1wlmwp9AMAgV8mmQh8AMMhVsqnQBwAMcpVsKvQBAINcJZsKfQDAIFfJpkIfADDIVbKp0AcADHKVbCr0AQCDXCWbCn0AwCBXyaZCHwAwyFWyqdAHAAxylWwq9AEAg1wlmwp9AMAgV8mmQh8AMMhVsqnQBwAMcpVsKvQBAINcJZsKfQDAIFfJpkIfADDIVbKp0AcADHKVbCr0AQCDXCWbCn0AwCBXyaZCHwAwyFWyqbjrg8X3AcBh+Ek2FV99cHX5GYAfi2fO3eKrDwAAKfQBAODsgj4AAGzRBwCAswv6AACwRR8AAM4u6AMAwBZ9AAA4u6APAABb9IF9i/+O6F232WwWfxIhsfhraT2ir2r6wD6e3ym2fwNx8d2ABOfCVupVTR/Yx/M7BX1gCefCFn3gF8/vFPSBJZwLW/SBXzy/U9AHlnAubNEHfvH8TkEfWMK5sEUf+BV9fjetm3ZzwpHXEMT0gSXhubDp3hbZq/Z2m93YJG6SLdIHfkXPgej8dOUjh19dZ+zSB5ak3hv1ZoRKxuyt09ufcDodfeBXvg+0ykemD3B4mT6Y6Vku7IPUJcKoccrRB35lPi/KLGxfn4bLM5sbHLk3eH5JuEL4Zirc1QNcWeMuyn922v5nOJN67aXuFY4cFY3+6ELhcaAP/Mo8v9EX3KiZupGjIwwukezYWPSBJYXXB5k4zs+UvKrLt04fQC///Ebfg7e/FF2h5NUZvkuS98FF7CQs3L1C9IEl+e8fZBZWvxcp6YPUeUcfQK/w+8klaTv9siAz1JTrg5Lx69AHlhR+P7n6+iAzeErhgPQBNPI/Y5dfHs3ozBvwwZHDhakl4Z40/+zNRFfLP4TBJQ36wJKSnzcNZy4KXsCZ82LwfMnsSWrwmV7V9IF9hp/f/BkiQR9YUn0uGHsN0Ad+2X5+M+/LJOgDS+rOhblfY4dHH/jF8zsFfWAJ58IWfeAXz+8U9IElnAtb9IFfPL9T0AeWcC5s0Qd+8fxOQR9YwrmwRR/4dXX5+cObF6hGH5jBuZB/VdMH9m24Tb4t/iRCYunX0bpukeNzQR8AAOgDAMAWfQAAOLugDwAAW/QBAODsgj4AAGzRBwCAswv6AACwRR8AAM4u6AMAwNZ/AD95rXckKyHFAAAAAElFTkSuQmCC" alt="" /></div>点击finish,搞定！运行时拷贝bams.propreties属性文件到同目录，直接运行即可。<br /><br /><br /><br /><br />全路径：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">C:\TEST\JARTEST<br />&#9474;&nbsp;&nbsp;bams.properties<br />&#9474;&nbsp;&nbsp;build.xml<br />&#9474;&nbsp;&nbsp;Info.log<br />&#9474;&nbsp;&nbsp;log4j.properties<br />&#9474;&nbsp;&nbsp;readme.txt<br />&#9474;<br />&#9500;&#9472;</span><span style="color: #000000; ">1.5</span><span style="color: #000000; "><br />&#9474;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bams.properties<br />&#9474;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;build.xml<br />&#9474;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Info.log<br />&#9474;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;parsing.jar<br />&#9474;<br />&#9500;&#9472;build<br />&#9474;&nbsp;&nbsp;&#9500;&#9472;classes<br />&#9474;&nbsp;&nbsp;&#9474;&nbsp;&nbsp;&#9474;&nbsp;&nbsp;log4j.properties<br />&#9474;&nbsp;&nbsp;&#9474;&nbsp;&nbsp;&#9474;<br />&#9474;&nbsp;&nbsp;&#9474;&nbsp;&nbsp;&#9500;&#9472;com<br />&#9474;&nbsp;&nbsp;&#9474;&nbsp;&nbsp;&#9474;&nbsp;&nbsp;&#9492;&#9472;vanceinfo<br />&#9474;&nbsp;&nbsp;&#9474;&nbsp;&nbsp;&#9474;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#9492;&#9472;jvmmem<br />&#9474;&nbsp;&nbsp;&#9474;&nbsp;&nbsp;&#9474;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MessageData.</span><span style="color: #0000FF; ">class</span><span style="color: #000000; "><br />&#9474;&nbsp;&nbsp;&#9474;&nbsp;&nbsp;&#9474;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ParsingLogFile.</span><span style="color: #0000FF; ">class</span><span style="color: #000000; "><br />&#9474;&nbsp;&nbsp;&#9474;&nbsp;&nbsp;&#9474;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ParsingLogFileTest.</span><span style="color: #0000FF; ">class</span><span style="color: #000000; "><br />&#9474;&nbsp;&nbsp;&#9474;&nbsp;&nbsp;&#9474;<br />&#9474;&nbsp;&nbsp;&#9474;&nbsp;&nbsp;&#9500;&#9472;config<br />&#9474;&nbsp;&nbsp;&#9474;&nbsp;&nbsp;&#9474;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;db.properties<br />&#9474;&nbsp;&nbsp;&#9474;&nbsp;&nbsp;&#9474;<br />&#9474;&nbsp;&nbsp;&#9474;&nbsp;&nbsp;&#9492;&#9472;lib<br />&#9474;&nbsp;&nbsp;&#9474;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;junit</span><span style="color: #000000; ">-</span><span style="color: #000000; ">3.8</span><span style="color: #000000; ">.</span><span style="color: #000000; ">1</span><span style="color: #000000; ">.jar<br />&#9474;&nbsp;&nbsp;&#9474;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;junit.jar<br />&#9474;&nbsp;&nbsp;&#9474;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log4j</span><span style="color: #000000; ">-</span><span style="color: #000000; ">1.2</span><span style="color: #000000; ">.</span><span style="color: #000000; ">8</span><span style="color: #000000; ">.jar<br />&#9474;&nbsp;&nbsp;&#9474;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mysql</span><span style="color: #000000; ">-</span><span style="color: #000000; ">connector</span><span style="color: #000000; ">-</span><span style="color: #000000; ">java</span><span style="color: #000000; ">-</span><span style="color: #000000; ">5.0</span><span style="color: #000000; ">.</span><span style="color: #000000; ">8</span><span style="color: #000000; ">-</span><span style="color: #000000; ">bin.j<br />&#9474;&nbsp;&nbsp;&#9474;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ojdbc14.jar<br />&#9474;&nbsp;&nbsp;&#9474;<br />&#9474;&nbsp;&nbsp;&#9492;&#9472;jar<br />&#9474;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bams.properties<br />&#9474;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Info.log<br />&#9474;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;parsing.jar<br />&#9474;<br />&#9500;&#9472;config<br />&#9474;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;db.properties<br />&#9474;<br />&#9500;&#9472;lib<br />&#9474;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;junit</span><span style="color: #000000; ">-</span><span style="color: #000000; ">3.8</span><span style="color: #000000; ">.</span><span style="color: #000000; ">1</span><span style="color: #000000; ">.jar<br />&#9474;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;junit.jar<br />&#9474;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log4j</span><span style="color: #000000; ">-</span><span style="color: #000000; ">1.2</span><span style="color: #000000; ">.</span><span style="color: #000000; ">8</span><span style="color: #000000; ">.jar<br />&#9474;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mysql</span><span style="color: #000000; ">-</span><span style="color: #000000; ">connector</span><span style="color: #000000; ">-</span><span style="color: #000000; ">java</span><span style="color: #000000; ">-</span><span style="color: #000000; ">5.0</span><span style="color: #000000; ">.</span><span style="color: #000000; ">8</span><span style="color: #000000; ">-</span><span style="color: #000000; ">bin.jar<br />&#9474;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ojdbc14.jar<br />&#9474;<br />&#9500;&#9472;src<br />&#9474;&nbsp;&nbsp;&#9492;&#9472;com<br />&#9474;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#9492;&#9472;vanceinfo<br />&#9474;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#9492;&#9472;jvmmem<br />&#9474;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MessageData.java<br />&#9474;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ParsingLogFile.java<br />&#9474;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ParsingLogFileTest.java</span></div><img src ="http://www.blogjava.net/zhb8015/aggbug/385075.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zhb8015/" target="_blank">zhb8015</a> 2012-08-08 15:59 <a href="http://www.blogjava.net/zhb8015/articles/385075.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>TW interview experience(转)</title><link>http://www.blogjava.net/zhb8015/articles/384189.html</link><dc:creator>zhb8015</dc:creator><author>zhb8015</author><pubDate>Fri, 27 Jul 2012 10:48:00 GMT</pubDate><guid>http://www.blogjava.net/zhb8015/articles/384189.html</guid><wfw:comment>http://www.blogjava.net/zhb8015/comments/384189.html</wfw:comment><comments>http://www.blogjava.net/zhb8015/articles/384189.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zhb8015/comments/commentRss/384189.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zhb8015/services/trackbacks/384189.html</trackback:ping><description><![CDATA[<div><strong><em>TW来了</em></strong><br /> &nbsp; &nbsp;&nbsp;&nbsp;12/23 收到了ThoughtWorks的HomeWork,  通知我简历筛选已经过了，发给我三个题目，是写程序的题。要求我从中选择一个作答，在2-3天内上交。能够通过TW的简历的筛选让我喜出望外，对这个公司 的兴趣源于公司名称。思想工作？通过进一步了解，让我对他们平等的组织机构有了了解，于是更增加了一份向往。如今有了这次机会，实在是太幸运了。<br /> <em><strong>做作业:</strong></em><br /> &nbsp;  &nbsp;&nbsp;&nbsp;程序题对输入输出没有要求，从题目说明中示范的输入输出来看，用控制台足以解决问题。但是为了方便以后通过其他的方式输入，接受用户输入的函数由外 边传入一个inputStream即可，这样你用System.in就是控制台输入，用StringBufferInputStream就是从字符串输 入。程序逻辑非常简单，但如何设计的可扩展确实值得下一番功夫的。因为后面的结对编程阶段将会对这份代码提出新的需求，并进行重构。花了一天的时间研究设 计模式，用ArgoUML画了UML图。这里前列推荐一下ArgoUML,这是一个JAVA写的UML工具，界面用的是SWING,跨平台性应该不错。关 键是麻雀虽小，五脏俱全，我原来用过RationalRose,只用了1个小时就基本适应了这个工具。看完设计模式以后，有点模式上瘾的感觉，看到什么都 想套个模式&#8230;&#8230;但是本着循序渐进的原则，我还是先写了一个较为简单的版本，已实现基本功能为目的。只设计了3个类。之后开始着手重构。在一番刻意的设计之 后，决定把原来的工程推倒重做&#8230;&#8230;因为改动实在太大了。状态、命令模式的引入使得类的数量增长到10个，并增加了3-4个接口。设计完之后，感觉自己的程 序像是变形金刚了&#8230;&#8230;甚是满意。于是写测试，写Ant脚本，写文档&#8230;&#8230;经过一番体力劳动，打包上交了。静候消息&#8230;&#8230;<br /> <br /> <em><strong>笔试:</strong></em><br /> &nbsp; &nbsp;&nbsp;  &nbsp;2008年过去了，第二年我终于收到了TW下一阶段的指示。1月6号下午让我去笔试。想了半天觉得也没什么可准备的，因为据说都是推理题。提前半小时来 到了TW在东直门的办公室。在门外观察了一下，很干净，确实是外企的风格。然后就进去了，里边的工作人员问我找谁，我说面试，然后就让我先坐下等着。TW 的办公区分为两大块，整体布局呈哑铃形状。桌子跟网上说的一样，没有隔板，是很自由的大家围着坐的布局。拿着资料看了几分钟，HR的MM就要请我进入了一 间写着'元'的房间，才意识到这里的办公室都是用中国朝代进行标记的.  一起的还有一个研究生，我们聊了聊天，气氛很融洽，也比较放松。之后就是漫长的笔试过程。首先是逻辑测试，在这个过程中还签署了保密协议，要求不能外泄题 目。题目确实还是设计的比较有针对性的，并不是平时见过的那种智力题。我想如果平时写过程序的话，应该能比较好适应里边的思维模式。但要命的是题目全部是 英文描述，尤其是碰到有一堆从句或者修饰语嵌套在一起的时候，让人想暴走&#8230;&#8230;提前10分钟前偶就全部做完了，但是太过自信，就在那里等着，到最后两分钟的 时候想最后检查一下就交。结果连续发现了问题，主要是对于题意的理解&#8230;&#8230;赶忙改完2道题后，卷子就收上去了T_T听后来HRMM说还改错了&#8230;&#8230;之后是英文 的快速反应题，HR说题比较多，时间很短，一般都做不完。反正能多做就多做呗&#8230;&#8230;一共15分钟的时间，这15分钟也比较痛苦，文字推理题换成英文的真是让 我感叹自己的英文水平，连单词都不认识，怎么选则反义词啊&#8230;&#8230;只能蒙！再往后是OpenQuestion,有大概12到题目，要求用英文任意作答。主要考 察综合素质和与公司文化的契合程度。由于当时感觉又疲惫又晕又饿，所以感觉打得并不怎么好，枉费了我的口才了&#8230;&#8230;我比研究生早很多就交了。HR把我单独待 到一房间，问我有什么问题么，我就问了问后边还有什么筛选环节。MM很亲切的告诉我后边如果能继续，还会有结对编程，技术面试，HR主管面试&#8230;&#8230;God  Bless Me，忐忑的回了家。<br /> <br /> &nbsp; &nbsp;&nbsp; &nbsp;本来以为笔试完了  隔一天会进行结对编程，谁知道刚坐车回家就接到HRMM电话说第二天要来结对编程&#8230;&#8230;得了，也没的准备了，改什么样就什么样，是骡子是马拉出去给他们溜 溜。晚上看了看Extreme Programming Cook Book  中的Junit，特别复习了一下Eclipse的快捷键,然后在期待与不安中入睡&#8230;&#8230;。<br /> &nbsp; &nbsp;&nbsp; &nbsp;迎着下午一点的太阳和北京特有的刺骨的寒风，我再次出现在了东直门的国华投资大厦下面。经过HR的介绍，我和一位TW的帅哥开始pair.  我们共用一台Mac  Book,连接一个液晶显示器，两套键盘和鼠标。首先我解释了我的代码，帅哥很认真的听，不时提出几个问题。问题不断深入，考查设计模式的使用，及设计 OO的概念。我对自己这方面还是比较有自信的，回答的也比较流畅。并且在解释的过程中着重的强调了自己对于扩展性的一些基本想法。并自揭老底告诉他有可能 涉及过度了。都怪前一阵看设计模式看得有点着了魔，什么玩意都想往模式上套，一看就是新手，呵呵！之后提出了几个两个新的需求。于是我们讨论了新的设计， 当我着手开始写代码的时候，才发现这Mac的键盘实在是&#8230;&#8230;具然没有Ctrl!  结果Eclipse里的快捷键全不能用了&#8230;&#8230;昨天晚上白准备了。打字的时候尤其不适应，都怪我是土人一个，用Mac键盘写程序，感觉自己的动作像是小脑出 了问题一般。动不动就按错，最后小心翼翼的一个字母一个字母的按&#8230;&#8230;两个需求变更，最终完成了其中的第一个，但对于第二个变更，我跟TWer进行了建设性 的讨论，并交换了意见，但是由于时间所限，最后没来得及完成。在这个过程中，我看到了我设计和开发习惯的种种不足，学到了很多。比如一定要在测试全部通过 之后才能引入新的变化，并且面向对象的概念很重要的就是根据问题域，逻辑来划分对象，应该就是所谓的领域对象的思想。真的非常感谢那位TWer的指导，花 了两个小时帮助我改进代码。<br /> &nbsp; &nbsp;&nbsp; &nbsp;HRMM又出现了，问我还有没有其他的问题，于是我问了问安排，被告知Office  Interview将是Boss战，能否通关拿到Offer在此一举了。临走之前MM说  &#8220;我们讨论之后，如果我想起来，明天就能告诉你pair的结果&#8221;，我赶紧笑着说"那就麻烦您尽量想起来。&#8221;<br /> <br /> &nbsp; &nbsp;&nbsp;&nbsp;总算没有白等。结对编程的结果也还算不错。本以为下一轮很快就会结束，却被告知最后如果想通关，还要进行N连战&#8230;&#8230;这让我想起了玩洛克人的感觉&#8230;&#8230;一关一关有一关。相隔了一周左右。N连战开始了。<br /> &nbsp; &nbsp;&nbsp; &nbsp;早上便来到了ThoughWorks办公室。开始Round1  Presentation。一共8个人。4个人一组开始做。我跟3个MM分在一组。我是最后一个讲的，为了能够更清晰的表示我的意思，我决定用中 文+ppt的形式进行表达(英文水平还不太够)。平时在学校里大大小小的课设和项目也算做了不少，所以对于Presentation我还是比较有信心的。 对于后来HR问我的问题:你认为好Presentation的标准是什么。我的解释是让听众和自己都感觉舒服，并能可取所需。具体的标准可能包括保持目光 接触；虽然有不少人说，演讲的时候把人头当作西瓜，或者朝无限远的地方延伸(这样大家都以为你是在看他)。这两种做法我都试过，效果并不好。我尝试过把人 当西瓜，但是没用，脑袋和西瓜长得实在太不像了，而且关键在于让演讲者害怕的其实不是脑袋，而是嵌在一颗颗西瓜，噢不，是脑袋上的一双双注视你的眼睛。至 于把目光放到无限远，可能人多的时候是比较实用的。但我总觉得这样做会让我感觉眩晕，而且自我感觉很痴呆的样子。我认为保持目光接触，这是最好的办法。随 机得看每个人的眼睛，就像跟同一个人在对话一样。把他们想象成一个人，这样就不会紧张了。<br /> &nbsp; &nbsp;&nbsp; &nbsp;Round2 是协作游戏。8人分两组，每组四人。在沟通受限，时间受限的情况下，齐力完成一项手工。这个环节由多名TWer监视着。考察协作和沟通能力。我感觉我们表现得并不好。大家都有点失望:(<br /> &nbsp; &nbsp;&nbsp;&nbsp;Round3是面谈。迎接我的是Jessie。并没有什么让我觉得特别有压力的问题。交流是在轻松的气氛下进行的。我也坦诚的回答了所有的问题。坦诚是很重要的，该什么样就是什么样，自己轻松，也防止误解。<br /> &nbsp; &nbsp;  3连战就这样结束了。经历了最长的等待（大概一周多），我终于成功了！接到通知电话的时候感觉好像范进中举&#8230;&#8230;虽然找工作的这段时间，不断在痛苦，迷茫， 中徘徊。但是终于能够拿到喜欢的公司的Offer也算是老天对我不薄了。ThoughtWorks真的很不错，从我面试的一开始我就喜欢上了这个公司，平 等，开放，互相尊重。我想这是每一个热爱技术的人都向往的氛围。待遇也还可以，我觉得在这里我应该可以更好的学习技术，更好的享受技术和生活。这也是我选 择ThoughtWorks的原因吧&#8230;&#8230;  <div id="comment_2709098"> </div> <div>1</div></div><img src ="http://www.blogjava.net/zhb8015/aggbug/384189.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zhb8015/" target="_blank">zhb8015</a> 2012-07-27 18:48 <a href="http://www.blogjava.net/zhb8015/articles/384189.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>排序算法（转）</title><link>http://www.blogjava.net/zhb8015/articles/384094.html</link><dc:creator>zhb8015</dc:creator><author>zhb8015</author><pubDate>Thu, 26 Jul 2012 09:31:00 GMT</pubDate><guid>http://www.blogjava.net/zhb8015/articles/384094.html</guid><wfw:comment>http://www.blogjava.net/zhb8015/comments/384094.html</wfw:comment><comments>http://www.blogjava.net/zhb8015/articles/384094.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zhb8015/comments/commentRss/384094.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zhb8015/services/trackbacks/384094.html</trackback:ping><description><![CDATA[原文：<div>http://blog.csdn.net/luosijin123/article/details/4795177</div><br /><br />。并总结成API供大家参考： <div><p><a name="navbar_top"></a>  </p><table style="width: 100%;" border="0" cellpadding="1" cellspacing="0"> <tbody> <tr> <td colspan="2" bgcolor="#eeeeff"><a name="navbar_top_firstrow"></a> <table border="0" cellpadding="0" cellspacing="3"> <tbody> <tr align="center" valign="top"> <td bgcolor="#eeeeff"><a href="http://writeblog.csdn.net/org/luosijin/test/package-summary.html"><strong>软件包</strong></a>&nbsp;</td> <td bgcolor="#ffffff">&nbsp;<strong>类</strong>&nbsp;</td> <td bgcolor="#eeeeff"><a href="http://writeblog.csdn.net/class-use/Sort.html"><strong>使用</strong></a>&nbsp;</td> <td bgcolor="#eeeeff"><a href="http://writeblog.csdn.net/package-tree.html"><strong>树</strong></a>&nbsp;</td> <td bgcolor="#eeeeff"><a href="http://writeblog.csdn.net/deprecated-list.html"><strong>已过时</strong></a>&nbsp;</td> <td bgcolor="#eeeeff"><a href="http://writeblog.csdn.net/index-files/index-1.html"><strong>索引</strong></a>&nbsp;</td> <td bgcolor="#eeeeff"><a href="http://writeblog.csdn.net/help-doc.html"><strong>帮助</strong></a>&nbsp;</td> </tr> </tbody> </table> </td> <td rowspan="3" align="right" valign="top"><em></em><br /></td> </tr> <tr> <td bgcolor="#ffffff">&nbsp;上一个类&nbsp; &nbsp;下一个类</td> <td bgcolor="#ffffff"><span><a href="http://writeblog.csdn.net/index.html?org/luosijin/test/Sort.html" target="_top"><strong>框架</strong></a> &nbsp; &nbsp;<a href="http://writeblog.csdn.net/Sort.html" target="_top"><strong>无框架</strong></a> &nbsp; &nbsp;  </span></td> </tr> <tr> <td valign="top">摘要：&nbsp;嵌套&nbsp;|&nbsp;字段&nbsp;|&nbsp;<a href="http://writeblog.csdn.net/#constructor_summary">构造函数</a>&nbsp;|&nbsp;<a href="http://writeblog.csdn.net/#method_summary">方法</a></td> <td valign="top">详细信息：&nbsp;字段&nbsp;|&nbsp;<a href="http://writeblog.csdn.net/#constructor_detail">构造函数</a>&nbsp;|&nbsp;<a href="http://writeblog.csdn.net/#method_detail">方法</a></td> </tr> </tbody> </table> <a name="skip-navbar_top"></a> <hr />  <h2>org.luosijin.test <br />类 Sort</h2> <pre>java.lang.Object   <strong>org.luosijin.test.Sort</strong> </pre> <hr /> <dl><dt> <pre>public class <strong>Sort</strong><dt>extends java.lang.Object</dt></pre> </dt></dl> <p>Java实现几种常见排序方法:冒泡排序、快速排序、选择排序、插入排序、希尔排序，甚至还有基数排序、鸡尾酒排序、桶排序、鸽巢排序、归并排序等。 </p> <p>&nbsp;</p> <p>&nbsp;</p> <dl><dt><strong>版本：</strong> </dt><dd>V5.0 </dd><dt><strong>作者：</strong> </dt><dd>罗嗣金 </dd></dl> <hr /> <p><a name="constructor_summary"></a> </p><table style="width: 100%;" border="1" cellpadding="3" cellspacing="0"> <tbody> <tr bgcolor="#ccccff"> <th colspan="2" align="left"><span style="font-size: x-small;"><strong>构造函数摘要</strong></span></th> </tr> <tr bgcolor="#ffffff"> <td><code><strong><a href="http://writeblog.csdn.net/org/luosijin/test/Sort.html#Sort%28%29">Sort</a></strong>()</code> <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td> </tr> </tbody> </table> &nbsp; <a name="method_summary"></a> <table style="width: 100%;" border="1" cellpadding="3" cellspacing="0"> <tbody> <tr bgcolor="#ccccff"> <th colspan="2" align="left"><span style="font-size: x-small;"><strong>方法摘要</strong></span></th> </tr> <tr bgcolor="#ffffff"> <td align="right" valign="top" width="1%"><code>static&nbsp;void</code></td> <td><code><strong><a href="http://writeblog.csdn.net/org/luosijin/test/Sort.html#bubbleSort%28int[]%29">bubbleSort</a></strong>(int[]&nbsp;nums)</code> <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;冒泡法排序<br />比较相邻的元素。</td> </tr> <tr bgcolor="#ffffff"> <td align="right" valign="top" width="1%"><code>static&nbsp;void</code></td> <td><code><strong><a href="http://writeblog.csdn.net/org/luosijin/test/Sort.html#insertSort%28int[]%29">insertSort</a></strong>(int[]&nbsp;nums)</code> <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;插入排序<br />从第一个元素开始，该元素可以认为已经被排序 取出下一个元素，在已经排序的元素序列中从后向前扫描 如果该元素（已排序）大于新元素，将该元素移到下一位置 重复步骤3，直到找到已排序的元素小于或者等于新元素的位置 将新元素插入到该位置中 重复步骤2 </td> </tr> <tr bgcolor="#ffffff"> <td align="right" valign="top" width="1%"><code>static&nbsp;void</code></td> <td><code><strong><a href="http://writeblog.csdn.net/org/luosijin/test/Sort.html#merge%28int[],%20int,%20int,%20int%29">merge</a></strong>(int[]&nbsp;data, int&nbsp;p, int&nbsp;q, int&nbsp;r)</code> <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;归并算法实现</td> </tr> <tr bgcolor="#ffffff"> <td align="right" valign="top" width="1%"><code>static&nbsp;void</code></td> <td><code><strong><a href="http://writeblog.csdn.net/org/luosijin/test/Sort.html#mergeSort%28int[],%20int,%20int%29">mergeSort</a></strong>(int[]&nbsp;nums, int&nbsp;left, int&nbsp;right)</code> <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;归并排序<br />申 请空间，使其大小为两个已经排序序列之和，该空间用来存放合并后的序列 设定两个指针，最初位置分别为两个已经排序序列的起始位置  比较两个指针所指向的元素，选择相对小的元素放入到合并空间，并移动指针到下一位置 重复步骤3直到某一指针达到序列尾  将另一序列剩下的所有元素直接复制到合并序列尾 算法参考：<a href="http://www.cnitblog.com/intrl/">Java部落</a></td> </tr> <tr bgcolor="#ffffff"> <td align="right" valign="top" width="1%"><code>static&nbsp;void</code></td> <td><code><strong><a href="http://writeblog.csdn.net/org/luosijin/test/Sort.html#quickSort%28int[],%20int,%20int%29">quickSort</a></strong>(int[]&nbsp;nums, int&nbsp;start, int&nbsp;end)</code> <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;快速排序<br />从数列中挑出一个元素，称为&#8220;基准&#8221; 重新排序数列，所有元素比基准值小的摆放在基准前面，所有元素比基准值大的摆在基准的后面（相同的数可以到任一边）。</td> </tr> <tr bgcolor="#ffffff"> <td align="right" valign="top" width="1%"><code>static&nbsp;void</code></td> <td><code><strong><a href="http://writeblog.csdn.net/org/luosijin/test/Sort.html#selectSort%28int[]%29">selectSort</a></strong>(int[]&nbsp;nums)</code> <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;选择排序<br />在未排序序列中找到最小元素，存放到排序序列的起始位置 再从剩余未排序元素中继续寻找最小元素，然后放到排序序列末尾。</td> </tr> </tbody> </table> &nbsp;<a name="methods_inherited_from_class_java.lang.Object"></a>  <table style="width: 100%;" border="1" cellpadding="3" cellspacing="0"> <tbody> <tr bgcolor="#eeeeff"> <th align="left"><strong>从类 java.lang.Object 继承的方法</strong></th> </tr> <tr bgcolor="#ffffff"> <td><code>equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait</code></td> </tr> </tbody> </table> &nbsp;  <p><a name="constructor_detail"></a> </p><table style="width: 100%;" border="1" cellpadding="3" cellspacing="0"> <tbody> <tr bgcolor="#ccccff"> <th align="left"><span style="font-size: x-small;"><strong>构造函数详细信息</strong></span></th> </tr> </tbody> </table> <a name="Sort()"></a> <h3>Sort</h3> <pre>public <strong>Sort</strong>()</pre>  <p><a name="method_detail"></a> </p><table style="width: 100%;" border="1" cellpadding="3" cellspacing="0"> <tbody> <tr bgcolor="#ccccff"> <th align="left"><span style="font-size: x-small;"><strong>方法详细信息</strong></span></th> </tr> </tbody> </table> <a name="bubbleSort(int[])"></a> <h3>bubbleSort</h3> <pre>public static void <strong>bubbleSort</strong>(int[]&nbsp;nums)</pre> <dl><dd>冒泡法排序<br /> <ul><li>比较相邻的元素。如果第一个比第二个大，就交换他们两个。 </li><li>对每一对相邻元素作同样的工作，从开始第一对到结尾的最后一对。在这一点，最后的元素应该会是最大的数。 </li><li>针对所有的元素重复以上的步骤，除了最后一个。 </li><li>持续每次对越来越少的元素重复上面的步骤，直到没有任何一对数字需要比较。 </li></ul> <p>&nbsp;</p> </dd><dd><dl><dt><strong>参数：</strong> </dt><dd><code>nums</code> - 需要排序的整型数组</dd></dl></dd></dl> <hr /> <p><a name="quickSort(int[], int, int)"></a>" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif"&gt;</p> <h3>quickSort</h3> <pre>public static void <strong>quickSort</strong>(int[]&nbsp;nums,                              int&nbsp;start,                              int&nbsp;end)</pre> <dl><dd>快速排序<br /> <ul><li>从数列中挑出一个元素，称为&#8220;基准&#8221; </li><li>重新排序数列，所有元素比基准值小的摆放在基准前面，所有元素比基准值大的摆在基准的后面（相同的数可以到任一边）。在这个分割之后，该基准是它的最后位置。这个称为分割（partition）操作。 </li><li>递归地把小于基准值元素的子数列和大于基准值元素的子数列排序。 </li></ul> <p>&nbsp;</p> </dd><dd><dl><dt><strong>参数：</strong> </dt><dd><code>nums</code> - </dd><dd><code>start</code> - </dd><dd><code>end</code> - </dd></dl></dd></dl> <hr /> <p><a name="selectSort(int[])"></a></p> <h3>selectSort</h3> <pre>public static void <strong>selectSort</strong>(int[]&nbsp;nums)</pre> <dl><dd>选择排序<br /> <ul><li>在未排序序列中找到最小元素，存放到排序序列的起始位置 </li><li>再从剩余未排序元素中继续寻找最小元素，然后放到排序序列末尾。 </li><li>以此类推，直到所有元素均排序完毕。 </li></ul> <p>&nbsp;</p> </dd><dd><dl><dt><strong>参数：</strong> </dt><dd><code>nums</code> - </dd></dl></dd></dl> <hr /> <p><a name="insertSort(int[])"></a></p> <h3>insertSort</h3> <pre>public static void <strong>insertSort</strong>(int[]&nbsp;nums)</pre> <dl><dd>插入排序<br /> <ul><li>从第一个元素开始，该元素可以认为已经被排序 </li><li>取出下一个元素，在已经排序的元素序列中从后向前扫描 </li><li>如果该元素（已排序）大于新元素，将该元素移到下一位置 </li><li>重复步骤3，直到找到已排序的元素小于或者等于新元素的位置 </li><li>将新元素插入到该位置中 </li><li>重复步骤2 </li></ul> <p>&nbsp;</p> </dd><dd><dl><dt><strong>参数：</strong> </dt><dd><code>nums</code> - </dd></dl></dd></dl> <hr /> <p><a name="mergeSort(int[], int, int)"></a>" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif"&gt;</p> <h3>mergeSort</h3> <pre>public static void <strong>mergeSort</strong>(int[]&nbsp;nums,                              int&nbsp;left,                              int&nbsp;right)</pre> <dl><dd>归并排序<br /> <ul><li>申请空间，使其大小为两个已经排序序列之和，该空间用来存放合并后的序列 </li><li>设定两个指针，最初位置分别为两个已经排序序列的起始位置 </li><li>比较两个指针所指向的元素，选择相对小的元素放入到合并空间，并移动指针到下一位置 </li><li>重复步骤3直到某一指针达到序列尾 </li><li>将另一序列剩下的所有元素直接复制到合并序列尾 </li></ul> 算法参考：<a href="http://www.cnitblog.com/intrl/">Java部落</a> <p>&nbsp;</p> </dd><dd><dl><dt><strong>参数：</strong> </dt><dd><code>nums</code> - </dd><dd><code>left</code> - </dd><dd><code>right</code> - </dd></dl></dd></dl> <hr /> <p><a name="merge(int[], int, int, int)"></a>" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif"&gt;</p> <h3>merge</h3> <pre>public static void <strong>merge</strong>(int[]&nbsp;data,                          int&nbsp;p,                          int&nbsp;q,                          int&nbsp;r)</pre> <dl><dd>归并算法实现 <p>&nbsp;</p> </dd><dd><dl><dt><strong>参数：</strong> </dt><dd><code>data</code> - </dd><dd><code>p</code> - </dd><dd><code>q</code> - </dd><dd><code>r</code> - </dd></dl></dd></dl> <hr /> <p><a name="navbar_bottom"></a> </p>  <table style="width: 100%;" border="0" cellpadding="1" cellspacing="0"><tbody><tr> <td colspan="2" bgcolor="#eeeeff"><a name="navbar_bottom_firstrow"></a> <table border="0" cellpadding="0" cellspacing="3"> <tbody> <tr align="center" valign="top"> <td bgcolor="#eeeeff"><a href="http://writeblog.csdn.net/org/luosijin/test/package-summary.html"><strong>软件包</strong></a>&nbsp;</td> <td bgcolor="#ffffff">&nbsp;<strong>类</strong>&nbsp;</td> <td bgcolor="#eeeeff"><a href="http://writeblog.csdn.net/class-use/Sort.html"><strong>使用</strong></a>&nbsp;</td> <td bgcolor="#eeeeff"><a href="http://writeblog.csdn.net/package-tree.html"><strong>树</strong></a>&nbsp;</td> <td bgcolor="#eeeeff"><a href="http://writeblog.csdn.net/deprecated-list.html"><strong>已过时</strong></a>&nbsp;</td> <td bgcolor="#eeeeff"><a href="http://writeblog.csdn.net/index-files/index-1.html"><strong>索引</strong></a>&nbsp;</td> <td bgcolor="#eeeeff"><a href="http://writeblog.csdn.net/help-doc.html"><strong>帮助</strong></a>&nbsp;</td> </tr> </tbody> </table> </td> <td rowspan="3" align="right" valign="top"><em></em><br /></td> </tr> <tr> <td bgcolor="#ffffff">&nbsp;上一个类&nbsp; &nbsp;下一个类</td> <td bgcolor="#ffffff"><span><a href="http://writeblog.csdn.net/index.html?org/luosijin/test/Sort.html" target="_top"><strong>框架</strong></a> &nbsp; &nbsp;<a href="http://writeblog.csdn.net/Sort.html" target="_top"><strong>无框架</strong></a> &nbsp; &nbsp;  </span></td> </tr> <tr> <td valign="top">摘要：&nbsp;嵌套&nbsp;|&nbsp;字段&nbsp;|&nbsp;<a href="http://writeblog.csdn.net/#constructor_summary">构造函数</a>&nbsp;|&nbsp;<a href="http://writeblog.csdn.net/#method_summary">方法</a></td> <td valign="top">详细信息：&nbsp;字段&nbsp;|&nbsp;<a href="http://writeblog.csdn.net/#constructor_detail">构造函数</a>&nbsp;|&nbsp;<a href="http://writeblog.csdn.net/#method_detail">方法</a></td></tr></tbody></table></div><img src ="http://www.blogjava.net/zhb8015/aggbug/384094.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zhb8015/" target="_blank">zhb8015</a> 2012-07-26 17:31 <a href="http://www.blogjava.net/zhb8015/articles/384094.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>加密算法（转）</title><link>http://www.blogjava.net/zhb8015/articles/384070.html</link><dc:creator>zhb8015</dc:creator><author>zhb8015</author><pubDate>Thu, 26 Jul 2012 07:05:00 GMT</pubDate><guid>http://www.blogjava.net/zhb8015/articles/384070.html</guid><wfw:comment>http://www.blogjava.net/zhb8015/comments/384070.html</wfw:comment><comments>http://www.blogjava.net/zhb8015/articles/384070.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zhb8015/comments/commentRss/384070.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zhb8015/services/trackbacks/384070.html</trackback:ping><description><![CDATA[<div>加密算法分类 ：<br />http://baike.baidu.com/view/7510.htm<br /><br />JDK1.4 JCE 使用方法，介绍的比较详细<br /><div>http://hi.baidu.com/bluewhale84/blog/item/f3bb20a1f538a9884710648c.html#0</div></div><img src ="http://www.blogjava.net/zhb8015/aggbug/384070.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zhb8015/" target="_blank">zhb8015</a> 2012-07-26 15:05 <a href="http://www.blogjava.net/zhb8015/articles/384070.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>软件设计过程一些术语 AN BD FD DD CD CT </title><link>http://www.blogjava.net/zhb8015/articles/383424.html</link><dc:creator>zhb8015</dc:creator><author>zhb8015</author><pubDate>Wed, 18 Jul 2012 10:04:00 GMT</pubDate><guid>http://www.blogjava.net/zhb8015/articles/383424.html</guid><wfw:comment>http://www.blogjava.net/zhb8015/comments/383424.html</wfw:comment><comments>http://www.blogjava.net/zhb8015/articles/383424.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zhb8015/comments/commentRss/383424.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zhb8015/services/trackbacks/383424.html</trackback:ping><description><![CDATA[<div><h3>         <span><a href="http://blog.csdn.net/yuyin86/article/details/7243787">         BD FD DD         </a></span>     </h3>                <div>         <span>         分类：             <a href="http://blog.csdn.net/yuyin86/article/category/737734">c++</a>              <a href="http://blog.csdn.net/yuyin86/article/category/877313">uml</a>          </span>     2012-02-08 22:24     <span title="阅读次数">59人阅读</span>     <span title="评论次数"><a href="http://blog.csdn.net/yuyin86/article/details/7243787#comments">评论</a>(0)</span>     <a title="收藏">收藏</a>     <a href="http://blog.csdn.net/yuyin86/article/details/7243787#report" title="举报">举报</a>      </div>              <div id="app-share-content" style="word-wrap:break-word; border-top-width:1px; border-right-width:1px; border-bottom-width:1px; border-left-width:1px; border-top-style:solid; border-right-style:solid; border-bottom-style:solid; border-left-style:solid; border-top-color:#edf1f4; border-right-color:#edf1f4; border-bottom-color:#edf1f4; border-left-color:#edf1f4; background-color:#ffffff; padding-top:20px; padding-right:20px; padding-bottom:20px; padding-left:20px; color:#9a9a9a; font-size:12px"> <p style="margin-top:0px; margin-right:0px; margin-bottom:1em; margin-left:0px; padding-top:0px; padding-right:0px; padding-bottom:0px; padding-left:0px; color:#6d6d6d; line-height:26px"> N BD FD DD C UT CT TT IT OP&nbsp;<br /> 今天填简历,工程一栏给出这样的选项、网上没有查到准确解释.<br /> 跟朋友讨论了一下,大体上猜测出几个,也有两个不知道何意,如果有知道正解的请不吝赐教!<br /> AN-要求分析<br /> BD-基本设计&nbsp;<br /> FD-结构设计<br /> DD-详细设计<br /> C&nbsp; -编码<br /> UT-单体测试<br /> CT-不知道<br /> TT-结合测试<br /> IT-系统测试<br /> OP-发布<br /> <br /> 以上只是个人理解,像OP这样的纯属猜测...欢迎指摘!<br /> <br /> </p> <div style="word-wrap:break-word"> <div style="word-wrap:break-word"> <div style="word-wrap:break-word"> <h1> &nbsp;</h1> <h1> 软件开发测试过程的一些缩写和解释,感觉不太准确,望补充</h1> <h1> &nbsp;</h1> <h1> 正解 AN BD FD DD CD UT CT TT IT ST UAT OP</h1> <div style="word-wrap:break-word"> <div style="word-wrap:break-word">2011-3-9 15:55</div> 提问者：<a href="http://passport.baidu.com/?business&amp;aid=6&amp;un=lily%5Fdy#2" target="_blank" style="color:#1463c4; text-decoration:none">lily_dy</a>|浏览次数：677次</div> </div> </div> <div style="word-wrap:break-word"> <pre>AN...???                         英文(__) BD...基本设计                 英文(__) FD...结构设计                 英文(__)  DD...详细设计                 英文(__) CD...编码                     英文(Coding) UT...单元测试                 英文(unit testing) CT...组件测试                 英文(Component testing) TT...???                                      英文(__) IT ...集成测试                 英文(integration testing) ST...系统测试                 英文(system testing)   UAT...俗称:验收测试           英文(User acceptance testing) OP...???                                     英文(__)  有哪位高手了解,请帮忙给出正解,谢谢!</pre> </div> </div>  <div style="word-wrap:break-word"> <div style="word-wrap:break-word"> <div style="word-wrap:break-word">2011-3-9 16:11</div> 最佳答案</div> <div style="word-wrap:break-word"> <div style="word-wrap:break-word"> <pre>AN...???                         英文(_Analysis_) BD...基本设计                 英文(_Basic Design_) FD...结构设计                 英文(_Functional Design_)  DD...详细设计                 英文(_Detail Design_) CD...编码                     英文(Coding) UT...单元测试                 英文(unit testing) CT...组件测试                 英文(Component testing) TT...???                                      英文(_Technical Test_) IT ...集成测试                 英文(integration testing) ST...系统测试                 英文(system testing)   UAT...俗称:验收测试           英文(User acceptance testing) OP...???                                     英文(_Operation_)  供参考。</pre> </div> </div> </div> </div></div><img src ="http://www.blogjava.net/zhb8015/aggbug/383424.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zhb8015/" target="_blank">zhb8015</a> 2012-07-18 18:04 <a href="http://www.blogjava.net/zhb8015/articles/383424.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Log4j详细配置（转）</title><link>http://www.blogjava.net/zhb8015/articles/382624.html</link><dc:creator>zhb8015</dc:creator><author>zhb8015</author><pubDate>Mon, 09 Jul 2012 08:57:00 GMT</pubDate><guid>http://www.blogjava.net/zhb8015/articles/382624.html</guid><wfw:comment>http://www.blogjava.net/zhb8015/comments/382624.html</wfw:comment><comments>http://www.blogjava.net/zhb8015/articles/382624.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zhb8015/comments/commentRss/382624.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zhb8015/services/trackbacks/382624.html</trackback:ping><description><![CDATA[<div style="border-bottom-style: none; border-right-style: none; margin: 20px 0px; border-left-style: none; border-top: #ccc 1px dotted; padding-top: 15px" class="blogzz_abstract borderc"><span style="margin-right: 25px"><strong>log4j.appender.CONSOLE.layout.ConversionPattern=[framework] %d - %c -%r [%t] %-10p %c %x - %m%n 
<div style="margin-bottom: 12px" class="blogzz_ainfo">
<div style="widows: 2; text-transform: none; text-indent: 0px; font: 18px 微软雅黑; white-space: normal; orphans: 2; letter-spacing: normal; color: rgb(0,0,0); word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px"><br /></div>
<div style="widows: 2; text-transform: none; text-indent: 0px; font: 18px 微软雅黑; white-space: normal; orphans: 2; letter-spacing: normal; color: rgb(0,0,0); word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">%-10p &nbsp; //'-'左对齐 &nbsp; &nbsp; 10宽度 &nbsp;</div><br />原文地址：</strong><a title="Log4j.properties配置详解" href="http://blog.sina.com.cn/s/blog_56fd58ab0100tcna.html" target="_blank">Log4j.properties配置详解</a></span><span><strong>作者：</strong><a title="大海巨浪" href="http://blog.sina.com.cn/u/1459443883" target="_blank">大海巨浪</a><br /><a href="http://blog.sina.com.cn/s/blog_7774a1fe01013msb.html">http://blog.sina.com.cn/s/blog_7774a1fe01013msb.html</a><br /></span></div>
<div class="blogzz_acon">
<div>一、Log4j简介<br /><br />Log4j有三个主要的组件：Loggers(记录器)，Appenders (输出源)和Layouts(布局)。这里可简单理解为日志类别，日志要输出的地方和日志以何种形式输出。综合使用这三个组件可以轻松地记录信息的类型和级别，并可以在运行时控制日志输出的样式和位置。<br /><br />1、Loggers<br /><br />Loggers组件在此系统中被分为五个级别：DEBUG、INFO、WARN、ERROR和FATAL。这五个级别是有顺序的，DEBUG &lt; INFO &lt; WARN &lt; ERROR &lt; FATAL，分别用来指定这条日志信息的重要程度，明白这一点很重要，Log4j有一个规则：只输出级别不低于设定级别的日志信息，假设Loggers级别设定为INFO，则INFO、WARN、ERROR和FATAL级别的日志信息都会输出，而级别比INFO低的DEBUG则不会输出。<br /><br />2、Appenders<br /><br />禁用和使用日志请求只是Log4j的基本功能，Log4j日志系统还提供许多强大的功能，比如允许把日志输出到不同的地方，如控制台（Console）、文件（Files）等，可以根据天数或者文件大小产生新的文件，可以以流的形式发送到其它地方等等。<br /><br />常使用的类如下：<br /><br />org.apache.log4j.ConsoleAppender（控制台）<br />org.apache.log4j.FileAppender（文件）<br />org.apache.log4j.DailyRollingFileAppender<wbr>（每天产生一个日志文件）<br />org.apache.log4j.RollingFileAppender（文件大小到达指定尺寸的时候产生一个新的文件）<br />org.apache.log4j.WriterAppender（将日志信息以流格式发送到任意指定的地方）<br /><br />配置模式：<br />log4j.appender.appenderName = className<br />log4j.appender.appenderName.Option1 = value1<br />&#8230;<br />log4j.appender.appenderName.OptionN = valueN<br /><br />3、Layouts<br /><br />有时用户希望根据自己的喜好格式化自己的日志输出，Log4j可以在Appenders的后面附加Layouts来完成这个功能。Layouts提供四种日志输出样式，如根据HTML样式、自由指定样式、包含日志级别与信息的样式和包含日志时间、线程、类别等信息的样式。<br /><br />常使用的类如下：<br /><br />org.apache.log4j.HTMLLayout（以HTML表格形式布局）<br />org.apache.log4j.PatternLayout（可以灵活地指定布局模式）<br />org.apache.log4j.SimpleLayout（包含日志信息的级别和信息字符串）<br />org.apache.log4j.TTCCLayout（包含日志产生的时间、线程、类别等信息）<br /><br />配置模式：<br /><br />log4j.appender.appenderName.layout =className<br />log4j.appender.appenderName.layout.Option1 = value1<br />&#8230;<br />log4j.appender.appenderName.layout.OptionN = valueN<br /><br />二、配置详解<br /><br />在实际应用中，要使Log4j在系统中运行须事先设定配置文件。配置文件事实上也就是对Logger、Appender及Layout进行相应设定。Log4j支持两种配置文件格式，一种是XML格式的文件，一种是properties属性文件。下面以properties属性文件为例介绍log4j.properties的配置。<br /><br />1、配置根Logger：<br />log4j.rootLogger = [ level ] , appenderName1, appenderName2, &#8230;<br />log4j.additivity.org.apache=false：表示Logger不会在父Logger的appender里输出，默认为true。<br />level ：设定日志记录的最低级别，可设的值有OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL或者自定义的级别，Log4j建议只使用中间四个级别。通过在这里设定级别，您可以控制应用程序中相应级别的日志信息的开关，比如在这里设定了INFO级别，则应用程序中所有DEBUG级别的日志信息将不会被打印出来。<br />appenderName：就是指定日志信息要输出到哪里。可以同时指定多个输出目的地，用逗号隔开。<br />例如：log4j.rootLogger＝INFO,A1,B2,C3<br /><br />2、配置日志信息输出目的地（appender）：<br />log4j.appender.appenderName = className<br />appenderName：自定义appderName，在log4j.rootLogger设置中使用；<br />className：可设值如下：<br />(1)org.apache.log4j.ConsoleAppender（控制台）<br />(2)org.apache.log4j.FileAppender（文件）<br />(3)org.apache.log4j.DailyRollingFileAppender<wbr>（每天产生一个日志文件）<br />(4)org.apache.log4j.RollingFileAppender（文件大小到达指定尺寸的时候产生一个新的文件）<br />(5)org.apache.log4j.WriterAppender（将日志信息以流格式发送到任意指定的地方）<br />(1)ConsoleAppender选项：<br />Threshold=WARN：指定日志信息的最低输出级别，默认为DEBUG。<br />ImmediateFlush=true：表示所有消息都会被立即输出，设为false则不输出，默认值是true。<br />Target=System.err：默认值是System.out。<br />(2)FileAppender选项：<br />Threshold=WARN：指定日志信息的最低输出级别，默认为DEBUG。<br />ImmediateFlush=true：表示所有消息都会被立即输出，设为false则不输出，默认值是true。<br />Append=false：true表示消息增加到指定文件中，false则将消息覆盖指定的文件内容，默认值是true。<br />File=D:/logs/logging.log4j：指定消息输出到logging.log4j文件中。<br />(3)DailyRollingFileAppender<wbr>选项：<br />Threshold=WARN：指定日志信息的最低输出级别，默认为DEBUG。<br />ImmediateFlush=true：表示所有消息都会被立即输出，设为false则不输出，默认值是true。<br />Append=false：true表示消息增加到指定文件中，false则将消息覆盖指定的文件内容，默认值是true。<br />File=D:/logs/logging.log4j：指定当前消息输出到logging.log4j文件中。<br />DatePattern='.'yyyy-MM：每月滚动一次日志文件，即每月产生一个新的日志文件。当前月的日志文件名为logging.log4j，前一个月的日志文件名为logging.log4j.yyyy-MM。<br />另外，也可以指定按周、天、时、分等来滚动日志文件，对应的格式如下：<br />1)'.'yyyy-MM：每月<br />2)'.'yyyy-ww：每周<br />3)'.'yyyy-MM-dd：每天<br />4)'.'yyyy-MM-dd-a：每天两次<br />5)'.'yyyy-MM-dd-HH：每小时<br />6)'.'yyyy-MM-dd-HH-mm：每分钟<br />(4)RollingFileAppender选项：<br />Threshold=WARN：指定日志信息的最低输出级别，默认为DEBUG。<br />ImmediateFlush=true：表示所有消息都会被立即输出，设为false则不输出，默认值是true。<br />Append=false：true表示消息增加到指定文件中，false则将消息覆盖指定的文件内容，默认值是true。<br />File=D:/logs/logging.log4j：指定消息输出到logging.log4j文件中。<br />MaxFileSize=100KB：后缀可以是KB, MB 或者GB。在日志文件到达该大小时，将会自动滚动，即将原来的内容移到logging.log4j.1文件中。<br />MaxBackupIndex=2：指定可以产生的滚动文件的最大数，例如，设为2则可以产生logging.log4j.1，logging.log4j.2两个滚动文件和一个logging.log4j文件。<br /><br />3、配置日志信息的输出格式（Layout）：<br />log4j.appender.appenderName.layout=className<br />className：可设值如下：<br />(1)org.apache.log4j.HTMLLayout（以HTML表格形式布局）<br />(2)org.apache.log4j.PatternLayout（可以灵活地指定布局模式）<br />(3)org.apache.log4j.SimpleLayout（包含日志信息的级别和信息字符串）<br />(4)org.apache.log4j.TTCCLayout（包含日志产生的时间、线程、类别等等信息）<br />(1)HTMLLayout选项：<br />LocationInfo=true：输出java文件名称和行号，默认值是false。<br />Title=My Logging： 默认值是Log4J Log Messages。<br />(2)PatternLayout选项：<br />ConversionPattern=%m%n：设定以怎样的格式显示消息。<br /><br />格式化符号说明：<br /><br />%p：输出日志信息的优先级，即DEBUG，INFO，WARN，ERROR，FATAL。<br />%d：输出日志时间点的日期或时间，默认格式为ISO8601，也可以在其后指定格式，如：%d{yyyy/MM/dd HH:mm:ss,SSS}。<br />%r：输出自应用程序启动到输出该log信息耗费的毫秒数。<br />%t：输出产生该日志事件的线程名。<br />%l：输出日志事件的发生位置，相当于%c.%M(%F:%L)的组合，包括类全名、方法、文件名以及在代码中的行数。例如：test.TestLog4j.main(TestLog4j.java:10)。<br />%c：输出日志信息所属的类目，通常就是所在类的全名。<br />%M：输出产生日志信息的方法名。<br />%F：输出日志消息产生时所在的文件名称。<br />%L:：输出代码中的行号。<br />%m:：输出代码中指定的具体日志信息。<br />%n：输出一个回车换行符，Windows平台为"rn"，Unix平台为"n"。<br />%x：输出和当前线程相关联的NDC(嵌套诊断环境)，尤其用到像java servlets这样的多客户多线程的应用中。<br />%%：输出一个"%"字符。<br />另外，还可以在%与格式字符之间加上修饰符来控制其最小长度、最大长度、和文本的对齐方式。如：<br />1) c：指定输出category的名称，最小的长度是20，如果category的名称长度小于20的话，默认的情况下右对齐。<br />2)%-20c："-"号表示左对齐。<br />3)%.30c：指定输出category的名称，最大的长度是30，如果category的名称长度大于30的话，就会将左边多出的字符截掉，但小于30的话也不会补空格。<br /><br />附：Log4j比较全面的配置<br /><br />Log4j配置文件实现了输出到控制台、文件、回滚文件、发送日志邮件、输出到数据库日志表、自定义标签等全套功能。<br />log4j.rootLogger=DEBUG,console,dailyFile,im<br />log4j.additivity.org.apache=true<br /># 控制台(console)<br />log4j.appender.console=org.apache.log4j.ConsoleAppender<br />log4j.appender.console.Threshold=DEBUG<br />log4j.appender.console.ImmediateFlush=true<br />log4j.appender.console.Target=System.err<br />log4j.appender.console.layout=org.apache.log4j.PatternLayout<br />log4j.appender.console.layout.ConversionPattern=[%-5p] %d(%r) --&gt; [%t] %l: %m %x %n<br /><br /># 日志文件(logFile)<br />log4j.appender.logFile=org.apache.log4j.FileAppender<br />log4j.appender.logFile.Threshold=DEBUG<br />log4j.appender.logFile.ImmediateFlush=true<br />log4j.appender.logFile.Append=true<br />log4j.appender.logFile.File=D:/logs/log.log4j<br />log4j.appender.logFile.layout=org.apache.log4j.PatternLayout<br />log4j.appender.logFile.layout.ConversionPattern=[%-5p] %d(%r) --&gt; [%t] %l: %m %x %n<br /># 回滚文件(rollingFile)<br />log4j.appender.rollingFile=org.apache.log4j.RollingFileAppender<br />log4j.appender.rollingFile.Threshold=DEBUG<br />log4j.appender.rollingFile.ImmediateFlush=true<br />log4j.appender.rollingFile.Append=true<br />log4j.appender.rollingFile.File=D:/logs/log.log4j<br />log4j.appender.rollingFile.MaxFileSize=200KB<br />log4j.appender.rollingFile.MaxBackupIndex=50<br />log4j.appender.rollingFile.layout=org.apache.log4j.PatternLayout<br />log4j.appender.rollingFile.layout.ConversionPattern=[%-5p] %d(%r) --&gt; [%t] %l: %m %x %n<br /># 定期回滚日志文件(dailyFile)<br />log4j.appender.dailyFile=org.apache.log4j.DailyRollingFileAppender<wbr><br />log4j.appender.dailyFile.Threshold=DEBUG<br />log4j.appender.dailyFile.ImmediateFlush=true<br />log4j.appender.dailyFile.Append=true<br />log4j.appender.dailyFile.File=D:/logs/log.log4j<br />log4j.appender.dailyFile.DatePattern='.'yyyy-MM-dd<br />log4j.appender.dailyFile.layout=org.apache.log4j.PatternLayout<br />log4j.appender.dailyFile.layout.ConversionPattern=[%-5p] %d(%r) --&gt; [%t] %l: %m %x %n<br /># 应用于socket<br />log4j.appender.socket=org.apache.log4j.RollingFileAppender<br />log4j.appender.socket.RemoteHost=localhost<br />log4j.appender.socket.Port=5001<br />log4j.appender.socket.LocationInfo=true<br /># Set up for Log Factor 5<br />log4j.appender.socket.layout=org.apache.log4j.PatternLayout<br />log4j.appender.socket.layout.ConversionPattern=[%-5p] %d(%r) --&gt; [%t] %l: %m %x %n<br /># Log Factor 5 Appender<br />log4j.appender.LF5_APPENDER=org.apache.log4j.lf5.LF5Appender<br />log4j.appender.LF5_APPENDER.MaxNumberOfRecords=2000<br /># 发送日志到指定邮件<br />log4j.appender.mail=org.apache.log4j.net.SMTPAppender<br />log4j.appender.mail.Threshold=FATAL<br />log4j.appender.mail.BufferSize=10<br />log4j.appender.mail.From = xxx@mail.com<br />log4j.appender.mail.SMTPHost=mail.com<br />log4j.appender.mail.Subject=Log4J Message<br />log4j.appender.mail.To= xxx@mail.com<br />log4j.appender.mail.layout=org.apache.log4j.PatternLayout<br />log4j.appender.mail.layout.ConversionPattern=[%-5p] %d(%r) --&gt; [%t] %l: %m %x %n<br /># 应用于数据库<br />log4j.appender.database=org.apache.log4j.jdbc.JDBCAppender<br />log4j.appender.database.URL=jdbc:mysql://localhost:3306/test<br />log4j.appender.database.driver=com.mysql.jdbc.Driver<br />log4j.appender.database.user=root<br />log4j.appender.database.password=<br />log4j.appender.database.sql=INSERT INTO LOG4J (Message) VALUES('=[%-5p] %d(%r) --&gt; [%t] %l: %m %x %n')<br />log4j.appender.database.layout=org.apache.log4j.PatternLayout<br />log4j.appender.database.layout.ConversionPattern=[%-5p] %d(%r) --&gt; [%t] %l: %m %x %n<br /><br /># 自定义Appender<br />log4j.appender.im = net.cybercorlin.util.logger.appender.IMAppender<br />log4j.appender.im.host = mail.cybercorlin.net<br />log4j.appender.im.username = username<br />log4j.appender.im.password = password<br />log4j.appender.im.recipient = corlin@cybercorlin.net<br />log4j.appender.im.layout=org.apache.log4j.PatternLayout<br />log4j.appender.im.layout.ConversionPattern=[%-5p] %d(%r) --&gt; [%t] %l: %m %x %n<br /></div>
<div>&nbsp;<wbr></div>
<div>
<div>
<p><span>log4j</span>的强大功能无可置疑，但实际应用中免不了遇到某个功能需要输出独立的日志文件的情况，怎样才能把所需的内容从原有日志中分离，形成单独的日志文件呢？其实只要在现有的<span>log4j</span>基础上稍加配置即可轻松实现这一功能。</p>
<p style="margin: 0cm 0cm 0pt"><span style="font-size: 12pt">　　先看一个常见的<span>log4j.properties</span>文件，它是在控制台和<span>myweb.log</span>文件中记录日志：</span></p>
<div style="padding-bottom: 1pt; padding-left: 4pt; padding-right: 4pt; padding-top: 1pt">
<p style="padding-bottom: 0cm; margin: 0cm 0cm 0pt; padding-left: 0cm; padding-right: 0cm; padding-top: 0cm"><span style="font-size: 12pt">log4j.rootLogger=DEBUG, stdout, logfile</span></p>
<p style="padding-bottom: 0cm; margin: 0cm 0cm 0pt; padding-left: 0cm; padding-right: 0cm; padding-top: 0cm">&nbsp;<wbr></p>
<p style="padding-bottom: 0cm; margin: 0cm 0cm 0pt; padding-left: 0cm; padding-right: 0cm; padding-top: 0cm"><span style="font-size: 12pt">log4j.category.org.springframework=ERROR</span></p>
<p style="padding-bottom: 0cm; margin: 0cm 0cm 0pt; padding-left: 0cm; padding-right: 0cm; padding-top: 0cm"><span style="font-size: 12pt">log4j.category.org.apache=INFO</span></p>
<p style="padding-bottom: 0cm; margin: 0cm 0cm 0pt; padding-left: 0cm; padding-right: 0cm; padding-top: 0cm">&nbsp;<wbr></p>
<p style="padding-bottom: 0cm; margin: 0cm 0cm 0pt; padding-left: 0cm; padding-right: 0cm; padding-top: 0cm"><span style="font-size: 12pt">log4j.appender.stdout=org.apache.log4j.ConsoleAppender</span></p>
<p style="padding-bottom: 0cm; margin: 0cm 0cm 0pt; padding-left: 0cm; padding-right: 0cm; padding-top: 0cm"><span style="font-size: 12pt">log4j.appender.stdout.layout=org.apache.log4j.PatternLayout</span></p>
<p style="padding-bottom: 0cm; margin: 0cm 0cm 0pt; padding-left: 0cm; padding-right: 0cm; padding-top: 0cm"><span style="font-size: 12pt">log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n</span></p>
<p style="padding-bottom: 0cm; margin: 0cm 0cm 0pt; padding-left: 0cm; padding-right: 0cm; padding-top: 0cm">&nbsp;<wbr></p>
<p style="padding-bottom: 0cm; margin: 0cm 0cm 0pt; padding-left: 0cm; padding-right: 0cm; padding-top: 0cm"><span style="font-size: 12pt">log4j.appender.logfile=org.apache.log4j.RollingFileAppender</span></p>
<p style="padding-bottom: 0cm; margin: 0cm 0cm 0pt; padding-left: 0cm; padding-right: 0cm; padding-top: 0cm"><span style="font-size: 12pt">log4j.appender.logfile.File=${myweb.root}/WEB-INF/log/myweb.log</span></p>
<p style="padding-bottom: 0cm; margin: 0cm 0cm 0pt; padding-left: 0cm; padding-right: 0cm; padding-top: 0cm"><span style="font-size: 12pt">log4j.appender.logfile.MaxFileSize=512KB</span></p>
<p style="padding-bottom: 0cm; margin: 0cm 0cm 0pt; padding-left: 0cm; padding-right: 0cm; padding-top: 0cm"><span style="font-size: 12pt">log4j.appender.logfile.MaxBackupIndex=5</span></p>
<p style="padding-bottom: 0cm; margin: 0cm 0cm 0pt; padding-left: 0cm; padding-right: 0cm; padding-top: 0cm"><span style="font-size: 12pt">log4j.appender.logfile.layout=org.apache.log4j.PatternLayout</span></p>
<p style="padding-bottom: 0cm; margin: 0cm 0cm 0pt; padding-left: 0cm; padding-right: 0cm; padding-top: 0cm"><span style="font-size: 12pt">log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n</span></p></div>
<p style="margin: 0cm 0cm 0pt"><span style="font-size: 12pt">　　</span></p>
<p style="text-indent: 24pt; margin: 0cm 0cm 0pt"><span style="font-size: 12pt">如果想对不同的类输出不同的文件<span>(</span>以<span>cn.com.Test</span>为例<span>)</span>，先要在<span>Test.java</span>中定义<span>:</span></span></p>
<div style="padding-bottom: 1pt; padding-left: 4pt; padding-right: 4pt; padding-top: 1pt">
<p style="padding-bottom: 0cm; margin: 0cm 0cm 0pt; padding-left: 0cm; padding-right: 0cm; padding-top: 0cm"><span style="font-size: 12pt">private static Log logger = LogFactory.getLog(<span style="color: #ff0000">Test.class</span>);</span></p></div>
<p style="margin: 0cm 0cm 0pt"><span style="font-size: 12pt">　　然后在<span>log4j.properties</span>中加入<span>:</span></span></p>
<div style="padding-bottom: 1pt; padding-left: 4pt; padding-right: 4pt; padding-top: 1pt">
<p style="padding-bottom: 0cm; margin: 0cm 0cm 0pt; padding-left: 0cm; padding-right: 0cm; padding-top: 0cm"><span style="font-size: 12pt">log4j.logger.<span style="color: #ff0000">cn.com.Test</span>= DEBUG, <span style="color: #0000ff">test</span></span></p>
<p style="padding-bottom: 0cm; margin: 0cm 0cm 0pt; padding-left: 0cm; padding-right: 0cm; padding-top: 0cm"><span style="font-size: 12pt">log4j.appender.<span style="color: #0000ff">test</span>=org.apache.log4j.FileAppender</span></p>
<p style="padding-bottom: 0cm; margin: 0cm 0cm 0pt; padding-left: 0cm; padding-right: 0cm; padding-top: 0cm"><span style="font-size: 12pt">log4j.appender.<span style="color: #0000ff">test</span>.File=${myweb.root}/WEB-INF/log/<strong>test.log</strong></span></p>
<p style="padding-bottom: 0cm; margin: 0cm 0cm 0pt; padding-left: 0cm; padding-right: 0cm; padding-top: 0cm"><span style="font-size: 12pt">log4j.appender.<span style="color: #0000ff">test</span>.layout=org.apache.log4j.PatternLayout</span></p>
<p style="padding-bottom: 0cm; margin: 0cm 0cm 0pt; padding-left: 0cm; padding-right: 0cm; padding-top: 0cm"><span style="font-size: 12pt">log4j.appender.<span style="color: #0000ff">test</span>.layout.ConversionPattern=%d %p [%c] - %m%n</span></p></div>
<p style="margin: 0cm 0cm 0pt"><span style="font-size: 12pt">　　也就是让<span style="color: #ff0000">cn.com.Test</span>中的<span>logger</span>使用<span>log4j.appender.<span style="color: #0000ff">test</span></span>所做的配置。</span></p>
<p style="margin: 0cm 0cm 0pt">&nbsp;<wbr></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-size: 12pt">　　但是，如果在同一类中需要输出多个日志文件呢？其实道理是一样的，先在<span>Test.java</span>中定义<span>:</span></span></p>
<div style="padding-bottom: 1pt; padding-left: 4pt; padding-right: 4pt; padding-top: 1pt">
<p style="padding-bottom: 0cm; margin: 0cm 0cm 0pt; padding-left: 0cm; padding-right: 0cm; padding-top: 0cm"><span style="font-size: 12pt">private static Log logger1 = LogFactory.getLog("<span style="color: #ff0000">myTest1</span>");</span></p>
<p style="padding-bottom: 0cm; margin: 0cm 0cm 0pt; padding-left: 0cm; padding-right: 0cm; padding-top: 0cm"><span style="font-size: 12pt">private static Log logger2 = LogFactory.getLog("<span style="color: #ff0000">myTest2</span>");</span></p></div>
<p style="margin: 0cm 0cm 0pt"><span style="font-size: 12pt">　　然后在<span>log4j.properties</span>中加入<span>:</span></span></p>
<div style="padding-bottom: 1pt; padding-left: 4pt; padding-right: 4pt; padding-top: 1pt">
<p style="padding-bottom: 0cm; margin: 0cm 0cm 0pt; padding-left: 0cm; padding-right: 0cm; padding-top: 0cm"><span style="font-size: 12pt">log4j.logger.<span style="color: #ff0000">myTest1</span>= DEBUG, <span style="color: #0000ff">test1</span></span></p>
<p style="padding-bottom: 0cm; margin: 0cm 0cm 0pt; padding-left: 0cm; padding-right: 0cm; padding-top: 0cm"><span style="font-size: 12pt">log4j.appender.<span style="color: #0000ff">test1</span>=org.apache.log4j.FileAppender</span></p>
<p style="padding-bottom: 0cm; margin: 0cm 0cm 0pt; padding-left: 0cm; padding-right: 0cm; padding-top: 0cm"><span style="font-size: 12pt">log4j.appender.<span style="color: #0000ff">test1</span>.File=${myweb.root}/WEB-INF/log/<strong>test1.log</strong></span></p>
<p style="padding-bottom: 0cm; margin: 0cm 0cm 0pt; padding-left: 0cm; padding-right: 0cm; padding-top: 0cm"><span style="font-size: 12pt">log4j.appender.<span style="color: #0000ff">test1</span>.layout=org.apache.log4j.PatternLayout</span></p>
<p style="padding-bottom: 0cm; margin: 0cm 0cm 0pt; padding-left: 0cm; padding-right: 0cm; padding-top: 0cm"><span style="font-size: 12pt">log4j.appender.<span style="color: #0000ff">test1</span>.layout.ConversionPattern=%d %p [%c] - %m%n</span></p>
<p style="padding-bottom: 0cm; margin: 0cm 0cm 0pt; padding-left: 0cm; padding-right: 0cm; padding-top: 0cm"><span style="font-size: 12pt">　　</span></p>
<p style="padding-bottom: 0cm; margin: 0cm 0cm 0pt; padding-left: 0cm; padding-right: 0cm; padding-top: 0cm"><span style="font-size: 12pt">log4j.logger.<span style="color: #ff0000">myTest2</span>= DEBUG, <span style="color: #0000ff">test2</span></span></p>
<p style="padding-bottom: 0cm; margin: 0cm 0cm 0pt; padding-left: 0cm; padding-right: 0cm; padding-top: 0cm"><span style="font-size: 12pt">log4j.appender.<span style="color: #0000ff">test2</span>=org.apache.log4j.FileAppender</span></p>
<p style="padding-bottom: 0cm; margin: 0cm 0cm 0pt; padding-left: 0cm; padding-right: 0cm; padding-top: 0cm"><span style="font-size: 12pt">log4j.appender.<span style="color: #0000ff">test2</span>.File=${myweb.root}/WEB-INF/log/<strong>test2.log</strong></span></p>
<p style="padding-bottom: 0cm; margin: 0cm 0cm 0pt; padding-left: 0cm; padding-right: 0cm; padding-top: 0cm"><span style="font-size: 12pt">log4j.appender.<span style="color: #0000ff">test2</span>.layout=org.apache.log4j.PatternLayout</span></p>
<p style="padding-bottom: 0cm; margin: 0cm 0cm 0pt; padding-left: 0cm; padding-right: 0cm; padding-top: 0cm"><span style="font-size: 12pt">log4j.appender.<span style="color: #0000ff">test2</span>.layout.ConversionPattern=%d %p [%c] - %m%n</span></p></div>
<p style="margin: 0cm 0cm 0pt"><span style="font-size: 12pt">　　也就是在用<span>logger</span>时给它一个自定义的名字<span>(</span>如这里的<span>"<span style="color: #ff0000">myTest1</span>")</span>，然后在<span>log4j.properties</span>中做出相应配置即可。别忘了不同日志要使用不同的<span>logger(</span>如输出到<strong><span>test1.log</span></strong>的要用<strong><span>logger1</span></strong><span>.info("abc"))</span>。</span></p>
<p style="margin: 0cm 0cm 0pt">&nbsp;<wbr></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-size: 12pt">　　还有一个问题，就是这些自定义的日志默认是同时输出到<span>log4j.rootLogger</span>所配置的日志中的，如何能只让它们输出到自己指定的日志中呢？别急，这里有个开关：</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-size: 12pt">log4j.<strong>additivity</strong>.<span style="color: #ff0000">myTest1</span> = false</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-size: 12pt">　　它用来设置是否同时输出到<span>log4j.rootLogger</span>所配置的日志中，设为<span>false</span>就不会输出到其它地方啦！注意这里的<span>"<span style="color: #ff0000">myTest1</span>"</span>是你在程序中给<span>logger</span>起的那个自定义的名字！</span></p>
<p style="text-indent: 24pt; margin: 0cm 0cm 0pt"><span style="font-size: 12pt">如果你说，我只是不想同时输出这个日志到<span>log4j.rootLogger</span>所配置的<span>logfile</span>中，<span>stdout</span>里我还想同时输出呢！那也好办，把你的<span>log4j.logger.myTest1 = DEBUG, test1</span>改为下式就<span>OK</span>啦！</span></p>
<div style="padding-bottom: 1pt; padding-left: 4pt; padding-right: 4pt; padding-top: 1pt">
<p style="padding-bottom: 0cm; text-indent: 24pt; margin: 0cm 0cm 0pt; padding-left: 0cm; padding-right: 0cm; padding-top: 0cm"><span style="font-size: 12pt">log4j.logger.<span style="color: #ff0000">myTest1</span>=DEBUG, test1</span></p></div><br />参考：<br /><a href="http://www.cnblogs.com/ITEagle/archive/2010/04/23/1718365.html">http://www.cnblogs.com/ITEagle/archive/2010/04/23/1718365.html</a></div></div></div></div><img src ="http://www.blogjava.net/zhb8015/aggbug/382624.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zhb8015/" target="_blank">zhb8015</a> 2012-07-09 16:57 <a href="http://www.blogjava.net/zhb8015/articles/382624.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>log4j详解</title><link>http://www.blogjava.net/zhb8015/articles/382004.html</link><dc:creator>zhb8015</dc:creator><author>zhb8015</author><pubDate>Mon, 02 Jul 2012 09:32:00 GMT</pubDate><guid>http://www.blogjava.net/zhb8015/articles/382004.html</guid><wfw:comment>http://www.blogjava.net/zhb8015/comments/382004.html</wfw:comment><comments>http://www.blogjava.net/zhb8015/articles/382004.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zhb8015/comments/commentRss/382004.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zhb8015/services/trackbacks/382004.html</trackback:ping><description><![CDATA[<div><p><span style="font-size: x-small; font-family: Arial;">Log4J的配置文件(Configuration File)就是用来设置记录器的级别、存放器和布局的，它可接key=value格式的设置或xml格式的设置信息。通过配置，可以创建出Log4J的运行环境。</span></p> <p><strong>1. 配置文件</strong><br />Log4J配置文件的基本格式如下： </p> <div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: #eeeeee;"><span style="font-size: x-small; font-family: Arial;"><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="font-family: Arial;"><span style="font-size: x-small;"><span style="color: #000000;">#配置根Logger<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" />log4j.rootLogger&nbsp;</span> <span style="color: #000000;">=</span> &nbsp; <span style="font-weight: bold; color: #800000;">[</span> <span style="color: #800000;">level</span> <span style="font-weight: bold; color: #800000;">]</span> &nbsp; <span style="color: #000000;">,</span> <span style="color: #000000;">&nbsp;appenderName1</span> <span style="color: #000000;">,</span> <span style="color: #000000;">&nbsp;appenderName2</span> <span style="color: #000000;">,</span> </span></span><span style="font-family: Arial;"><span style="font-size: x-small;"><span style="color: #000000;">&nbsp;&#8230;<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" /><br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" />#配置日志信息输出目的地Appender<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" />log4j.appender.appenderName&nbsp;</span> <span style="color: #000000;">=</span> </span></span><span style="font-family: Arial;"><span style="font-size: x-small;"><span style="color: #000000;">&nbsp;fully.qualified.name.of.appender.class&nbsp;<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" />　　log4j.appender.appenderName.option1&nbsp;</span> <span style="color: #000000;">=</span> </span></span><span style="font-family: Arial;"><span style="font-size: x-small;"><span style="color: #000000;">&nbsp;value1&nbsp;<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" />　　&#8230;&nbsp;<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" />　　log4j.appender.appenderName.optionN&nbsp;</span> <span style="color: #000000;">=</span> </span></span><span style="font-family: Arial;"><span style="font-size: x-small;"><span style="color: #000000;">&nbsp;valueN&nbsp;<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" /><br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" />#配置日志信息的格式（布局）<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" />log4j.appender.appenderName.layout&nbsp;</span> <span style="color: #000000;">=</span> </span></span><span style="font-family: Arial;"><span style="font-size: x-small;"><span style="color: #000000;">&nbsp;fully.qualified.name.of.layout.class&nbsp;<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" />　　log4j.appender.appenderName.layout.option1&nbsp;</span> <span style="color: #000000;">=</span> </span></span><span style="font-family: Arial;"><span style="font-size: x-small;"><span style="color: #000000;">&nbsp;value1&nbsp;<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" />　　&#8230;&nbsp;<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" />　　log4j.appender.appenderName.layout.optionN&nbsp;</span> <span style="color: #000000;">=</span> <span style="color: #000000;">&nbsp;valueN&nbsp;</span> </span></span></div> <p><br /><span style="font-size: x-small; font-family: Arial;">其中 <strong>[level] </strong>是日志输出级别，共有5级：<br /></span></p> <div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: #eeeeee;"><span style="font-size: x-small; font-family: Arial;"><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" /><span style="color: #000000;">FATAL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>&nbsp; <span style="color: #000000;">0</span> </span><span style="font-family: Arial;"><span style="font-size: x-small;"><span style="color: #000000;">&nbsp;<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" />ERROR&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="color: #000000;">3</span> </span></span><span style="font-family: Arial;"><span style="font-size: x-small;"><span style="color: #000000;">&nbsp;<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" />WARN&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="color: #000000;">4</span> </span></span><span style="font-family: Arial;"><span style="font-size: x-small;"><span style="color: #000000;">&nbsp;<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" />INFO&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>&nbsp;&nbsp; <span style="color: #000000;">6</span> </span></span><span style="font-family: Arial;"><span style="font-size: x-small;"><span style="color: #000000;">&nbsp;<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" />DEBUG&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="color: #000000;">7</span> </span></span><span style="color: #000000;"><br /><span style="font-size: x-small; font-family: Arial;"><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" /> </span></span></div> <br /><span style="font-size: x-small; font-family: Arial;">Appender </span><span style="font-size: x-small; font-family: Arial;">为日志输出目的地，Log4j提供的appender有以下几种：<br /></span> <div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: #eeeeee;"><span style="font-size: x-small; font-family: Arial;"><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #000000;"><span style="font-size: x-small; font-family: Arial;">org.apache.log4j.ConsoleAppender（控制台），<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" />org.apache.log4j.FileAppender（文件），<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" />org.apache.log4j.DailyRollingFileAppender（每天产生一个日志文件），<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" />org.apache.log4j.RollingFileAppender（文件大小到达指定尺寸的时候产生一个新的文件），<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" />org.apache.log4j.WriterAppender（将日志信息以流格式发送到任意指定的地方） </span></span></div> <br /><span style="font-family: Arial;"><span style="font-size: x-small;"><strong>Layout</strong>：日志输出格式，Log4j提供的layout有以下几种：<br /></span></span> <div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: #eeeeee;"><span style="font-size: x-small; font-family: Arial;"><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #000000;"><span style="font-size: x-small; font-family: Arial;">org.apache.log4j.HTMLLayout（以HTML表格形式布局），<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" />org.apache.log4j.PatternLayout（可以灵活地指定布局模式），<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" />org.apache.log4j.SimpleLayout（包含日志信息的级别和信息字符串），<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" />org.apache.log4j.TTCCLayout（包含日志产生的时间、线程、类别等等信息） </span></span></div> <p><br /><span style="font-family: Arial;"><span style="font-size: x-small;"><strong>打印参数: </strong>Log4J采用类似C语言中的printf函数的打印格式格式化日志信息，如下:<br /></span></span></p> <div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: #eeeeee;"><span style="font-size: x-small; font-family: Arial;"><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" /> </span><span style="font-family: Arial;"><span style="font-size: x-small;"><span style="color: #000000;">　&nbsp; <strong>%m</strong>&nbsp;&nbsp; 输出代码中指定的消息<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" />　　<strong>%p</strong>&nbsp;&nbsp; 输出优先级，即DEBUG，INFO，WARN，ERROR，FATAL&nbsp;<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" />　　<strong>%r</strong>&nbsp;&nbsp; 输出自应用启动到输出该log信息耗费的毫秒数&nbsp;<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" />　　<strong>%c</strong>&nbsp;&nbsp; 输出所属的类目，通常就是所在类的全名&nbsp;<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" />　　<strong>%t</strong>&nbsp;&nbsp; 输出产生该日志事件的线程名&nbsp;<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" />　　<strong>%n&nbsp;</strong>&nbsp; 输出一个回车换行符，Windows平台为&#8220;\r\n&#8221;，Unix平台为&#8220;\n&#8221;&nbsp;<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" />　　<strong>%d</strong>&nbsp;&nbsp; 输出日志时间点的日期或时间，默认格式为ISO8601，也可以在其后指定格式，比如：%d{yyy&nbsp;MMM&nbsp;dd&nbsp;HH:mm:ss</span> <span style="color: #000000;">,</span> <span style="color: #000000;">SSS}，输出类似：2002年10月18日&nbsp;</span> <span style="color: #000000;">22</span> <span style="color: #000000;">：</span> <span style="color: #000000;">10</span> <span style="color: #000000;">：</span> <span style="color: #000000;">28</span> <span style="color: #000000;">，</span> <span style="color: #000000;">921</span> </span></span><span style="font-family: Arial;"><span style="font-size: x-small;"><span style="color: #000000;">&nbsp;<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" />　　<strong>%l&nbsp;</strong>&nbsp; 输出日志事件的发生位置，包括类目名、发生的线程，以及在代码中的行数。举例：Testlog4.main(TestLog4.java:</span> <span style="color: #000000;">10</span> <span style="color: #000000;">)&nbsp;<img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" /></span> </span></span></div> <p><br /><span style="font-family: Arial;"><span style="font-size: x-small;"><strong>2. 在代码中初始化Logger:</strong> <br />1）在程序中调用<strong>BasicConfigurator.configure()</strong>方法：给根记录器增加一个ConsoleAppender，输出格式通过PatternLayout设为<strong>"%-4r [%t] %-5p %c %x - %m%n"</strong>，还有根记录器的默认级别是<strong>Level.DEBUG</strong>. <br />2）配置放在文件里，通过命令行参数传递文件名字，通过<strong>PropertyConfigurator.configure(args[x])</strong>解析并配置；<br />3）配置放在文件里，通过环境变量传递文件名等信息，利用log4j默认的初始化过程解析并配置；<br />4）配置放在文件里，通过应用服务器配置传递文件名等信息，利用一个特殊的servlet来完成配置。</span></span></p> <p><strong>3. 为不同的 Appender 设置日志输出级别：</strong><br />当调试系统时，我们往往注意的只是异常级别的日志输出，但是通常所有级别的输出都是放在一个文件里的，如果日志输出的级别是BUG！？那就慢慢去找吧。<br />这时我们也许会想要是能把异常信息单独输出到一个文件里该多好啊。当然可以，Log4j已经提供了这样的功能，我们只需要在配置中修改<strong>Appender</strong>的<span style="color: #990000;"><strong>Threshold</strong></span> <span style="color: #000000;"><span style="font-size: x-small; font-family: Arial;">就能实现,比如下面的例子：</span></span></p> <p><strong>[配置文件]</strong></p> <div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: #eeeeee;"><span style="font-size: x-small; font-family: Arial;"><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" /> </span><span style="font-family: Arial;"><span style="font-size: x-small;"><span style="color: #000000;">###&nbsp;set&nbsp;log&nbsp;levels&nbsp;###<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" />log4j.rootLogger</span> <span style="color: #000000;">=</span> <span style="color: #000000;">debug</span> <span style="color: #000000;">,</span> <span style="color: #000000;">&nbsp;stdout</span> <span style="color: #000000;">,</span> <span style="color: #000000;">&nbsp;D</span> <span style="color: #000000;">,</span> </span></span><span style="font-family: Arial;"><span style="font-size: x-small;"><span style="color: #000000;">&nbsp;E<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" /><br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" />###&nbsp;输出到控制台&nbsp;###<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" />log4j.appender.stdout</span> <span style="color: #000000;">=</span> </span></span><span style="font-family: Arial;"><span style="font-size: x-small;"><span style="color: #000000;">org.apache.log4j.ConsoleAppender<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" />log4j.appender.stdout.Target</span> <span style="color: #000000;">=</span> </span></span><span style="font-family: Arial;"><span style="font-size: x-small;"><span style="color: #000000;">System.out<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" />log4j.appender.stdout.layout</span> <span style="color: #000000;">=</span> </span></span><span style="font-family: Arial;"><span style="font-size: x-small;"><span style="color: #000000;">org.apache.log4j.PatternLayout<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" />log4j.appender.stdout.layout.ConversionPattern</span> <span style="color: #000000;">=</span> <span style="color: #000000;">&nbsp;%d{ABSOLUTE}&nbsp;%5p&nbsp;%c{</span> <span style="color: #000000;">1</span> </span></span><span style="font-family: Arial;"><span style="font-size: x-small;"><span style="color: #000000;">}:%L&nbsp;-&nbsp;%m%n<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" /><br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" />###&nbsp;输出到日志文件&nbsp;###<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" />log4j.appender.D</span> <span style="color: #000000;">=</span> </span></span><span style="font-family: Arial;"><span style="font-size: x-small;"><span style="color: #000000;">org.apache.log4j.DailyRollingFileAppender<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" />log4j.appender.D.File</span> <span style="color: #000000;">=</span> </span></span><span style="font-family: Arial;"><span style="font-size: x-small;"><span style="color: #000000;">logs/log.log<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" />log4j.appender.D.Append</span> <span style="color: #000000;">=</span> </span></span><span style="font-family: Arial;"><span style="font-size: x-small;"><span style="color: #000000;">true<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" />log4j.appender.D.<strong><span style="color: #990000;">Threshold</span></strong></span> <span style="color: #000000;">=</span> </span></span><span style="font-family: Arial;"><span style="font-size: x-small;"><span style="color: #000000;">DEBUG&nbsp;<strong>##&nbsp;输出DEBUG级别以上的日志</strong><br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" />log4j.appender.D.layout</span> <span style="color: #000000;">=</span> </span></span><span style="font-family: Arial;"><span style="font-size: x-small;"><span style="color: #000000;">org.apache.log4j.PatternLayout<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" />log4j.appender.D.layout.ConversionPattern</span> <span style="color: #000000;">=</span> <span style="color: #000000;">%-d{yyyy-MM-dd&nbsp;HH:mm:ss}&nbsp;</span> <span style="font-weight: bold; color: #800000;">[</span> <span style="color: #800000;">%t:%r</span> <span style="font-weight: bold; color: #800000;">]</span> <span style="color: #000000;">-</span> <span style="font-weight: bold; color: #800000;">[</span> <span style="color: #800000;">%p</span> <span style="font-weight: bold; color: #800000;">]</span> </span></span><span style="font-family: Arial;"><span style="font-size: x-small;"><span style="color: #000000;">&nbsp;%m%n<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" /><br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" />###&nbsp;保存异常信息到单独文件&nbsp;###<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" />log4j.appender.D</span> <span style="color: #000000;">=</span> </span></span><span style="font-family: Arial;"><span style="font-size: x-small;"><span style="color: #000000;">org.apache.log4j.DailyRollingFileAppender<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" />log4j.appender.D.File</span> <span style="color: #000000;">=</span> </span></span><span style="font-family: Arial;"><span style="font-size: x-small;"><span style="color: #000000;">logs/error.log&nbsp;##&nbsp;异常日志文件名<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" />log4j.appender.D.Append</span> <span style="color: #000000;">=</span> </span></span><span style="font-family: Arial;"><span style="font-size: x-small;"><span style="color: #000000;">true<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" />log4j.appender.D.<strong><span style="color: #990000;">Threshold</span></strong></span> <span style="color: #000000;">=</span> </span></span><span style="font-family: Arial;"><span style="font-size: x-small;"><span style="color: #000000;">ERROR<strong>&nbsp;##&nbsp;只输出ERROR级别以上的日志!!!<br /></strong><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" />log4j.appender.D.layout</span> <span style="color: #000000;">=</span> </span></span><span style="font-family: Arial;"><span style="font-size: x-small;"><span style="color: #000000;">org.apache.log4j.PatternLayout<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/None.gif" align="top"  alt="" />log4j.appender.D.layout.ConversionPattern</span> <span style="color: #000000;">=</span> <span style="color: #000000;">%-d{yyyy-MM-dd&nbsp;HH:mm:ss}&nbsp;</span> <span style="font-weight: bold; color: #800000;">[</span> <span style="color: #800000;">%t:%r</span> <span style="font-weight: bold; color: #800000;">]</span> <span style="color: #000000;">-</span> <span style="font-weight: bold; color: #800000;">[</span> <span style="color: #800000;">%p</span> <span style="font-weight: bold; color: #800000;">]</span> <span style="color: #000000;">&nbsp;%m%n</span> </span></span></div> <br /><span style="font-family: Arial;"><span style="font-size: x-small;"><strong>[代码中使用]</strong> <br /></span></span> <div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: #eeeeee;"><span style="font-family: Arial;"><span style="font-size: x-small;"><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/ExpandedBlockStart.gif" align="top"  alt="" />  <span style="color: #0000ff;">public</span> &nbsp; <span style="color: #0000ff;">class</span> <span style="color: #000000;">&nbsp;TestLog4j&nbsp;</span> </span></span><span style="font-family: Arial;"><span style="font-size: x-small;"><span style="color: #000000;">{<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #0000ff;">public</span> &nbsp; <span style="color: #0000ff;">static</span> &nbsp; <span style="color: #0000ff;">void</span> <span style="color: #000000;">&nbsp;main(String[]&nbsp;args)&nbsp;</span> </span></span><span style="font-family: Arial;"><span style="font-size: x-small;"><span style="color: #000000;">{<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PropertyConfigurator.configure( <span style="color: #000000;">"</span> <span style="color: #000000;">D:/Co<wbr>de/conf/log4j.properties</span> <span style="color: #000000;">"</span> </span></span><span style="font-family: Arial;"><span style="font-size: x-small;"><span style="color: #000000;">);<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Logger&nbsp;logger&nbsp;</span> <span style="color: #000000;">=</span> <span style="color: #000000;">&nbsp;Logger.getLogger(TestLog4j.</span> <span style="color: #0000ff;">class</span> </span></span><span style="font-family: Arial;"><span style="font-size: x-small;"><span style="color: #000000;">);<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.debug(</span> <span style="color: #000000;">"</span> <span style="color: #000000;">debug</span> <span style="color: #000000;">"</span> </span></span><span style="font-family: Arial;"><span style="font-size: x-small;"><span style="color: #000000;">);<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.error(</span> <span style="color: #000000;">"</span> <span style="color: #000000;">error</span> <span style="color: #000000;">"</span> </span></span><span style="color: #000000;"><span style="font-size: x-small; font-family: Arial;">);<br /><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;}</span> </span></span><span style="color: #000000;"><br /><span style="font-size: x-small; font-family: Arial;"><img title="log4j配置详解 - stone - stonexmx 的博客" src="../../Images/OutliningIndicators/ExpandedBlockEnd.gif" align="top"  alt="" />}</span> </span></span></div> <p><br /><span style="font-size: x-small; font-family: Arial;">运行一下，看看异常信息是不是保存在了一个单独的文件error.log中</span></p> <p style="color: #1f73c1;"><span style="font-size: small;"><span style="color: #285cb8; font-family: courier new,courier;">log4j.properties 使用<br />一.参数意义说明<br />输出级别的种类<br />ERROR、WARN、INFO、DEBUG<br />ERROR 为严重错误 主要是程序的错误<br />WARN 为一般警告，比如session丢失<br />INFO 为一般要显示的信息，比如登录登出<br />DEBUG 为程序的调试信息<br />配置日志信息输出目的地<br />log4j.appender.appenderName = fully.qualified.name.of.appender.class<br />1.org.apache.log4j.ConsoleAppender（控制台）<br />2.org.apache.log4j.FileAppender（文件）<br />3.org.apache.log4j.DailyRollingFileAppender（每天产生一个日志文件）<br />4.org.apache.log4j.RollingFileAppender（文件大小到达指定尺寸的时候产生一个新的文件）<br />5.org.apache.log4j.WriterAppender（将日志信息以流格式发送到任意指定的地方）<br />配置日志信息的格式<br />log4j.appender.appenderName.layout = fully.qualified.name.of.layout.class<br />1.org.apache.log4j.HTMLLayout（以HTML表格形式布局），<br />2.org.apache.log4j.PatternLayout（可以灵活地指定布局模式），<br />3.org.apache.log4j.SimpleLayout（包含日志信息的级别和信息字符串），<br />4.org.apache.log4j.TTCCLayout（包含日志产生的时间、线程、类别等等信息）<br />控制台选项<br />Threshold=DEBUG:指定日志消息的输出最低层次。<br />ImmediateFlush=true:默认值是true,意谓着所有的消息都会被立即输出。<br />Target=System.err：默认情况下是：System.out,指定输出控制台<br />FileAppender 选项<br />Threshold=DEBUF:指定日志消息的输出最低层次。<br />ImmediateFlush=true:默认值是true,意谓着所有的消息都会被立即输出。<br />File=mylog.txt:指定消息输出到mylog.txt文件。<br />Append=false:默认值是true,即将消息增加到指定文件中，false指将消息覆盖指定的文件内容。<br />RollingFileAppender 选项<br />Threshold=DEBUG:指定日志消息的输出最低层次。<br />ImmediateFlush=true:默认值是true,意谓着所有的消息都会被立即输出。<br />File=mylog.txt:指定消息输出到mylog.txt文件。<br />Append=false:默认值是true,即将消息增加到指定文件中，false指将消息覆盖指定的文件内容。<br />MaxFileSize=100KB: 后缀可以是KB, MB 或者是 GB. 在日志文件到达该大小时，将会自动滚动，即将原来的内容移到mylog.log.1文件。<br />MaxBackupIndex=2:指定可以产生的滚动文件的最大数。<br />log4j.appender.A1.layout.ConversionPattern=%-4r %-5p %d{yyyy-MM-dd HH:mm:ssS} %c %m%n<br />日志信息格式中几个符号所代表的含义：<br />&nbsp;-X号: X信息输出时左对齐；<br />&nbsp;%p: 输出日志信息优先级，即DEBUG，INFO，WARN，ERROR，FATAL,<br />&nbsp;%d: 输出日志时间点的日期或时间，默认格式为ISO8601，也可以在其后指定格式，比如：%d{yyy MMM dd HH:mm:ss,SSS}，输出类似：2002年10月18日 22：10：28，921<br />&nbsp;%r: 输出自应用启动到输出该log信息耗费的毫秒数<br />&nbsp;%c: 输出日志信息所属的类目，通常就是所在类的全名<br />&nbsp;%t: 输出产生该日志事件的线程名<br />&nbsp;%l: 输出日志事件的发生位置，相当于%C.%M(%F:%L)的组合,包括类目名、发生的线程，以及在代码中的行数。举例：Testlog4.main (TestLog4.java:10)<br />&nbsp;%x: 输出和当前线程相关联的NDC(嵌套诊断环境),尤其用到像java servlets这样的多客户多线程的应用中。<br />&nbsp;%%: 输出一个"%"字符<br />&nbsp;%F: 输出日志消息产生时所在的文件名称<br />&nbsp;%L: 输出代码中的行号<br />&nbsp;%m: 输出代码中指定的消息,产生的日志具体信息<br />&nbsp;%n: 输出一个回车换行符，Windows平台为"\r\n"，Unix平台为"\n"输出日志信息换行<br />&nbsp;可以在%与模式字符之间加上修饰符来控制其最小宽度、最大宽度、和文本的对齐方式。如：<br />&nbsp;1)%20c：指定输出category的名称，最小的宽度是20，如果category的名称小于20的话，默认的情况下右对齐。<br />&nbsp;2)%-20c:指定输出category的名称，最小的宽度是20，如果category的名称小于20的话，"-"号指定左对齐。<br />&nbsp;3)%.30c:指定输出category的名称，最大的宽度是30，如果category的名称大于30的话，就会将左边多出的字符截掉，但小于30的话也不会有空格。<br />&nbsp;4)%20.30c:如果category的名称小于20就补空格，并且右对齐，如果其名称长于30字符，就从左边较远输出的字符截掉。<br />二.文件配置Sample1<br />log4j.rootLogger=DEBUG,A1,R<br />#log4j.rootLogger=INFO,A1,R<br /># ConsoleAppender 输出<br />log4j.appender.A1=org.apache.log4j.ConsoleAppender<br />log4j.appender.A1.layout=org.apache.log4j.PatternLayout<br />log4j.appender.A1.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [%c]-[%p] %m%n<br /># File 输出 一天一个文件,输出路径可以定制,一般在根路径下<br />log4j.appender.R=org.apache.log4j.DailyRollingFileAppender<br />log4j.appender.R.File=blog_log.txt<br />log4j.appender.R.MaxFileSize=500KB<br />log4j.appender.R.MaxBackupIndex=10<br />log4j.appender.R.layout=org.apache.log4j.PatternLayout<br />log4j.appender.R.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c] [%p] - %m%n<br />文件配置Sample2<br />下面给出的Log4J配置文件实现了输出到控制台，文件，回滚文件，发送日志邮件，输出到数据库日志表，自定义标签等全套功能。<br />log4j.rootLogger=DEBUG,CONSOLE,A1,im <br />#DEBUG,CONSOLE,FILE,ROLLING_FILE,MAIL,DATABASE<br />log4j.addivity.org.apache=true<br />################### <br /># Console Appender <br />################### <br />log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender <br />log4j.appender.Threshold=DEBUG <br />log4j.appender.CONSOLE.Target=System.out <br />log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout <br />log4j.appender.CONSOLE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n <br />#log4j.appender.CONSOLE.layout.ConversionPattern=[start]%d{DATE}[DATE]%n%p[PRIORITY]%n%x[NDC]%n%t[THREAD]  n%c[CATEGORY]%n%m[MESSAGE]%n%n<br />##################### <br /># File Appender <br />##################### <br />log4j.appender.FILE=org.apache.log4j.FileAppender <br />log4j.appender.FILE.File=file.log <br />log4j.appender.FILE.Append=false <br />log4j.appender.FILE.layout=org.apache.log4j.PatternLayout <br />log4j.appender.FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n <br /># Use this layout for LogFactor 5 analysis<br />######################## <br /># Rolling File <br />######################## <br />log4j.appender.ROLLING_FILE=org.apache.log4j.RollingFileAppender <br />log4j.appender.ROLLING_FILE.Threshold=ERROR <br />log4j.appender.ROLLING_FILE.File=rolling.log <br />log4j.appender.ROLLING_FILE.Append=true <br />log4j.appender.ROLLING_FILE.MaxFileSize=10KB <br />log4j.appender.ROLLING_FILE.MaxBackupIndex=1 <br />log4j.appender.ROLLING_FILE.layout=org.apache.log4j.PatternLayout <br />log4j.appender.ROLLING_FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n<br />#################### <br /># Socket Appender <br />#################### <br />log4j.appender.SOCKET=org.apache.log4j.RollingFileAppender <br />log4j.appender.SOCKET.RemoteHost=localhost <br />log4j.appender.SOCKET.Port=5001 <br />log4j.appender.SOCKET.LocationInfo=true <br /># Set up for Log Facter 5 <br />log4j.appender.SOCKET.layout=org.apache.log4j.PatternLayout <br />log4j.appender.SOCET.layout.ConversionPattern=[start]%d{DATE}[DATE]%n%p[PRIORITY]%n%x[NDC]%n%t[THREAD]%n%c[CATEGORY]%n%m[MESSAGE]%n%n<br />######################## <br /># Log Factor 5 Appender <br />######################## <br />log4j.appender.LF5_APPENDER=org.apache.log4j.lf5.LF5Appender <br />log4j.appender.LF5_APPENDER.MaxNumberOfRecords=2000<br />######################## <br /># SMTP Appender <br />####################### <br />log4j.appender.MAIL=org.apache.log4j.net.SMTPAppender <br />log4j.appender.MAIL.Threshold=FATAL <br />log4j.appender.MAIL.BufferSize=10 <br /><a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#108;&#111;&#103;&#52;&#106;&#46;&#97;&#112;&#112;&#101;&#110;&#100;&#101;&#114;&#46;&#77;&#65;&#73;&#76;&#46;&#70;&#114;&#111;&#109;&#61;&#99;&#104;&#101;&#110;&#121;&#108;&#64;&#121;&#101;&#113;&#105;&#97;&#110;&#103;&#119;&#101;&#105;&#46;&#99;&#111;&#109;">log4j.appender.MAIL.From=chenyl@yeqiangwei.com</a><br />log4j.appender.MAIL.SMTPHost=mail.hollycrm.com <br />log4j.appender.MAIL.Subject=Log4J Message <br /><a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#108;&#111;&#103;&#52;&#106;&#46;&#97;&#112;&#112;&#101;&#110;&#100;&#101;&#114;&#46;&#77;&#65;&#73;&#76;&#46;&#84;&#111;&#61;&#99;&#104;&#101;&#110;&#121;&#108;&#64;&#121;&#101;&#113;&#105;&#97;&#110;&#103;&#119;&#101;&#105;&#46;&#99;&#111;&#109;">log4j.appender.MAIL.To=chenyl@yeqiangwei.com</a><br />log4j.appender.MAIL.layout=org.apache.log4j.PatternLayout <br />log4j.appender.MAIL.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n<br />######################## <br /># JDBC Appender <br />####################### <br />log4j.appender.DATABASE=org.apache.log4j.jdbc.JDBCAppender <br />log4j.appender.DATABASE.URL=jdbc:mysql://localhost:3306/test <br />log4j.appender.DATABASE.driver=com.mysql.jdbc.Driver <br />log4j.appender.DATABASE.user=root <br />log4j.appender.DATABASE.password= <br />log4j.appender.DATABASE.sql=INSERT INTO LOG4J (Message) VALUES ('[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n') <br />log4j.appender.DATABASE.layout=org.apache.log4j.PatternLayout <br />log4j.appender.DATABASE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n<br />log4j.appender.A1=org.apache.log4j.DailyRollingFileAppender <br />log4j.appender.A1.File=SampleMessages.log4j <br />log4j.appender.A1.DatePattern=yyyyMMdd-HH'.log4j' <br />log4j.appender.A1.layout=org.apache.log4j.xml.XMLLayout<br />################### <br />#自定义Appender <br />################### <br />log4j.appender.im = net.cybercorlin.util.logger.appender.IMAppender<br />log4j.appender.im.host = mail.cybercorlin.net <br />log4j.appender.im.username = username <br />log4j.appender.im.password = password <br />log4j.appender.im.recipient = <a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#99;&#111;&#114;&#108;&#105;&#110;&#64;&#121;&#101;&#113;&#105;&#97;&#110;&#103;&#119;&#101;&#105;&#46;&#99;&#111;&#109;">corlin@yeqiangwei.com</a><br />log4j.appender.im.layout=org.apache.log4j.PatternLayout <br />log4j.appender.im.layout.ConversionPattern =[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n<br />三.高级使用<br />实验目的：<br />&nbsp;1.把FATAL级错误写入2000NT日志<br />&nbsp;2. WARN，ERROR，FATAL级错误发送email通知管理员<br />&nbsp;3.其他级别的错误直接在后台输出<br />实验步骤：<br />&nbsp;输出到2000NT日志<br />&nbsp;1.把Log4j压缩包里的NTEventLogAppender.dll拷到WINNT\SYSTEM32目录下<br />&nbsp;2.写配置文件log4j.properties<br /># 在2000系统日志输出<br />&nbsp;log4j.logger.NTlog=FATAL, A8<br />&nbsp;# APPENDER A8<br />&nbsp;log4j.appender.A8=org.apache.log4j.nt.NTEventLogAppender<br />&nbsp;log4j.appender.A8.Source=JavaTest<br />&nbsp;log4j.appender.A8.layout=org.apache.log4j.PatternLayout<br />&nbsp;log4j.appender.A8.layout.ConversionPattern=%-4r %-5p [%t] %37c %3x - %m%n<br />3.调用代码：<br />&nbsp;Logger logger2 = Logger.getLogger("NTlog"); //要和配置文件中设置的名字相同<br />&nbsp;logger2.debug("debug!!!");<br />&nbsp;logger2.info("info!!!");<br />&nbsp;logger2.warn("warn!!!");<br />&nbsp;logger2.error("error!!!");<br />&nbsp;//只有这个错误才会写入2000日志<br />&nbsp;logger2.fatal("fatal!!!");<br />发送email通知管理员：<br />&nbsp;1. 首先下载JavaMail和JAF, <br />&nbsp; <a href="http://java.sun.com/j2ee/ja/javamail/index.html">http://java.sun.com/j2ee/ja/javamail/index.html</a><br />&nbsp; <a href="http://java.sun.com/beans/glasgow/jaf.html">http://java.sun.com/beans/glasgow/jaf.html</a><br />&nbsp;在项目中引用mail.jar和activation.jar。<br />&nbsp;2. 写配置文件<br />&nbsp;# 将日志发送到email<br />&nbsp;log4j.logger.MailLog=WARN,A5<br />&nbsp;#&nbsp; APPENDER A5<br />&nbsp;log4j.appender.A5=org.apache.log4j.net.SMTPAppender<br />&nbsp;log4j.appender.A5.BufferSize=5<br />&nbsp;<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#108;&#111;&#103;&#52;&#106;&#46;&#97;&#112;&#112;&#101;&#110;&#100;&#101;&#114;&#46;&#65;&#53;&#46;&#84;&#111;&#61;&#99;&#104;&#117;&#110;&#106;&#105;&#101;&#64;&#121;&#101;&#113;&#105;&#97;&#110;&#103;&#119;&#101;&#105;&#46;&#99;&#111;&#109;">log4j.appender.A5.To=chunjie@yeqiangwei.com</a><br />&nbsp;<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#108;&#111;&#103;&#52;&#106;&#46;&#97;&#112;&#112;&#101;&#110;&#100;&#101;&#114;&#46;&#65;&#53;&#46;&#70;&#114;&#111;&#109;&#61;&#101;&#114;&#114;&#111;&#114;&#64;&#121;&#101;&#113;&#105;&#97;&#110;&#103;&#119;&#101;&#105;&#46;&#99;&#111;&#109;">log4j.appender.A5.From=error@yeqiangwei.com</a><br />&nbsp;log4j.appender.A5.Subject=ErrorLog<br />&nbsp;log4j.appender.A5.SMTPHost=smtp.263.net<br />&nbsp;log4j.appender.A5.layout=org.apache.log4j.PatternLayout<br />&nbsp;log4j.appender.A5.layout.ConversionPattern=%-4r %-5p [%t] %37c %3x - %m%n<br />&nbsp;3.调用代码：<br />&nbsp;//把日志发送到mail<br />&nbsp;Logger logger3 = Logger.getLogger("MailLog");<br />&nbsp;logger3.warn("warn!!!");<br />&nbsp;logger3.error("error!!!");<br />&nbsp;logger3.fatal("fatal!!!");<br />在后台输出所有类别的错误：<br />&nbsp;1. 写配置文件<br />&nbsp;# 在后台输出<br />&nbsp;log4j.logger.console=DEBUG, A1<br />&nbsp;# APPENDER A1<br />&nbsp;log4j.appender.A1=org.apache.log4j.ConsoleAppender<br />&nbsp;log4j.appender.A1.layout=org.apache.log4j.PatternLayout<br />&nbsp;log4j.appender.A1.layout.ConversionPattern=%-4r %-5p [%t] %37c %3x - %m%n<br />&nbsp;2．调用代码<br />&nbsp;Logger logger1 = Logger.getLogger("console");<br />&nbsp;logger1.debug("debug!!!");<br />&nbsp;logger1.info("info!!!");<br />&nbsp;logger1.warn("warn!!!");<br />&nbsp;logger1.error("error!!!");<br />&nbsp;logger1.fatal("fatal!!!");<br />--------------------------------------------------------------------<br />&nbsp;全部配置文件：log4j.properties<br />&nbsp;# 在后台输出<br />&nbsp;log4j.logger.console=DEBUG, A1<br />&nbsp;# APPENDER A1<br />&nbsp;log4j.appender.A1=org.apache.log4j.ConsoleAppender<br />&nbsp;log4j.appender.A1.layout=org.apache.log4j.PatternLayout<br />&nbsp;log4j.appender.A1.layout.ConversionPattern=%-4r %-5p [%t] %37c %3x - %m%n<br /># 在2000系统日志输出<br />&nbsp;log4j.logger.NTlog=FATAL, A8<br />&nbsp;# APPENDER A8<br />&nbsp;log4j.appender.A8=org.apache.log4j.nt.NTEventLogAppender<br />&nbsp;log4j.appender.A8.Source=JavaTest<br />&nbsp;log4j.appender.A8.layout=org.apache.log4j.PatternLayout<br />&nbsp;log4j.appender.A8.layout.ConversionPattern=%-4r %-5p [%t] %37c %3x - %m%n<br /># 将日志发送到email<br />&nbsp;log4j.logger.MailLog=WARN,A5<br />&nbsp;#&nbsp; APPENDER A5<br />&nbsp;log4j.appender.A5=org.apache.log4j.net.SMTPAppender<br />&nbsp;log4j.appender.A5.BufferSize=5<br />&nbsp;<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#108;&#111;&#103;&#52;&#106;&#46;&#97;&#112;&#112;&#101;&#110;&#100;&#101;&#114;&#46;&#65;&#53;&#46;&#84;&#111;&#61;&#99;&#104;&#117;&#110;&#106;&#105;&#101;&#64;&#121;&#101;&#113;&#105;&#97;&#110;&#103;&#119;&#101;&#105;&#46;&#99;&#111;&#109;">log4j.appender.A5.To=chunjie@yeqiangwei.com</a><br />&nbsp;<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#108;&#111;&#103;&#52;&#106;&#46;&#97;&#112;&#112;&#101;&#110;&#100;&#101;&#114;&#46;&#65;&#53;&#46;&#70;&#114;&#111;&#109;&#61;&#101;&#114;&#114;&#111;&#114;&#64;&#121;&#101;&#113;&#105;&#97;&#110;&#103;&#119;&#101;&#105;&#46;&#99;&#111;&#109;">log4j.appender.A5.From=error@yeqiangwei.com</a><br />&nbsp;log4j.appender.A5.Subject=ErrorLog<br />&nbsp;log4j.appender.A5.SMTPHost=smtp.263.net<br />&nbsp;log4j.appender.A5.layout=org.apache.log4j.PatternLayout<br />&nbsp;log4j.appender.A5.layout.ConversionPattern=%-4r %-5p [%t] %37c %3x - %m%n<br />全部代码：Log4jTest.java<br />&nbsp; <br />/* <br />&nbsp; * 创建日期 2003-11-13 <br />&nbsp; */ <br />&nbsp;package edu.bcu.Bean; <br />&nbsp;imp<wbr>ort org.apache.log4j.*; <br />&nbsp;//imp<wbr>ort org.apache.log4j.nt.*; <br />&nbsp;//imp<wbr>ort org.apache.log4j.net.*; <br />&nbsp;/** <br />&nbsp; * @author yanxu <br />&nbsp; */ <br />&nbsp;public class Log4jTest <br />&nbsp;{ <br />&nbsp; public static void main(String args[]) <br />&nbsp; { <br />&nbsp;&nbsp; PropertyConfigurator.configure("log4j.properties"); <br />&nbsp;&nbsp; //在后台输出 <br />&nbsp;&nbsp; Logger logger1 = Logger.getLogger("console"); <br />&nbsp;&nbsp; logger1.debug("debug!!!"); <br />&nbsp;&nbsp; logger1.info("info!!!"); <br />&nbsp;&nbsp; logger1.warn("warn!!!"); <br />&nbsp;&nbsp; logger1.error("error!!!"); <br />&nbsp;&nbsp; logger1.fatal("fatal!!!");<br />//在NT系统日志输出 <br />&nbsp;&nbsp; Logger logger2 = Logger.getLogger("NTlog"); <br />&nbsp;&nbsp; //NTEventLogAppender nla = new NTEventLogAppender(); <br />&nbsp;&nbsp; logger2.debug("debug!!!"); <br />&nbsp;&nbsp; logger2.info("info!!!"); <br />&nbsp;&nbsp; logger2.warn("warn!!!"); <br />&nbsp;&nbsp; logger2.error("error!!!"); <br />&nbsp;&nbsp; //只有这个错误才会写入2000日志 <br />&nbsp;&nbsp; logger2.fatal("fatal!!!");<br />//把日志发送到mail <br />&nbsp;&nbsp; Logger logger3 = Logger.getLogger("MailLog"); <br />&nbsp;&nbsp; //SMTPAppender sa = new SMTPAppender(); <br />&nbsp;&nbsp; logger3.warn("warn!!!"); <br />&nbsp;&nbsp; logger3.error("error!!!"); <br />&nbsp;&nbsp; logger3.fatal("fatal!!!"); <br />&nbsp; } <br />&nbsp;} </span></span></p></div><img src ="http://www.blogjava.net/zhb8015/aggbug/382004.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zhb8015/" target="_blank">zhb8015</a> 2012-07-02 17:32 <a href="http://www.blogjava.net/zhb8015/articles/382004.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>时间复杂度</title><link>http://www.blogjava.net/zhb8015/articles/381026.html</link><dc:creator>zhb8015</dc:creator><author>zhb8015</author><pubDate>Mon, 18 Jun 2012 10:25:00 GMT</pubDate><guid>http://www.blogjava.net/zhb8015/articles/381026.html</guid><wfw:comment>http://www.blogjava.net/zhb8015/comments/381026.html</wfw:comment><comments>http://www.blogjava.net/zhb8015/articles/381026.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zhb8015/comments/commentRss/381026.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zhb8015/services/trackbacks/381026.html</trackback:ping><description><![CDATA[<div><div nslog-area"="" data-nslog-type="72"> <div> <p> 同一问题可用不同<a target="_blank" href="http://baike.baidu.com/view/7420.htm">算法</a>解决，而一个算法的质量优劣将影响到算法乃至<a target="_blank" href="http://baike.baidu.com/view/17674.htm">程序</a>的效率。算法分析的目的在于选择合适算法和改进算法。</p> </div>  </div>  <div nslog-area=""  log-set-param"="" data-nslog-type="1016" data-subindex="0" id="catalog-0"> <p>目录</p> <dl style="width: 133px; visibility: hidden; padding-bottom: 20px;" id="catalog-holder-0"><dd><a href="http://baike.baidu.com/view/104946.htm#1" name="STAT_ONCLICK_UNSUBMIT_CATALOG"></a></dd><dd><a href="http://baike.baidu.com/view/104946.htm#2" name="STAT_ONCLICK_UNSUBMIT_CATALOG"></a></dd><dd><a href="http://baike.baidu.com/view/104946.htm#3" name="STAT_ONCLICK_UNSUBMIT_CATALOG"></a></dd></dl> <dl style="width: 133px; display: block;"  arr"="" id="catalog-holder-2-0"><dd><a href="http://baike.baidu.com/view/104946.htm#1" name="STAT_ONCLICK_UNSUBMIT_CATALOG">算法复杂度</a></dd><dd><a href="http://baike.baidu.com/view/104946.htm#2" name="STAT_ONCLICK_UNSUBMIT_CATALOG">时间复杂度</a></dd><dd><a href="http://baike.baidu.com/view/104946.htm#3" name="STAT_ONCLICK_UNSUBMIT_CATALOG">空间复杂度</a></dd><div catalog-holder"="" id="catalog-holder0">展开</div></dl> </div>    <h2><span editable-title"="" data-edit-id="104946:104946:1"><a href="http://baike.baidu.com/view/104946.htm#">编辑本段</a></span><a name="1"></a><a name="sub104946_1"></a>算法复杂度</h2>　　<a target="_blank" href="http://baike.baidu.com/view/7527.htm">算法复杂度</a>分为<a target="_blank" href="http://baike.baidu.com/view/104946.htm">时间复杂度</a>和<a target="_blank" href="http://baike.baidu.com/view/540497.htm">空间复杂度</a>。其作用： 时间复杂度是度量算法执行的时间长短；而空间复杂度是度量算法所需存储空间的大小。<h2><span editable-title"="" data-edit-id="104946:104946:2"><a href="http://baike.baidu.com/view/104946.htm#">编辑本段</a></span><a name="2"></a><a name="sub104946_2"></a>时间复杂度</h2><h3><a name="2_1"></a><a name="sub104946_2_1"></a>1.时间频度</h3>　　一个算法执行所耗费的时间，从理论上是不能算出来的，必须上机运行测试才能知道。但我们不可能也没有必要对每个算法都上机测试，只需知道哪个算法花费的时间多，哪个算法花费的时间少就可以了。并且一个算法花费的时间与算法中语句的执行次数<a target="_blank" href="http://baike.baidu.com/view/2060659.htm">成正比例</a>，哪个算法中语句执行次数多，它花费时间就多。一个算法中的语句执行次数称为语句频度或时间频度。记为T(n)。<h3><a name="2_2"></a><a name="sub104946_2_2"></a>2.计算方法</h3>　　1. 一般情况下，算法的基本操作重复执行的次数是模块n的某一个函数f（n），因此，算法的时间复杂度记做：T（n）=O（f（n）） 　　分析：随着模块n的增大，算法执行的时间的增长率和f（n）的增长率成正比，所以f（n）越小，算法的时间复杂度越低，算法的效率越高。 　　2.  在计算时间复杂度的时候，先找出算法的基本操作，然后根据相应的各语句确定它的执行次数，再找出T（n）的同数量级（它的同数量级有以下：1，Log2n  ，n ，nLog2n  ，n的平方，n的三次方，2的n次方，n！），找出后，f（n）=该数量级，若T(n)/f(n)求极限可得到一常数c，则时间复杂度 T（n）=O（f（n）） 　　例：算法： 　　for（i=1;i&lt;=n;++i） 　　{ 　　for(j=1;j&lt;=n;++j) 　　{ 　　c[ i ][ j ]=0; //该步骤属于基本操作 执行次数：n的平方 次 　　for(k=1;k&lt;=n;++k) 　　c[ i ][ j ]+=a[ i ][ k ]*b[ k ][ j ]; //该步骤属于基本操作 执行次数：n的三次方 次 　　} 　　} 　　则有 T（n）= n的平方+n的三次方，根据上面括号里的同数量级，我们可以确定 n的三次方 为T（n）的同数量级 　　则有f（n）= n的三次方，然后根据T（n）/f（n）求极限可得到常数c 　　则该算法的 时间复杂度：T（n）=O（n^3） 注：n^3即是n的3次方。<h3><a name="2_3"></a><a name="sub104946_2_3"></a>3.分类</h3>　　按数量级递增排列，常见的时间复杂度有： 　　常数阶O(1),对数阶O(log2n),线性阶O(n), 　　线性对数阶O(nlog2n),平方阶O(n^2)，立方阶O(n^3),...， 　　k次方阶O(n^k), 指数阶O(2n) 。随着问题规模n的不断增大，上述时间复杂度不断增大，算法的执行效率越低。<h2><span editable-title"="" data-edit-id="104946:104946:3"><a href="http://baike.baidu.com/view/104946.htm#">编辑本段</a></span><a name="3"></a><a name="sub104946_3"></a>空间复杂度</h2>　 　一个程序的空间复杂度是指运行完一个程序所需内存的大小。利用程序的空间复杂度，可以对程序的运行所需要的内存多少有个预先估计。一个程序执行时除了需 要存储空间和存储本身所使用的指令、常数、变量和输入数据外，还需要一些对数据进行操作的工作单元和存储一些为现实计算所需信息的辅助空间。程序执行时所 需存储空间包括以下两部分。 　　（1）固定部分。这部分空间的大小与输入/输出的数据的个数多少、数值无关。主要包括指令空间（即代码空间）、数据空间（常量、简单变量）等所占的空间。这部分属于静态空间。 　　（2）可变空间，这部分空间的主要包括动态分配的空间，以及递归栈所需的空间等。这部分的空间大小与算法有关。 　　一个算法所需的存储空间用f(n)表示。 　　S(n)=O(f(n)) 　　其中n为问题的规模，S(n)表示空间复杂度。</div><img src ="http://www.blogjava.net/zhb8015/aggbug/381026.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zhb8015/" target="_blank">zhb8015</a> 2012-06-18 18:25 <a href="http://www.blogjava.net/zhb8015/articles/381026.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java栈与堆（转）</title><link>http://www.blogjava.net/zhb8015/articles/380703.html</link><dc:creator>zhb8015</dc:creator><author>zhb8015</author><pubDate>Wed, 13 Jun 2012 09:27:00 GMT</pubDate><guid>http://www.blogjava.net/zhb8015/articles/380703.html</guid><wfw:comment>http://www.blogjava.net/zhb8015/comments/380703.html</wfw:comment><comments>http://www.blogjava.net/zhb8015/articles/380703.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zhb8015/comments/commentRss/380703.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zhb8015/services/trackbacks/380703.html</trackback:ping><description><![CDATA[<div><p>&nbsp;</p><div>摘自 chenghai2011的专栏				</div><p>-------------------------------------------------------------------------------------------------------------------</p> <p><br /> Java栈与堆</p> <p>&nbsp;</p> <p><br /> 1. 栈(stack)与堆(heap)都是Java用来在Ram中存放数据的地方。与C++不同，Java自动管理栈和堆，程序员不能直接地设置栈或堆。</p> <p>2.  栈的优势是，存取速度比堆要快，仅次于直接位于CPU中的寄存器。但缺点是，存在栈中的数据大小与生存期必须是确定的，缺乏灵活性。另外，栈数据可以共 享，详见第3点。堆的优势是可以动态地分配内存大小，生存期也不必事先告诉编译器，Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是，由于要 在运行时动态分配内存，存取速度较慢。</p> <p>3. Java中的数据类型有两种。</p> <p>一种是基本类型(primitive types), 共有8种，即int, short, long, byte, float,  double, boolean, char(注意，并没有string的基本类型)。这种类型的定义是通过诸如int a = 3; long b =  255L;的形式来定义的，称为自动变量。值得注意的是，自动变量存的是字面值，不是类的实例，即不是类的引用，这里并没有类的存在。如int a =  3;  这里的a是一个指向int类型的引用，指向3这个字面值。这些字面值的数据，由于大小可知，生存期可知(这些字面值固定定义在某个程序块里面，程序块退出 后，字段值就消失了)，出于追求速度的原因，就存在于栈中。</p> <p>另外，栈有一个很重要的特殊性，就是存在栈中的数据可以共享。假设我们同时定义：<br /> 复制内容到剪贴板代码:<br /> int a = 3;<br /> int b = 3；<br /> 编译器先处理int a =  3；首先它会在栈中创建一个变量为a的引用，然后查找有没有字面值为3的地址，没找到，就开辟一个存放3这个字面值的地址，然后将a指向3的地址。接着处 理int b = 3；在创建完b的引用变量后，由于在栈中已经有3这个字面值，便将b直接指向3的地址。这样，就出现了a与b同时均指向3的情况。</p> <p>特别注意的是，这种字面值的引用与类对象的引用不同。假定两个类对象的引用同时指向一个对象，如果一个对象引用变量修改了这个对象的内部状态，那么 另一个对象引用变量也即刻反映出这个变化。相反，通过字面值的引用来修改其值，不会导致另一个指向此字面值的引用的值也跟着改变的情况。如上例，我们定义 完a与b的值后，再令a=4；那么，b不会等于4，还是等于3。在编译器内部，遇到a=4；时，它就会重新搜索栈中是否有4的字面值，如果没有，重新开辟 地址存放4的值；如果已经有了，则直接将a指向这个地址。因此a值的改变不会影响到b的值。</p> <p>另一种是包装类数据，如Integer, String,  Double等将相应的基本数据类型包装起来的类。这些类数据全部存在于堆中，Java用new()语句来显示地告诉编译器，在运行时才根据需要动态创 建，因此比较灵活，但缺点是要占用更多的时间。 4. String是一个特殊的包装类数据。即可以用String str = new  String("abc");的形式来创建，也可以用String str = "abc"；的形式来创建(作为对比，在JDK  5.0之前，你从未见过Integer i = 3;的表达式，因为类与字面值是不能通用的，除了String。而在JDK  5.0中，这种表达式是可以的！因为编译器在后台进行Integer i = new  Integer(3)的转换)。前者是规范的类的创建过程，即在Java中，一切都是对象，而对象是类的实例，全部通过new()的形式来创建。Java 中的有些类，如DateFormat类，可以通过该类的getInstance()方法来返回一个新创建的类，似乎违反了此原则。其实不然。该类运用了单 例模式来返回类的实例，只不过这个实例是在该类内部通过new()来创建的，而getInstance()向外部隐藏了此细节。那为什么在String  str = "abc"；中，并没有通过new()来创建实例，是不是违反了上述原则？其实没有。</p> <p>5. 关于String str = "abc"的内部工作。Java内部将此语句转化为以下几个步骤：</p> <p>(1)先定义一个名为str的对String类的对象引用变量：String str；</p> <p>(2)在栈中查找有没有存放值为"abc"的地址，如果没有，则开辟一个存放字面值为"abc"的地址，接着创建一个新的String类的对象o， 并将o的字符串值指向这个地址，而且在栈中这个地址旁边记下这个引用的对象o。如果已经有了值为"abc"的地址，则查找对象o，并返回o的地址。</p> <p>(3)将str指向对象o的地址。</p> <p>值得注意的是，一般String类中字符串值都是直接存值的。但像String str = "abc"；这种场合下，其字符串值却是保存了一个指向存在栈中数据的引用！</p> <p>为了更好地说明这个问题，我们可以通过以下的几个代码进行验证。<br /> 复制内容到剪贴板代码:<br /> String str1 = "abc";<br /> String str2 = "abc";<br /> System.out.println(str1==str2); //true<br /> 注意，我们这里并不用str1.equals(str2)；的方式，因为这将比较两个字符串的值是否相等。==号，根据JDK的说明，只有在两个引用都指向了同一个对象时才返回真值。而我们在这里要看的是，str1与str2是否都指向了同一个对象。<br /> 结果说明，JVM创建了两个引用str1和str2，但只创建了一个对象，而且两个引用都指向了这个对象。</p> <p>我们再来更进一步，将以上代码改成：<br /> 复制内容到剪贴板代码:<br /> String str1 = "abc";<br /> String str2 = "abc";<br /> str1 = "bcd";<br /> System.out.println(str1 + "," + str2); //bcd, abc<br /> System.out.println(str1==str2); //false<br /> 这就是说，赋值的变化导致了类对象引用的变化，str1指向了另外一个新对象！而str2仍旧指向原来的对象。上例中，当我们将str1的值改为"bcd"时，JVM发现在栈中没有存放该值的地址，便开辟了这个地址，并创建了一个新的对象，其字符串的值指向这个地址。</p> <p>事实上，String类被设计成为不可改变(immutable)的类。如果你要改变其值，可以，但JVM在运行时根据新值悄悄创建了一个新对象， 然后将这个对象的地址返回给原来类的引用。这个创建过程虽说是完全自动进行的，但它毕竟占用了更多的时间。在对时间要求比较敏感的环境中，会带有一定的不 良影响。</p> <p>再修改原来代码：<br /> 复制内容到剪贴板代码:<br /> String str1 = "abc";<br /> String str2 = "abc";</p> <p>str1 = "bcd";</p> <p>String str3 = str1;<br /> System.out.println(str3); //bcd</p> <p>String str4 = "bcd";<br /> System.out.println(str1 == str4); //true<br /> str3这个对象的引用直接指向str1所指向的对象(注意，str3并没有创建新对象)。当str1改完其值后，再创建一个String的引用str4，并指向因str1修改值而创建的新的对象。可以发现，这回str4也没有创建新的对象，从而再次实现栈中数据的共享。</p> <p>我们再接着看以下的代码。<br /> 复制内容到剪贴板代码:<br /> String str1 = new String("abc");<br /> String str2 = "abc";<br /> System.out.println(str1==str2); //false 创建了两个引用。创建了两个对象。两个引用分别指向不同的两个对象。</p> <p>String str1 = "abc";<br /> String str2 = new String("abc");<br /> System.out.println(str1==str2); //false<br /> 创建了两个引用。创建了两个对象。两个引用分别指向不同的两个对象。</p> <p>以上两段代码说明，只要是用new()来新建对象的，都会在堆中创建，而且其字符串是单独存值的，即使与栈中的数据相同，也不会与栈中的数据共享。</p> <p>6. 数据类型包装类的值不可修改。不仅仅是String类的值不可修改，所有的数据类型包装类都不能更改其内部的值。</p> <p>7. 结论与建议：</p> <p>(1)我们在使用诸如String str =  "abc"；的格式定义类时，总是想当然地认为，我们创建了String类的对象str。担心陷阱！对象可能并没有被创建！唯一可以肯定的是，指向 String类的引用被创建了。至于这个引用到底是否指向了一个新的对象，必须根据上下文来考虑，除非你通过new()方法来显要地创建一个新的对象。因 此，更为准确的说法是，我们创建了一个指向String类的对象的引用变量str，这个对象引用变量指向了某个值为"abc"的String类。清醒地认 识到这一点对排除程序中难以发现的bug是很有帮助的。</p> <p>(2)使用String str =  "abc"；的方式，可以在一定程度上提高程序的运行速度，因为JVM会自动根据栈中数据的实际情况来决定是否有必要创建新对象。而对于String  str = new  String("abc")；的代码，则一概在堆中创建新对象，而不管其字符串值是否相等，是否有必要创建新对象，从而加重了程序的负担。这个思想应该是 享元模式的思想，但JDK的内部在这里实现是否应用了这个模式，不得而知。</p> <p>(3)当比较包装类里面的数值是否相等时，用equals()方法；当测试两个包装类的引用是否指向同一个对象时，用==。</p> <p>(4)由于String类的immutable性质，当String变量需要经常变换其值时，应该考虑使用StringBuffer类，以提高程序效率。</p> <p>&nbsp;</p></div><img src ="http://www.blogjava.net/zhb8015/aggbug/380703.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zhb8015/" target="_blank">zhb8015</a> 2012-06-13 17:27 <a href="http://www.blogjava.net/zhb8015/articles/380703.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>也说Java循环优化(转)</title><link>http://www.blogjava.net/zhb8015/articles/380629.html</link><dc:creator>zhb8015</dc:creator><author>zhb8015</author><pubDate>Tue, 12 Jun 2012 09:47:00 GMT</pubDate><guid>http://www.blogjava.net/zhb8015/articles/380629.html</guid><wfw:comment>http://www.blogjava.net/zhb8015/comments/380629.html</wfw:comment><comments>http://www.blogjava.net/zhb8015/articles/380629.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zhb8015/comments/commentRss/380629.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zhb8015/services/trackbacks/380629.html</trackback:ping><description><![CDATA[<div>http://hi.baidu.com/freish/blog/item/b793042433594a3fd40742bf.html</div><br /><div><span style="font-size:14.0pt;font-family:宋体">近有不少人提出</span><span style="font-size:14.0pt">Java</span><span style="font-size:14.0pt;font-family:宋体">循环优化问题，问题分为两类：</span><p>&nbsp;</p><p><strong><span style="font-family:黑体">1</span></strong><strong><span style="font-family:黑体">）</span></strong></p><p><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><strong>for</strong>(<strong>int</strong> i=0; i&lt;10000; i--){<span style="font-size:10.0pt;font-family:宋体;;;;color:black">。。。</span>}</p><p>&nbsp;</p><p><span style="font-family:宋体">与</span></p><p>&nbsp;</p><p><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><strong>for</strong>(<strong>int</strong> i = 100000; i &gt; 0; i--){<span style="font-size:10.0pt;font-family:宋体;;;;color:black">。。。</span>}</p><p>&nbsp;</p><p><span style="font-size:14.0pt;font-family:宋体;;;color:black">这个比较无非是</span><span style="font-size:14.0pt;color:black">i++</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">和</span><span style="font-size:14.0pt;color:black">i&#8212;</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">的比较。</span></p><p>&nbsp;</p><p><strong><span style="font-family:黑体">2</span></strong><strong><span style="font-family:黑体">）</span></strong></p><p><strong>for</strong>(<strong>int</strong> i=0; i&lt;1000; i++) {</p><p><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><strong>for</strong>(<strong>int</strong> j=0; j&lt;100000; j++) {</p><p><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-size:10.0pt;font-family:宋体;;;;color:black">。。。</span></p><p><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></p><p><span>&nbsp;&nbsp;&nbsp;&nbsp;}</span></p><p>&nbsp;</p><p><span style="font-size:10.0pt;font-family:宋体;;;;color:black">与</span></p><p>&nbsp;</p><p><strong>for</strong> (<strong>int</strong> i = 0; i &lt; 100000; i++) {</p><p><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><strong>for</strong> (<strong>int</strong> j = 0; j &lt; 1000; j++) {</p><p><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-size:10.0pt;font-family:宋体">。。。</span></p><p><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></p><p><span>&nbsp;&nbsp;&nbsp;&nbsp;}</span></p><p>&nbsp;</p><div style=";border:none;border-bottom:solid windowtext 1.0pt;border-bottom:solid windowtext 1pt"><p><span style="font-size:14.0pt;font-family:宋体;;;color:black">这个比较主要问题在于循环次数多的放在里面还是外面的问题。</span></p><p>&nbsp;</p></div><p><span style="font-size:14.0pt;font-family:宋体;;;color:black">我的观点：首先，这种代码上自以为是的优化是没有意义的；其次，拿</span><span style="font-size:14.0pt;color:black">C</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">语言的思维来考虑这个问题表示</span><span style="font-size:14.0pt;color:black">Java</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">基本常识都不懂。</span></p><p><span style="font-size:14.0pt;font-family:宋体;;;color:black">分析：</span></p><p><span style="font-size:14.0pt;font-family:宋体;;;color:black">在具体阐明我的观点前有必要做一点</span><span style="font-size:14.0pt;color:black">Java</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">常识的普及。（注，若没有特别说明，文中</span><span style="font-size:14.0pt;color:black">sun</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">的指的是被</span><span style="font-size:14.0pt;color:black">Oracle</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">收购的那个</span><span style="font-size:14.0pt;color:black">sun</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">，也用来表示</span><span style="font-size:14.0pt;color:black">Oracle</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">接手的</span><span style="font-size:14.0pt;color:black">sun</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">公司的一些产品，如</span><span style="font-size:14.0pt;color:black">sun</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">的</span><span style="font-size:14.0pt;color:black">jvm</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">，既指</span><span style="font-size:14.0pt;color:black">Oracle</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">接手</span><span style="font-size:14.0pt;color:black">sun</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">后的虚拟机，也指未收购时的</span><span style="font-size:14.0pt;color:black">sun</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">的虚拟机）</span></p><p><span style="font-size:14.0pt;;;color:black">1）<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span><span style="font-size:14.0pt;color:black">jvm</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">。</span></p><p><span style="font-size:14.0pt;font-family:宋体;;;color:black">众所周知，这是</span><span style="font-size:14.0pt;color:black">java</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">虚拟机。但是，很多人，包括初学者甚至一些工作了的人，对</span><span style="font-size:14.0pt;color:black">jvm</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">的认识仅仅是</span><span style="font-size:14.0pt;color:black">sun</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">的</span><span style="font-size:14.0pt;color:black">hotspot</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">虚拟机，就是从</span><span style="font-size:14.0pt;color:black">sun</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">官网上下载的那个。</span></p><p><span style="font-size:14.0pt;font-family:宋体;;;color:black">而实际上，</span><span style="font-size:14.0pt;color:black">sun</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">公司制定的是一个规范，即</span><span style="font-size:14.0pt;color:black"><a href="http://java.sun.com/docs/books/jvms/second_edition/html/VMSpecTOC.doc.html">Java<span style="font-family:宋体">虚拟机规范</span></a></span><span style="font-size:14.0pt;font-family:宋体;;;color:black">，搜索</span><span style="font-size:14.0pt;color:black">jvmspec</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">即可得。同时</span><span style="font-size:14.0pt;color:black">sun</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">也提供了该规范的一个标准实现，就是</span><span style="font-size:14.0pt;color:black">sun</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">的</span><span style="font-size:14.0pt;color:black">hotspot</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">虚拟机（</span><span style="font-size:14.0pt;color:black">N</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">年前的版本就不说了）。但很多人不知道的是，除了</span><span style="font-size:14.0pt;color:black">sun</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">实现了虚拟机外，还有很多公司也根据自己的需要实现了</span><span style="font-size:14.0pt;color:black">Java</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">虚拟机，比较常见的有</span><span style="font-size:14.0pt;color:black">IBM</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">的</span><span style="font-size:14.0pt;color:black">J9</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">（</span><span style="font-size:14.0pt;color:black">Websphere</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">中用的），</span><span style="font-size:14.0pt;color:black">Oracle</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">的</span><span style="font-size:14.0pt;color:black">JRockit</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">（</span><span style="font-size:14.0pt;color:black">Weblogic</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">中用的），</span><span style="font-size:14.0pt;color:black">Apache</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">的</span><span style="font-size:14.0pt;color:black">Harmony</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">（由于利益等原因，</span><span style="font-size:14.0pt;color:black">sun</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">和</span><span style="font-size:14.0pt;color:black">Oracle</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">都没有给它提供兼容性测试），还有</span><span style="font-size:14.0pt;color:black">openJDK</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">。这些都是比较流行的。诸如此类，还有很多很多。</span></p><p><span style="font-size:14.0pt;;;color:black">2）<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span><span style="font-size:14.0pt;color:black">Java</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">指令集</span></p><p><span style="font-size:14.0pt;color:black">jvm</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">规范中，为</span><span style="font-size:14.0pt;color:black">Java</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">定义了一套指令集。如</span><span style="font-size:14.0pt;color:black">iadd</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">，</span><span style="font-size:14.0pt;color:black">iinc</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">等，指令集用单字节表示，也就是说不超过</span><span style="font-size:14.0pt;color:black">255</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">个。</span></p><p><span style="font-size:14.0pt;font-family:宋体;;;color:black">关于规范中</span><span style="font-size:14.0pt;color:black">jvm</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">指令集最需要注意的一点是：指令集指描述了指令该做什么事情，对于如何去做，是留给</span><span style="font-size:14.0pt;color:black">jvm</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">实现者自己去思考的，所以不同的</span><span style="font-size:14.0pt;color:black">jvm</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">实现对于同一段代码在效率上可能会有很大的差别。譬如，对于</span><span style="font-size:14.0pt;color:black">iadd</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">指令，两个</span><span style="font-size:14.0pt;color:black">int</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">相加，既可以直接交给硬件去做，也可以拐弯抹角的去做，只要最终结果符合</span><span style="font-size:14.0pt;color:black">jvm</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">规范的描述即可。</span></p><p><span style="font-size:14.0pt;;;color:black">3）<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span><span style="font-size:14.0pt;color:black">Java</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">栈</span></p><p><span style="font-size:14.0pt;font-family:宋体;;;color:black">需要知道的是，</span><span style="font-size:14.0pt;color:black">Java</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">考虑到跨平台的需要，所有指令的操作都不是基于寄存器的，而是内存中的</span><span style="font-size:14.0pt;color:black">Java</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">栈。在</span><span style="font-size:14.0pt;color:black">C</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">语言中，有个寄存器用于</span><span style="font-size:14.0pt;color:black">pc</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">计数器，而在</span><span style="font-size:14.0pt;color:black">Java</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">中，</span><span style="font-size:14.0pt;color:black">pc</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">计数器是内存中的一个字。</span><span style="font-size:14.0pt;color:black">Java</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">栈由栈帧组成，栈帧分为局部变量区，操作数栈和帧数据区。</span><span style="font-size:14.0pt;color:black">jvm</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">指令的操作数大都源于操作数栈。这与一些语言从寄存器中取操作数是不同的。而局部变量区和操作数栈的大小在编译</span><span style="font-size:14.0pt;color:black">Java</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">文件时就已经确定了。</span></p><p>&nbsp;</p><p><span style="font-size:14.0pt;font-family:宋体;;;color:black">对于问题一，我们有必要看一下</span><span style="font-size:14.0pt;color:black">Java</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">中对于</span><span style="font-size:14.0pt;color:black">i++</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">和</span><span style="font-size:14.0pt;color:black">i&#8212;</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">所使用的指令</span></p><p><strong>public</strong>&nbsp;<strong>class</strong> Test {</p><p><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><strong>public</strong>&nbsp;<strong>static</strong>&nbsp;<strong>void</strong> main(String... args) {</p><p><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><strong>int</strong> i = 0;</p><p><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i++;</span></p><p><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i--;</span></p><p><span>&nbsp;&nbsp;&nbsp;&nbsp;}</span></p><p>}</p><p><span style="font-size:14.0pt;font-family:宋体;;;color:black">上面的代码编译后再用</span><span style="font-size:14.0pt;color:black">javap &#8211;c Test</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">查看用到的指令：</span></p><p><span style=";color:black">Compiled from "Test.java"</span></p><p><span style=";color:black">public class Test extends java.lang.Object{</span></p><p><span style=";color:black">public Test();</span></p><p><span style=";color:black">&nbsp;&nbsp;Code:</span></p><p><span style=";color:black">&nbsp;&nbsp;&nbsp;0:&nbsp;&nbsp;&nbsp;aload_0</span></p><p><span style=";color:black">&nbsp;&nbsp;&nbsp;1:&nbsp;&nbsp;&nbsp;invokespecial&nbsp;&nbsp;&nbsp;#1; //Methodjava/lang/Object."&lt;init&gt;":()V</span></p><p><span style=";color:black">&nbsp;&nbsp;&nbsp;4:&nbsp;&nbsp;&nbsp;return</span></p><p>&nbsp;</p><p><span style=";color:black">public static void main(java.lang.String[]);</span></p><p><span style=";color:black">&nbsp;&nbsp;Code:</span></p><p><span style=";color:black">&nbsp;&nbsp;&nbsp;0:&nbsp;&nbsp;&nbsp;iconst_0</span></p><p><span style=";color:black">&nbsp;&nbsp;&nbsp;1:&nbsp;&nbsp;&nbsp;istore_1</span></p><p><span style=";color:black">&nbsp;&nbsp;&nbsp;</span><span style=";color:red">2:&nbsp;&nbsp;iinc&nbsp;&nbsp;&nbsp;&nbsp;1, 1</span></p><p><span style=";color:black">&nbsp;&nbsp;&nbsp;</span><span style=";color:red">5:&nbsp;&nbsp;iinc&nbsp;&nbsp;&nbsp;&nbsp;1, -1</span></p><p><span style=";color:black">&nbsp;&nbsp;&nbsp;8:&nbsp;&nbsp;&nbsp;return</span></p><p>&nbsp;</p><p><span style=";color:black">}</span></p><p><span style="font-size:14.0pt;font-family:宋体;;;color:black">从上面我们发现</span><span style="font-size:14.0pt;color:black">i++</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">和</span><span style="font-size:14.0pt;color:black">i--</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">其实用的是同一个指令，即</span><span style="font-size:14.0pt;color:black">iinc</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">，不过操作数不一样罢了；该指令直接修改局部变量区的值，而不需要压栈。至于如何去实现这个指令，不同的人在实现</span><span style="font-size:14.0pt;color:black">jvm</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">的时候有自己的想法。所以问题一的比较是毫无意义的。你在</span><span style="font-size:14.0pt;color:black">jvm</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">实现</span><span style="font-size:14.0pt;color:black">1</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">上运行很快，可能在</span><span style="font-size:14.0pt;color:black">jvm</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">实现</span><span style="font-size:14.0pt;color:black">2</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">上面就运行很慢。</span></p><p>&nbsp;</p><p><span style="font-size:14.0pt;font-family:宋体;;;color:black">对于问题二，如上面普及常识所言，不同的</span><span style="font-size:14.0pt;color:black">jvm</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">可以有不同的实现，不同的优化。与</span><span style="font-size:14.0pt;color:black">C</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">语言不同之处在于，</span><span style="font-size:14.0pt;color:black">java</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">的局部变量区在运行一个方法的时候已经分配好了，不需要遇到一个新变量就去分配。另外一点，因为由</span><span style="font-size:14.0pt;color:black">jvm</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">来执行，这种循环是</span><span style="font-size:14.0pt;color:black">jvm</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">内部是存在优化余地的，譬如，对于里层的循环变量，在重新下一次循环时就没用了，一些</span><span style="font-size:14.0pt;color:black">jvm</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">实现就可以重用这个变量。一些</span><span style="font-size:14.0pt;color:black">JVM</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">可能是纯粹的解释执行字节码，一些</span><span style="font-size:14.0pt;color:black">JVM</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">可能在启动的时候就把字节码编译成</span><span style="font-size:14.0pt;color:black">c++</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">本地代码，一些</span><span style="font-size:14.0pt;color:black">jvm</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">可能用纯硬件芯片来执行指令集，还有一些</span><span style="font-size:14.0pt;color:black">jvm</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">在运行了一段时间后找出程序热区，仔细优化并将这部分代码编译成</span><span style="font-size:14.0pt;color:black">c++</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">本地代码来达到最佳效果。所有你能想到的优化都可以在这里做掉。所以不同的</span><span style="font-size:14.0pt;color:black">jvm</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">实现对于这样的代码效率可能会有很大的差别。</span></p><p><span style="font-size:14.0pt;font-family:宋体;;;color:black">经过本人实测（循环体是数值计算），</span><span style="font-size:14.0pt;color:black">IBM J9 1.6</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">中两种都很快，</span><span style="font-size:14.0pt;color:black">Sun hotspot</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">跟</span><span style="font-size:14.0pt;color:black">J91.6</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">相比不是一个数量级的。但是</span><span style="font-size:14.0pt;color:black">IBM J9 1.5</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">的实现则相当的慢，跟</span><span style="font-size:14.0pt;color:black">hotspot</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">比慢的不是一个数量级。有兴趣的可能分别试试</span><span style="font-size:14.0pt;color:black">openJDK</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">，</span><span style="font-size:14.0pt;color:black">IBM J9</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">，</span><span style="font-size:14.0pt;color:black">Jrockit&nbsp;</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">这些实现的</span><span style="font-size:14.0pt;color:black">1.5</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">和</span><span style="font-size:14.0pt;color:black">1.6</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">版本的效率，另外一些</span><span style="font-size:14.0pt;color:black">jvm</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">还有</span><span style="font-size:14.0pt;color:black">server</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">和</span><span style="font-size:14.0pt;color:black">client</span><span style="font-size:14.0pt;font-family:宋体;;;color:black">运行版本的区别，效率也是大不一样的</span></p><p>&nbsp;</p><p><span style="font-size:14.0pt;font-family:宋体;;;color:black">总结，隔了一层虚拟机，什么都有可能！</span></p></div><img src ="http://www.blogjava.net/zhb8015/aggbug/380629.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zhb8015/" target="_blank">zhb8015</a> 2012-06-12 17:47 <a href="http://www.blogjava.net/zhb8015/articles/380629.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>javap </title><link>http://www.blogjava.net/zhb8015/articles/380628.html</link><dc:creator>zhb8015</dc:creator><author>zhb8015</author><pubDate>Tue, 12 Jun 2012 09:38:00 GMT</pubDate><guid>http://www.blogjava.net/zhb8015/articles/380628.html</guid><wfw:comment>http://www.blogjava.net/zhb8015/comments/380628.html</wfw:comment><comments>http://www.blogjava.net/zhb8015/articles/380628.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zhb8015/comments/commentRss/380628.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zhb8015/services/trackbacks/380628.html</trackback:ping><description><![CDATA[<div><div id="cnblogs_post_body"><p>一直在学习Java,碰到了很多问题，碰到了很多关于i++和++i的难题，以及最经典 的String str = "abc" 共创建了几个对象的疑难杂症。 知道有一日知道了java的反汇编 命令&nbsp;  javap。现将学习记录做一小结，以供自己以后翻看。如果有错误的地方，请指正</p>  <p><strong>1.javap是什么：</strong></p> <p><strong></strong></p> <p>&nbsp;where options include:<br />-c Disassemble the code<br />-classpath &lt;pathlist&gt; Specify where to find user class files<br />-extdirs &lt;dirs&gt; Override location of installed extensions<br />-help Print this usage message<br />-J&lt;flag&gt; Pass &lt;flag&gt; directly to the runtime system<br />-l Print line number and local variable tables<br />-public Show only public classes and members<br />-protected Show protected/public classes and members<br />-package Show package/protected/public classes<br />and members (default)<br />-private Show all classes and members<br />-s Print internal type signatures<br />-bootclasspath &lt;pathlist&gt; Override location of class files loaded<br />by the bootstrap class loader<br />-verbose Print stack size, number of locals and args for met<br />hods<br />If verifying, print reasons for failure　</p> <p>以上为百度百科里对它的描述，只是介绍了javap的一些参数和使用方法，而我们要用的就是这一个：-c Disassemble the code。</p>  <p><span style="color: #ff0000;">明确一个问题：javap是什么？</span>网上有人称之为 反汇编器，可以查看java编译器为我们生成的字节码。通过它，我们可以对照源代码和字节码，从而了解很多编译器内部的工作。</p>  <p><strong>2.初步认识javap</strong></p> <p>从一个最简单的例子开始：</p> <p>&nbsp;<img src="http://p.blog.csdn.net/images/p_blog_csdn_net/luckyp/EntryImages/20090609/2009-06-09_164137.jpg" alt="" height="244" width="510" /></p>  <p>&nbsp;这个例子中，我们只是简单的声明了两个int型变量并赋上初值。下面我们看看javap给我们带来了什么：（当然执行javap命令前，你得首先配置好自己的环境，能用javac编译通过了，即：<span style="color: #008080;"><strong>javac TestJavap.java</strong> </span>)</p> <p><img src="http://p.blog.csdn.net/images/p_blog_csdn_net/luckyp/EntryImages/20090609/1.jpg" alt="" height="329" width="621" /></p>  <p>我们只看（方便起见，将注释写到每句后面）</p> <p><strong>&nbsp; Code:<br />&nbsp;&nbsp; 0:&nbsp;&nbsp; iconst_2</strong>&nbsp;&nbsp;&nbsp; <span style="color: #339966;">//把2放到栈顶<br /></span><strong>&nbsp;&nbsp; 1:&nbsp;&nbsp; istore_1</strong>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #339966;">//把栈顶的值放到局部变量1中，即i中<br /></span><strong>&nbsp;&nbsp; 2:&nbsp;&nbsp; iconst_3</strong>&nbsp;&nbsp;&nbsp;<span style="color: #339966;"> //把3放到栈顶<br /></span><strong>&nbsp;&nbsp; 3:&nbsp;&nbsp; istore_2</strong>&nbsp;&nbsp;&nbsp; <span style="color: #339966;">//把栈顶的值放到局部变量1中，即j中<br /></span><strong>&nbsp;&nbsp; 4:&nbsp;&nbsp; return</strong></p> <p><strong></strong></p> <p>是不是很简单？（当然，估计需要点数据结构的知识） ，那我们就补点java的关于堆栈的知识：</p> <p>对于 int i = 2;首先它会在栈中创建一个变量为i的引用，然后查找有没有字面值为2的地址，没找到，就开辟一个存放2这个字面值的地址，然后将i指向2的地址。</p> <p>看了这段话，再比较下上面的注释，是不是完全吻合？</p>  <p>为了验证上面这一说法，我们继续实验：</p>  <p><img src="http://p.blog.csdn.net/images/p_blog_csdn_net/luckyp/EntryImages/20090609/2.jpg" alt="" height="268" width="417" /></p> <p>我们将 i 和 j的值都设为2。按照以上理论，在声明j的时候，会去栈中招有没有字面值为2的地址，由于在栈中已经有2这个字面值，便将j直接指向2的地址。这样，就出现了i与j同时均指向2的情况。 </p>  <p>&nbsp;拿出javap -c进行反编译：结果如下：</p> <p><img src="http://p.blog.csdn.net/images/p_blog_csdn_net/luckyp/EntryImages/20090609/3.jpg" alt="" height="336" width="567" /></p>  <p><strong>&nbsp; Code:<br />&nbsp;&nbsp; 0:&nbsp;&nbsp; iconst_2&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #339966;">//把2放到栈顶</span><br />&nbsp;&nbsp; 1:&nbsp;&nbsp; istore_1&nbsp;&nbsp;&nbsp; <span style="color: #339966;">//把栈顶的值放到局部变量1中，即i中</span><br />&nbsp;&nbsp; 2:&nbsp;&nbsp; iconst_2&nbsp;&nbsp;&nbsp; <span style="color: #339966;">//把2放到栈顶</span><br />&nbsp;&nbsp; 3:&nbsp;&nbsp; istore_2&nbsp;&nbsp;&nbsp; <span style="color: #339966;">//把栈顶的值放到局部变量2中，即j中(i 和 j同时指向2)</span><br />&nbsp;&nbsp; 4:&nbsp;&nbsp; return</strong></p> <p><strong></strong></p>  <p>虽然这里说i和j同时指向2，但这里不等于说i和j指向同一块地址（java是不允许程序员直接修改堆栈中的数据的，所以就不要想着，我是不是可以 修改栈中的2，那样岂不是i和j的值都会变化。另：在编译器内部，遇到j=2；时，它就会重新搜索栈中是否有2的字面值，如果没有，重新开辟地址存放2的 值；如果已经有了，则直接将j指向这个地址。因此,就算j另被赋值为其他值，如j=4,j值的改变不会影响到i的值。）</p>  <p>再来一个例子：</p> <p><img src="http://p.blog.csdn.net/images/p_blog_csdn_net/luckyp/EntryImages/20090609/4.jpg" alt="" height="259" width="424" /></p> <p>还是javap -c</p> <p><img src="http://p.blog.csdn.net/images/p_blog_csdn_net/luckyp/EntryImages/20090609/5.jpg" alt="" height="332" width="550" /></p>  <p>&nbsp; Code:<br />&nbsp;&nbsp; 0:&nbsp;&nbsp; iconst_2&nbsp;&nbsp;&nbsp; <span style="color: #339966;"><strong>//把2放到栈顶</strong></span><br />&nbsp;&nbsp; 1:&nbsp;&nbsp; istore_1&nbsp;&nbsp;&nbsp; <span style="color: #339966;"><strong>//把栈顶的值放到局部变量1中，即i中</strong></span><br />&nbsp;&nbsp; 2:&nbsp;&nbsp; iload_1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="widows: 2; text-transform: none; text-indent: 0px; border-collapse: separate; font: 16px Simsun; white-space: normal; orphans: 2; letter-spacing: normal; color: #000000; word-spacing: 0px; -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;"><span style="text-align: left; line-height: 18px; font-family: verdana; font-size: 12px;"><strong><span style="color: #339966;">//</span><span style="color: #339966;">把i的值放到栈顶，也就是说此时栈顶的值是2</span></strong></span></span><br />&nbsp;&nbsp; 3:&nbsp;&nbsp; istore_2&nbsp;&nbsp;&nbsp; <span style="color: #339966;"><strong>//把栈顶的值放到局部变量2中，即j中</strong></span><br />&nbsp;&nbsp; 4:&nbsp;&nbsp; return</p>  <p>看到这里是不是有点明确了？</p></div></div><img src ="http://www.blogjava.net/zhb8015/aggbug/380628.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zhb8015/" target="_blank">zhb8015</a> 2012-06-12 17:38 <a href="http://www.blogjava.net/zhb8015/articles/380628.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java对象池技术（Jakarta对象池）</title><link>http://www.blogjava.net/zhb8015/articles/380624.html</link><dc:creator>zhb8015</dc:creator><author>zhb8015</author><pubDate>Tue, 12 Jun 2012 08:55:00 GMT</pubDate><guid>http://www.blogjava.net/zhb8015/articles/380624.html</guid><wfw:comment>http://www.blogjava.net/zhb8015/comments/380624.html</wfw:comment><comments>http://www.blogjava.net/zhb8015/articles/380624.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zhb8015/comments/commentRss/380624.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zhb8015/services/trackbacks/380624.html</trackback:ping><description><![CDATA[<div>http://www.blogjava.net/baoyaer/articles/218460.html</div><img src ="http://www.blogjava.net/zhb8015/aggbug/380624.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zhb8015/" target="_blank">zhb8015</a> 2012-06-12 16:55 <a href="http://www.blogjava.net/zhb8015/articles/380624.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>浅谈java内存模型 (转 经经典)</title><link>http://www.blogjava.net/zhb8015/articles/380581.html</link><dc:creator>zhb8015</dc:creator><author>zhb8015</author><pubDate>Tue, 12 Jun 2012 03:29:00 GMT</pubDate><guid>http://www.blogjava.net/zhb8015/articles/380581.html</guid><wfw:comment>http://www.blogjava.net/zhb8015/comments/380581.html</wfw:comment><comments>http://www.blogjava.net/zhb8015/articles/380581.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zhb8015/comments/commentRss/380581.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zhb8015/services/trackbacks/380581.html</trackback:ping><description><![CDATA[<div>http://www.blogjava.net/qileilove/archive/2011/09/22/359262.html</div><br /><br /><div><p align="center">&nbsp;不同的平台，内存模型是不一样的，但是jvm的内存模型规范是统一的。其实java的多线程并发问题最终都会反映在java的内存模型上，<span style="color: red">所谓线程安全无非是要控制多个线程对某个资源的有序访问或修改。总结java的内存模型</span>，要解决两个主要的问题：<span style="color: red">可见性和有序性</span>。<br />我们都知道计算机有高速缓存的存在，处理器并不是每次处理数据都是取内存的。JVM定义了自己的内存模型，屏蔽了底层平台内存管理细节，对于java开发人员，要清楚在jvm内存模型的基础上，如果解决多线程的可见性和有序性。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #ff0000">那么，何谓可见性？</span> <span style="color: red">多个线程之间是不能互相传递数据通信的，它们之间的沟通只能通过共享变量来进行。</span>Java内存模型（JMM）规定了jvm有主内存，<span style="color: red">主内存是多个线程共享的</span>。当new一个对象的时候，也是被分配在主内存中，每个线程都有自己的工作内存，工作内存存储了主存的某些对象的副本，当然线程的工作内存大小是有限制的。当线程操作某个对象时，执行顺序如下：<br /><span style="color: #3366ff">&nbsp;(1) 从主存复制变量到当前工作内存 (read and load)<br />&nbsp;(2) 执行代码，改变共享变量值 (use and assign)<br />&nbsp;(3) 用工作内存数据刷新主存相关内容 (store and write)</span> </p> <p><span style="font-size: small">JVM规范定义了线程对主存的操作指令：read，load，use，assign，store，write。当一个共享变量在多个线程的工作内存中都有副本时，如果一个线程修改了这个共享变量，那么其他线程应该能够看到这个被修改后的值，这就是多线程的可见性问题。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #ff0000">那么，什么是有序性呢</span>   ？线程在引用变量时不能直接从主内存中引用,如果线程工作内存中没有该变量,则会从主内存中拷贝一个副本到工作内存中,这个过程为read-load,完 成后线程会引用该副本。当同一线程再度引用该字段时,有可能重新从主存中获取变量副本(read-load-use),也有可能直接引用原来的副本  (use),也就是说 read,load,use顺序可以由JVM实现系统决定。<br />&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  线程不能直接为主存中中字段赋值，它会将值指定给工作内存中的变量副本(assign),完成后这个变量副本会同步到主存储区(store-  write)，至于何时同步过去，根据JVM实现系统决定.有该字段,则会从主内存中将该字段赋值到工作内存中,这个过程为read-load,完成后线 程会引用该变量副本，当同一线程多次重复对字段赋值时,比如：<br /></span></p> <p align="center">&nbsp;</p> <div> <div> <div>Java代码 <a title="复制代码" href="http://www.iteye.com/topic/806990#"><img alt="复制代码" src="http://www.iteye.com/images/icon_copy.gif" /></a>&nbsp;<a title="收藏这段代码"><img alt="收藏代码" src="http://www.iteye.com/images/icon_star.png" /></a></div></div> <ol><li>for(int&nbsp;i=0;i&lt;10;i++) &nbsp;&nbsp;</li><li>&nbsp;a++;&nbsp;&nbsp;</li></ol></div> <p align="center">&nbsp;</p> <p align="center">&nbsp; </p> <p><span style="font-size: small"><br />线程有可能只对工作内存中的副本进行赋 值,只到最后一次赋值后才同步到主存储区，所以assign,store,weite顺序可以由JVM实现系统决定。假设有一个共享变量x，线程a执行 x=x+1。从上面的描述中可以知道x=x+1并不是一个原子操作，它的执行过程如下：<br /><span style="color: #3366ff">1 从主存中读取变量x副本到工作内存<br />2 给x加1<br />3 将x加1后的值写回主</span> 存<br />如果另外一个线程b执行x=x-1，执行过程如下：<br /><span style="color: #3366ff">1 从主存中读取变量x副本到工作内存<br />2 给x减1<br />3 将x减1后的值写回主存</span> <br />那么显然，最终的x的值是不可靠的。假设x现在为10，线程a加1，线程b减1，从表面上看，似乎最终x还是为10，但是多线程情况下会有这种情况发生：<br /><span style="color: #3366ff">1：线程a从主存读取x副本到工作内存，工作内存中x值为10<br />2：线程b从主存读取x副本到工作内存，工作内存中x值为10<br />3：线程a将工作内存中x加1，工作内存中x值为11<br />4：线程a将x提交主存中，主存中x为11<br />5：线程b将工作内存中x值减1，工作内存中x值为9<br />6：线程b将x提交到中主存中，主存中x为9</span> <br />同样，x有可能为11，如果x是一个银行账户，线程a存款，线程b扣款，显然这样是有严重问题的，要解决这个问题，必须保证线程a和线程b是有序执行的，并且每个线程执行的加1或减1是一个原子操作。看看下面代码：<br /></span></p> <p align="center">&nbsp;</p> <div> <div> <div>Java代码 <a title="复制代码" href="http://www.iteye.com/topic/806990#"><img alt="复制代码" src="http://www.iteye.com/images/icon_copy.gif" /></a>&nbsp;<a title="收藏这段代码"><img alt="收藏代码" src="http://www.iteye.com/images/icon_star.png" /></a></div></div> <ol><li>public&nbsp;class&nbsp;Account&nbsp;{ &nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;int&nbsp;balance; &nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;Account(int&nbsp;balance)&nbsp;{ &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.balance&nbsp;=&nbsp;balance; &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;int&nbsp;getBalance()&nbsp;{ &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;balance; &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;add(int&nbsp;num)&nbsp;{ &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;balance&nbsp;=&nbsp;balance&nbsp;+&nbsp;num; &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;withdraw(int&nbsp;num)&nbsp;{ &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;balance&nbsp;=&nbsp;balance&nbsp;-&nbsp;num; &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args)&nbsp;throws&nbsp;InterruptedException&nbsp;{ &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Account&nbsp;account&nbsp;=&nbsp;new&nbsp;Account(1000); &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread&nbsp;a&nbsp;=&nbsp;new&nbsp;Thread(new&nbsp;AddThread(account,&nbsp;20),&nbsp;"add"); &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread&nbsp;b&nbsp;=&nbsp;new&nbsp;Thread(new&nbsp;WithdrawThread(account,&nbsp;20),&nbsp;"withdraw"); &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a.start(); &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b.start(); &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a.join(); &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b.join(); &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(account.getBalance()); &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;static&nbsp;class&nbsp;AddThread&nbsp;implements&nbsp;Runnable&nbsp;{ &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Account&nbsp;account; &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;amount; &nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;AddThread(Account&nbsp;account,&nbsp;int&nbsp;amount)&nbsp;{ &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.account&nbsp;=&nbsp;account; &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.amount&nbsp;=&nbsp;amount; &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;run()&nbsp;{ &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(int&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;200000;&nbsp;i++)&nbsp;{ &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;account.add(amount); &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;static&nbsp;class&nbsp;WithdrawThread&nbsp;implements&nbsp;Runnable&nbsp;{ &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Account&nbsp;account; &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;amount; &nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;WithdrawThread(Account&nbsp;account,&nbsp;int&nbsp;amount)&nbsp;{ &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.account&nbsp;=&nbsp;account; &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.amount&nbsp;=&nbsp;amount; &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;run()&nbsp;{ &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(int&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;100000;&nbsp;i++)&nbsp;{ &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;account.withdraw(amount); &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</li><li>}&nbsp;&nbsp;</li></ol></div> <p align="center">&nbsp;</p> <p align="center">&nbsp; </p> <p><span style="font-size: small"><br />第一次执行结果为10200，第二次执行 结果为1060，每次执行的结果都是不确定的，因为线程的执行顺序是不可预见的。这是java同步产生的根源，synchronized关键字保证了多个 线程对于同步块是互斥的，synchronized作为一种同步手段，解决java多线程的执行有序性和内存可见性，而volatile关键字之解决多线 程的内存可见性问题。后面将会详细介绍。</span> </p> <p><span style="font-size: small"><br /></span></p> <p><span style="font-size: small"><br /><span style="font-size: medium"><strong>synchronized关键字</strong> </span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 上面说了，java用synchronized关键字做为多线程并发环境的执行有序性的保证手段之一。当一段代码会修改共享变量，这一段代码成为互斥区或临界区，为了保证共享变量的正确性，synchronized标示了临界区。典型的用法如下：<br /></span></p> <p align="center">&nbsp;</p> <div> <div> <div>Java代码 <a title="复制代码" href="http://www.iteye.com/topic/806990#"><img alt="复制代码" src="http://www.iteye.com/images/icon_copy.gif" /></a>&nbsp;<a title="收藏这段代码"><img alt="收藏代码" src="http://www.iteye.com/images/icon_star.png" /></a></div></div> <ol><li>synchronized(锁){ &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;临界区代码 &nbsp;&nbsp;</li><li>}&nbsp;&nbsp;&nbsp;</li></ol></div> <p align="center">&nbsp;</p> <p align="center">&nbsp; </p> <p><span style="font-size: small"><br />为了保证银行账户的安全，可以操作账户的方法如下：<br /></span></p> <p align="center">&nbsp;</p> <div> <div> <div>Java代码 <a title="复制代码" href="http://www.iteye.com/topic/806990#"><img alt="复制代码" src="http://www.iteye.com/images/icon_copy.gif" /></a>&nbsp;<a title="收藏这段代码"><img alt="收藏代码" src="http://www.iteye.com/images/icon_star.png" /></a></div></div> <ol><li>public&nbsp;synchronized&nbsp;void&nbsp;add(int&nbsp;num)&nbsp;{ &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;balance&nbsp;=&nbsp;balance&nbsp;+&nbsp;num; &nbsp;&nbsp;</li><li>} &nbsp;&nbsp;</li><li>public&nbsp;synchronized&nbsp;void&nbsp;withdraw(int&nbsp;num)&nbsp;{ &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;balance&nbsp;=&nbsp;balance&nbsp;-&nbsp;num; &nbsp;&nbsp;</li><li>}&nbsp;&nbsp;</li></ol></div> <p align="center">&nbsp;</p> <p align="center">&nbsp; </p> <p><span style="font-size: small"><br />刚才不是说了synchronized的用法是这样的吗：<br /></span></p> <p align="center">&nbsp;</p> <div> <div> <div>Java代码 <a title="复制代码" href="http://www.iteye.com/topic/806990#"><img alt="复制代码" src="http://www.iteye.com/images/icon_copy.gif" /></a>&nbsp;<a title="收藏这段代码"><img alt="收藏代码" src="http://www.iteye.com/images/icon_star.png" /></a></div></div> <ol><li>synchronized(锁){ &nbsp;&nbsp;</li><li>临界区代码 &nbsp;&nbsp;</li><li>}&nbsp;&nbsp;</li></ol></div> <p align="center">&nbsp;</p> <p align="center">&nbsp; </p> <p><span style="font-size: small"><br />那么对于public  synchronized void add(int  num)这种情况，意味着什么呢？其实这种情况，锁就是这个方法所在的对象。同理，如果方法是public&nbsp; static synchronized  void add(int num)，那么锁就是这个方法所在的class。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 理论上，每个对象都可以做为锁，但一个对象做为锁时，应该被多个线程共享，这样才显得有意义，在并发环境下，一个没有共享的对象作为锁是没有意义的。假如有这样的代码：<br /></span></p> <p align="center">&nbsp;</p> <div> <div> <div>Java代码 <a title="复制代码" href="http://www.iteye.com/topic/806990#"><img alt="复制代码" src="http://www.iteye.com/images/icon_copy.gif" /></a>&nbsp;<a title="收藏这段代码"><img alt="收藏代码" src="http://www.iteye.com/images/icon_star.png" /></a></div></div> <ol><li>public&nbsp;class&nbsp;ThreadTest{ &nbsp;&nbsp;</li><li>&nbsp;&nbsp;public&nbsp;void&nbsp;test(){ &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Object&nbsp;lock=new&nbsp;Object(); &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;synchronized&nbsp;(lock){ &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//do&nbsp;something &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</li><li>&nbsp;&nbsp;} &nbsp;&nbsp;</li><li>}&nbsp;&nbsp;</li></ol></div> <p align="center">&nbsp;</p> <p align="center">&nbsp; </p> <p><span style="font-size: small"><br /><span style="color: red">lock变量作为一个锁存在根本没有意义，因为它根本不是共享对象，每个线程进来都会执行Object lock=new Object();每个线程都有自己的lock，根本不存在锁竞争。</span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  每个锁对象都有两个队列，一个是就绪队列，一个是阻塞队列，就绪队列存储了将要获得锁的线程，阻塞队列存储了被阻塞的线程，当一个被线程被唤醒  (notify)后，才会进入到就绪队列，等待cpu的调度。当一开始线程a第一次执行account.add方法时，jvm会检查锁对象account   的就绪队列是否已经有线程在等待，如果有则表明account的锁已经被占用了，由于是第一次运行，account的就绪队列为空，所以线程a获得了锁， 执行account.add方法。如果恰好在这个时候，线程b要执行account.withdraw方法，因为线程a已经获得了锁还没有释放，所以线程  b要进入account的就绪队列，等到得到锁后才可以执行。<br /><span style="color: red">一个线程执行临界区代码过程如下：</span><br /><span style="color: red">1 获得同步锁</span><br /><span style="color: red">2 清空工作内存</span><br /><span style="color: red">3 从主存拷贝变量副本到工作内存</span><br /><span style="color: red">4 对这些变量计算</span><br /><span style="color: red">5 将变量从工作内存写回到主存</span><br /><span style="color: red">6 释放锁</span><br />可见，synchronized既保证了多线程的并发有序性，又保证了多线程的内存可见性。<br /><br /><br /><span style="font-size: medium"><strong>生产者/消费者模式</strong> </span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 生产者/消费者模式其实是一种很经典的线程同步模型，很多时候，并不是光保证多个线程对某共享资源操作的互斥性就够了，往往多个线程之间都是有协作的。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   假设有这样一种情况，有一个桌子，桌子上面有一个盘子，盘子里只能放一颗鸡蛋，A专门往盘子里放鸡蛋，如果盘子里有鸡蛋，则一直等到盘子里没鸡蛋，B专门 从盘子里拿鸡蛋，如果盘子里没鸡蛋，则等待直到盘子里有鸡蛋。其实盘子就是一个互斥区，每次往盘子放鸡蛋应该都是互斥的，A的等待其实就是主动放弃锁，B  等待时还要提醒A放鸡蛋。<br />如何让线程主动释放锁<br />很简单，调用锁的wait()方法就好。wait方法是从Object来的，所以任意对象都有这个方法。看这个代码片段：<br /></span></p> <p align="center">&nbsp;</p> <div> <div> <div>Java代码 <a title="复制代码" href="http://www.iteye.com/topic/806990#"><img alt="复制代码" src="http://www.iteye.com/images/icon_copy.gif" /></a>&nbsp;<a title="收藏这段代码"><img alt="收藏代码" src="http://www.iteye.com/images/icon_star.png" /></a></div></div> <ol><li>Object&nbsp;lock=new&nbsp;Object();//声明了一个对象作为锁 &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;synchronized&nbsp;(lock)&nbsp;{ &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;balance&nbsp;=&nbsp;balance&nbsp;-&nbsp;num; &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//这里放弃了同步锁，好不容易得到，又放弃了 &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lock.wait(); &nbsp;&nbsp;</li><li>}&nbsp;&nbsp;</li></ol></div> <p align="center">&nbsp;</p> <p align="center">&nbsp; </p> <p><span style="font-size: small"><br />如果一个线程获得了锁lock，进入了同步块，执行lock.wait()，那么这个线程会进入到lock的阻塞队列。如果调用 lock.notify()则会通知阻塞队列的某个线程进入就绪队列。<br />声明一个盘子，只能放一个鸡蛋<br /></span></p> <p align="center">&nbsp; </p> <div> <div> <div>Java代码 <a title="复制代码" href="http://www.iteye.com/topic/806990#"><img alt="复制代码" src="http://www.iteye.com/images/icon_copy.gif" /></a>&nbsp;<a title="收藏这段代码"><img alt="收藏代码" src="http://www.iteye.com/images/icon_star.png" /></a></div></div> <ol><li>import&nbsp;java.util.ArrayList; &nbsp;&nbsp;</li><li>import&nbsp;java.util.List; &nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>public&nbsp;class&nbsp;Plate&nbsp;{ &nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;List&lt;Object&gt;&nbsp;eggs&nbsp;=&nbsp;new&nbsp;ArrayList&lt;Object&gt;(); &nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;synchronized&nbsp;Object&nbsp;getEgg()&nbsp;{ &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(eggs.size()&nbsp;==&nbsp;0)&nbsp;{ &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try&nbsp;{ &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wait(); &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;catch&nbsp;(InterruptedException&nbsp;e)&nbsp;{ &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Object&nbsp;egg&nbsp;=&nbsp;eggs.get(0); &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;eggs.clear();//&nbsp;清空盘子 &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;notify();//&nbsp;唤醒阻塞队列的某线程到就绪队列 &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("拿到鸡蛋"); &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;egg; &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;synchronized&nbsp;void&nbsp;putEgg(Object&nbsp;egg)&nbsp;{ &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(eggs.size()&nbsp;&gt;&nbsp;0)&nbsp;{ &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try&nbsp;{ &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wait(); &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;catch&nbsp;(InterruptedException&nbsp;e)&nbsp;{ &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;eggs.add(egg);//&nbsp;往盘子里放鸡蛋 &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;notify();//&nbsp;唤醒阻塞队列的某线程到就绪队列 &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("放入鸡蛋"); &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;static&nbsp;class&nbsp;AddThread&nbsp;extends&nbsp;Thread{ &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;Plate&nbsp;plate; &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;Object&nbsp;egg=new&nbsp;Object(); &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;AddThread(Plate&nbsp;plate){ &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.plate=plate; &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;run(){ &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(int&nbsp;i=0;i&lt;5;i++){ &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;plate.putEgg(egg); &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;static&nbsp;class&nbsp;GetThread&nbsp;extends&nbsp;Thread{ &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;Plate&nbsp;plate; &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;GetThread(Plate&nbsp;plate){ &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.plate=plate; &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;run(){ &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(int&nbsp;i=0;i&lt;5;i++){ &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;plate.getEgg(); &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String&nbsp;args[]){ &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try&nbsp;{ &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Plate&nbsp;plate=new&nbsp;Plate(); &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread&nbsp;add=new&nbsp;Thread(new&nbsp;AddThread(plate)); &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread&nbsp;get=new&nbsp;Thread(new&nbsp;GetThread(plate)); &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;add.start(); &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;get.start(); &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;add.join(); &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;get.join(); &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;catch&nbsp;(InterruptedException&nbsp;e)&nbsp;{ &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace(); &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("测试结束"); &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</li><li>}&nbsp;&nbsp;</li></ol></div> <p align="center">&nbsp;</p> <p><span style="font-size: small">&nbsp; 执行结果：</span> </p> <p align="center">&nbsp;</p> <div> <div> <div>Html代码 <a title="复制代码" href="http://www.iteye.com/topic/806990#"><img alt="复制代码" src="http://www.iteye.com/images/icon_copy.gif" /></a>&nbsp;<a title="收藏这段代码"><img alt="收藏代码" src="http://www.iteye.com/images/icon_star.png" /></a></div></div> <ol><li>放入鸡蛋 &nbsp;&nbsp;</li><li>拿到鸡蛋 &nbsp;&nbsp;</li><li>放入鸡蛋 &nbsp;&nbsp;</li><li>拿到鸡蛋 &nbsp;&nbsp;</li><li>放入鸡蛋 &nbsp;&nbsp;</li><li>拿到鸡蛋 &nbsp;&nbsp;</li><li>放入鸡蛋 &nbsp;&nbsp;</li><li>拿到鸡蛋 &nbsp;&nbsp;</li><li>放入鸡蛋 &nbsp;&nbsp;</li><li>拿到鸡蛋 &nbsp;&nbsp;</li><li>测试结束&nbsp;&nbsp;</li></ol></div> <p align="center">&nbsp;</p> <p align="center">&nbsp; </p> <p>&nbsp;</p> <p><span style="font-size: small"><br />声明一个Plate对象为plate，被线程A和线程B共享，A专门放鸡蛋，B专门拿鸡蛋。假设<br /><span style="color: #3366ff">1 开始，A调用plate.putEgg方法，此时eggs.size()为0，因此顺利将鸡蛋放到盘子，还执行了notify()方法，唤醒锁的阻塞队列的线程，此时阻塞队列还没有线程。<br />2 又有一个A线程对象调用plate.putEgg方法，此时eggs.size()不为0，调用wait()方法，自己进入了锁对象的阻塞队列。<br />3   此时，来了一个B线程对象，调用plate.getEgg方法，eggs.size()不为0，顺利的拿到了一个鸡蛋，还执行了notify()方法，唤 醒锁的阻塞队列的线程，此时阻塞队列有一个A线程对象，唤醒后，它进入到就绪队列，就绪队列也就它一个，因此马上得到锁，开始往盘子里放鸡蛋，此时盘子是 空的，因此放鸡蛋成功。<br />4 假设接着来了线程A，就重复2；假设来料线程B，就重复3。</span> <br />整个过程都保证了放鸡蛋，拿鸡蛋，放鸡蛋，拿鸡蛋。</span> </p> <p><span style="font-size: small"><br /></span></p> <p><span style="font-size: small"><br /><span style="font-size: medium"><strong>volatile关键字</strong> </span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; volatile是java提供的一种同步手段，只不过它是轻量级的同步，为什么这么说，因为<span style="color: red">volatile只能保证多线程的内存可见性，不能保证多线程的执行有序性。</span>而 最彻底的同步要保证有序性和可见性，例如synchronized。任何被volatile修饰的变量，都不拷贝副本到工作内存，任何修改都及时写在主 存。因此对于Valatile修饰的变量的修改，所有线程马上就能看到，但是volatile不能保证对变量的修改是有序的。什么意思呢？假如有这样的代 码：<br /></span></p> <p align="center">&nbsp;</p> <div> <div> <div>Java代码 <a title="复制代码" href="http://www.iteye.com/topic/806990#"><img alt="复制代码" src="http://www.iteye.com/images/icon_copy.gif" /></a>&nbsp;<a title="收藏这段代码"><img alt="收藏代码" src="http://www.iteye.com/images/icon_star.png" /></a></div></div> <ol><li>public&nbsp;class&nbsp;VolatileTest{ &nbsp;&nbsp;</li><li>&nbsp;&nbsp;public&nbsp;volatile&nbsp;int&nbsp;a; &nbsp;&nbsp;</li><li>&nbsp;&nbsp;public&nbsp;void&nbsp;add(int&nbsp;count){ &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a=a+count; &nbsp;&nbsp;</li><li>&nbsp;&nbsp;} &nbsp;&nbsp;</li><li>}&nbsp;&nbsp;</li></ol></div> <p align="center">&nbsp;</p> <p align="center">&nbsp; </p> <p><span style="font-size: small"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当一个VolatileTest对象被多个线程共享，a的值不一定是正确的，因为a=a+count包含了好几步操作，而此时多个线程的执行是无序的，因为没有任何机制来保证多个线程的执行有序性和原子性。volatile存在的意义是，<span style="color: red">任何线程对a的修改，都会马上被其他线程读取到，因为直接操作主存，没有线程对工作内存和主存的同步。</span>所以，volatile的使用场景是有限的，在有限的一些情形下可以使用 volatile 变量替代锁。要使 volatile 变量提供理想的线程安全,必须同时满足下面两个条件:<br /><span style="color: #3366ff">1)对变量的写操作不依赖于当前值。<br />2)该变量没有包含在具有其他变量的不变式中</span> <br />volatile只保证了可见性，所以Volatile适合直接赋值的场景，如<br /></span></p> <p align="center">&nbsp;</p> <div> <div> <div>Java代码 <a title="复制代码" href="http://www.iteye.com/topic/806990#"><img alt="复制代码" src="http://www.iteye.com/images/icon_copy.gif" /></a>&nbsp;<a title="收藏这段代码"><img alt="收藏代码" src="http://www.iteye.com/images/icon_star.png" /></a></div></div> <ol><li>public&nbsp;class&nbsp;VolatileTest{ &nbsp;&nbsp;</li><li>&nbsp;&nbsp;public&nbsp;volatile&nbsp;int&nbsp;a; &nbsp;&nbsp;</li><li>&nbsp;&nbsp;public&nbsp;void&nbsp;setA(int&nbsp;a){ &nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.a=a; &nbsp;&nbsp;</li><li>&nbsp;&nbsp;} &nbsp;&nbsp;</li><li>}&nbsp;&nbsp;</li></ol></div> <p align="center">&nbsp;</p> <p align="center">&nbsp; </p> <p><span style="font-size: small"><br />在没有volatile声明时，多线程环 境下，a的最终值不一定是正确的，因为this.a=a;涉及到给a赋值和将a同步回主存的步骤，这个顺序可能被打乱。如果用volatile声明了，读 取主存副本到工作内存和同步a到主存的步骤，相当于是一个原子操作。所以简单来说，volatile适合这种场景<span style="color: red">：一个变量被多个线程共享，线程直接给这个变量赋值。这是一种很简单的同步场景，这时候使用volatile的开销将会非常小。<span style="font-size: small">站内很多人都问我，所谓线程的&#8220;工作内存&#8221;到底是个什么东西？有的人认为是线程的栈，其实这种理解是不正确的。看看JLS（java语言规范）对线程工作内存的描述，线程的working memory只是cpu的寄存器和高速缓存的抽象描述。</span> </span></span></p> <p>&nbsp;</p> <p><span style="font-size: small">&nbsp;&nbsp;<span style="font-size: small">&nbsp;&nbsp;&nbsp; 可能</span> </span><span style="font-size: small">很 多人都觉得莫名其妙，说JVM的内存模型，怎么会扯到cpu上去呢？在此，我认为很有必要阐述下，免得很多人看得不明不白的。先抛开java虚拟机不谈， 我们都知道，现在的计算机，cpu在计算的时候，并不总是从内存读取数据，它的数据读取顺序优先级是：寄存器－高速缓存－内存。线程耗费的是CPU，线程 计算的时候，原始的数据来自内存，在计算过程中，有些数据可能被频繁读取，这些数据被存储在寄存器和高速缓存中，当线程计算完后，这些缓存的数据在适当的 时候应该写回内存。当个多个线程同时读写某个内存数据时，就会产生多线程并发问题，涉及到三个特性：原子性，有序性，可见性。在《线程安全总结》这篇文章 中，为了理解方便，我把原子性和有序性统一叫做&#8220;多线程执行有序性&#8221;。支持多线程的平台都会面临这种问题，运行在多线程平台上支持多线程的语言应该提供解 决该问题的方案。</span> </p> <p>&nbsp;</p> <p><span style="font-size: small">&nbsp;&nbsp;</span> <span style="font-size: small">&nbsp;&nbsp;&nbsp; <span style="font-size: small">那么，我们看看JVM，JVM是一个虚拟的计算机，它也会面临多线程并发问题，java程序运行在java虚拟机平台上，java程序员不可能直接去控制底层线程对寄存器高速缓存内存之间的同步，那么java从语法层面，应该给开发人员提供一种解决方案，这个方案就是诸如</span> </span><span style="font-size: small"><span style="font-size: small"><span style="font-size: medium"><strong>synchronized,</strong> </span></span><span style="font-size: small"><span style="font-size: medium"><strong>volatile,锁机制（如同步块，就绪队列，阻塞队列）等等。这些方案只是语法层面的，但我们要从本质上去理解它，不能仅仅知道一个</strong> </span></span></span><span style="font-size: small"><span style="font-size: small"><span style="font-size: medium"><span style="font-size: small"><strong>synchronized 可以保证同步就完了。</strong></span> </span></span>&nbsp; 在这里我说的是jvm的内存模型，是动态的，面向多线程并发的，沿袭JSL的&#8220;working memory&#8221;的说法，只是不想牵扯到太多底层细节，因为</span> <span style="font-size: small">《线程安全总结》这篇文章意在说明怎样从语法层面去理解java的线程同步，知道各个关键字的使用场景。</span> </p> <p>&nbsp;</p> <p><span style="font-size: small">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-size: small">今 天有人问我，那java的线程不是有栈吗？难道栈不是工作内存吗？工作内存这四个字得放到具体的场景中描述，方能体现它具体的意义，在描述JVM的线程同 步时，工作内存指的是寄存器和告诉缓存的抽象描述，具体请自行参阅JLS。上面讲的都是动态的内存模型，甚至已经超越了JVM的范围，那么JVM的内存静 态存储是怎么划分的？今天还有人问我，jvm的内存模型不是有eden区吗？也不见你提起。我跟他说，这是两个角度去看的，甚至是两个不同的范围，动态的 线程同步的内存模型，涵盖了cpu，寄存器，高速缓存，内存；JVM的静态内存储模型只是一种对内存的物理划分而已，它只局限在内存，而且只局限在JVM 的内存。那些什么线程栈，eden区都仅仅在JVM内存。</span> </p> <p>&nbsp;</p> <p><span style="font-size: small">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 说说JVM的线程栈和有个朋友反复跟我纠结的eden区吧。JVM的内存，被划分了很多的区域：</span></p> <p><span style="font-size: small"><strong>1.程序计数器</strong><br /><span style="color: #3366ff">每一个Java线程都有一个程序计数器来用于保存程序执行到当前方法的哪一个指令。</span><br /><strong>2.线程栈</strong><br /><span style="color: #3366ff">线 程的每个方法被执行的时候，都会同时创建一个帧（Frame）用于存储本地变量表、操作栈、动态链接、方法出入口等信息。每一个方法的调用至完成，就意味 着一个帧在VM栈中的入栈至出栈的过程。如果线程请求的栈深度大于虚拟机所允许的深度，将抛出StackOverflowError异常；如果VM栈可以 动态扩展（VM Spec中允许固定长度的VM栈），当扩展时无法申请到足够内存则抛出OutOfMemoryError异常。</span><br /><strong>3.本地方法栈<br />4.堆</strong><br /><span style="color: #3366ff">每 个线程的栈都是该线程私有的，堆则是所有线程共享的。当我们new一个对象时，该对象就被分配到了堆中。但是堆，并不是一个简单的概念，堆区又划分了很多 区域，为什么堆划分成这么多区域，这是为了JVM的内存垃圾收集，似乎越扯越远了，扯到垃圾收集了，现在的jvm的gc都是按代收集，堆区大致被分为三大 块：新生代，旧生代，持久代（虚拟的）；新生代又分为eden区，s0区，s1区。新建一个对象时，基本小的对象，生命周期短的对象都会放在新生代的 eden区中，eden区满时，有一个小范围的gc（minor gc），整个新生代满时，会有一个大范围的gc（major  gc），将新生代里的部分对象转到旧生代里。</span><br /><strong>5.方法区 </strong><br /><span style="color: #3366ff">其 实就是永久代（Permanent Generation），方法区中存放了每个Class的结构信息，包括常量池、字段描述、方法描述等等。VM  Space描述中对这个区域的限制非常宽松，除了和Java堆一样不需要连续的内存，也可以选择固定大小或者可扩展外，甚至可以选择不实现垃圾收集。相对 来说，垃圾收集行为在这个区域是相对比较少发生的，但并不是某些描述那样永久代不会发生GC（至  少对当前主流的商业JVM实现来说是如此），这里的GC主要是对常量池的回收和对类的卸载，虽然回收的&#8220;成绩&#8221;一般也比较差强人意，尤其是类卸载，条件相 当苛刻。</span><br /><strong>6.常量池</strong><br /><span style="color: #3366ff">&nbsp;Class 文件中除了有类的版本、字段、方法、接口等描述等信息外，还有一项信息是常量表(constant_pool  table)，用于存放编译期已可知的常量，这部分内容将在类加载后进入方法区（永久代）存放。但是Java语言并不要求常量一定只有编译期预置入 Class的常量表的内容才能进入方法区常量池，运行期间也可将新内容放入常量池（最典型的String.intern()方法）。</span></span></p> <p style="margin: 10.5pt 0cm 10.5pt 21pt;">&nbsp;</p> <p><span style="font-size: small">关于垃圾收集，在此不多说，流到垃圾收集那一章再 详细说吧。关于java的同步，其实还有基于CPU原语的比较并交换的非阻塞算法（CAS），不过这个在java的并发包里已经实现了很多，因此关于这 点，就留到java并发包那一章介绍吧。后面我会专门写一篇文章，JVM内存与垃圾收集。<br /></span></p></div><img src ="http://www.blogjava.net/zhb8015/aggbug/380581.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zhb8015/" target="_blank">zhb8015</a> 2012-06-12 11:29 <a href="http://www.blogjava.net/zhb8015/articles/380581.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>设计模式大集锦 程序员面试(转)</title><link>http://www.blogjava.net/zhb8015/articles/380159.html</link><dc:creator>zhb8015</dc:creator><author>zhb8015</author><pubDate>Wed, 06 Jun 2012 09:33:00 GMT</pubDate><guid>http://www.blogjava.net/zhb8015/articles/380159.html</guid><wfw:comment>http://www.blogjava.net/zhb8015/comments/380159.html</wfw:comment><comments>http://www.blogjava.net/zhb8015/articles/380159.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zhb8015/comments/commentRss/380159.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zhb8015/services/trackbacks/380159.html</trackback:ping><description><![CDATA[<p>&nbsp;</p>
<h1>设计模式大集锦 程序员面试全攻略</h1>
<p><a href="http://sd.csdn.net/a/20120604/2806324.html">http://sd.csdn.net/a/20120604/2806324.html</a><br /><br />无论你是参与Java面试还是C#面试，设计模式和软件设计问题在程序员面试中是必不可少的一部分。编程和设计技两者相得益彰，一名出色的程序员也是一名出色的设计师，他们懂得如何利用代码来解决问题或者软件设计，但是这些技能需要不断提升。这就要求你不断的保持设计理念，无论编程项目的大小，从失败中总结经验。</p>
<p>从面向对象的设计原则开始学习是个不错的起点。本文总结了在各种面试过程中经常被提及的一些设计问题。文中分为两部分，一类为初学者，另一类专为中高级技术人员准备。</p>
<p style="text-align: center"><img style="cursor: pointer" border="0" alt="" src="http://articles.csdn.net/uploads/allimg/120604/94_120604161718_1.jpg" width="400" height="410" /></p>
<p><span style="font-size: larger"><strong>一、入门级程序员的面试题：</strong></span></p>
<p>这些软件设计和设计模式的先关问题大多会出现在初学者面试情景中，什么是设计模式？特定的设计模式又是什么？等等这些概念，也许你很轻易回答这些概念，但文内提供的这些问题也许能给你带来更多价值。</p>
<p><strong>1. 什么是设计模式？在你编码过程中使用了哪些设计模式？</strong></p>
<p>每位程序员都会利用自身经历来回答这些特定的设计问题。设计模式是代码重用的扩展。</p>
<p><strong>2. 你能说出在标准的JDK库中使用的一些设计模式吗？</strong></p>
<p><a href="http://javarevisited.blogspot.com/2011/11/decorator-design-pattern-java-example.html" target="_blank">Decorator设计模式</a>常被用于各种Java IO类中，Singleton模式常被用在运行环节中，Calendar以及各种其他类，Factory（工厂）模式常被用于各种不可变类，比如Boolean。Boolean.valueOf和Observer模式常被用于Swing和许多事件监听器框架中。</p>
<p><strong>3. 在Java中Singleton设计模式是什么？为线程安全Singleton编码。</strong></p>
<p>Singleton模式在整个系统中主要是共享模式。在整个应用程序实例中只保持一个特定的类，这是由所以模块共享决定的。Java.lang.Runtime是Singleton设计模式中一个典型范例。关于此问题你可以<a href="http://javarevisited.blogspot.com/2011/03/10-interview-questions-on-singleton.html" target="_blank">查看</a>更多。从Java 5版本开始，你可以为安全线程singleton模式使用<a href="http://javarevisited.blogspot.com/2011/08/enum-in-java-example-tutorial.html" target="_blank">enum</a>。</p>
<p><strong>4. 使用Factory模式主要优势是什么？你会在哪种情况下使用？</strong></p>
<p>Factory模式最主要的优势在于当创建对象时可提高封装水平。如果你使用Factory模式来创建对象，你可以在后期重置最初产品的装置或者无须任何客户层就可实现更先进更高性能的类。可以查看我曾发表过的有关<a href="http://javarevisited.blogspot.com/2011/12/factory-design-pattern-java-example.html" target="_blank">Factory模式</a>的更多细节及优点。</p>
<p><strong>5. Java中Observer设计模式是什么？</strong></p>
<p>Observer设计模式基于对象的变化而改变。比如：天气系统，在这里必须将天气变化的视图呈现给观众。这里天气项目是主体而非不同的观察者。通过这篇<a href="http://javarevisited.blogspot.sg/2011/12/observer-design-pattern-java-example.html" target="_blank">文章</a>，查看在Java中Observer模式。</p>
<p><strong>6. 例举一个在Java中使用Decorator模式的案例？它从事的是对象级别还是类级别？</strong></p>
<p>Decorator模式可提高个体对象的能力。Java IO广泛使用Decorator模式和Buffered类型的一些经典例子，比如BufferedReader和BufferedWriter，增强读者和作家执行Buffer级别的阅读和写作从而提高性能。了解<a href="http://javarevisited.blogspot.com/2011/11/decorator-design-pattern-java-example.html" target="_blank">更多</a>。</p>
<p><strong>7. 什么是MVC设计模式？请例举一个MVC设计模式案例。</strong></p>
<p><strong>8. Java中FrontController设计模式是什么？请例举一个FrontController设计模式案例。</strong></p>
<p><strong>9. Responsibility设计模式是什么？</strong></p>
<p><strong>10. Adapter设计模式是什么？请例举一个在Java中的Adapter设计模式案例。</strong></p>
<p><span style="font-size: larger"><strong>二、进阶级程序员的面试题：</strong></span></p>
<p><strong>1. 举例说明你什么时候会用抽象类，什么时候更愿意使用接口？</strong></p>
<p>这是一个很常见的面试问题，并不算难。接口和抽象类都按照&#8220;不为实现写代码&#8221;的设计原则，这是为了增加代码的灵活性，以应付不断变化的要求。下面是一些帮助你回答这个问题的指南：</p>
<ul><li>在Java中，你只能继承一个类，但实现多个接口。所以你继承一个类的时候就无法再继承别的类了。</li><li>接口是用来代表形容词或行为，例如Runnable、Clonable、Serializable等。因此，如果您使用一个抽象类来实现Runnable和Clonacle，你就不可以使你的类同时实现这两个功能，而如果接口的话就没问题。</li><li>抽象类是比接口稍快，所以很在乎时间的应用尽量使用抽象类。</li><li>如果多个继承层次的共同行为在在同一个地方编写更好，那么抽象类会是更好的选择。有时候可以在接口里定义函数但是在抽象类里默认功能就能实现接口和抽象类共同工作了。了解<a href="http://javarevisited.blogspot.com/2012/04/10-points-on-interface-in-java-with.html" target="_blank">Java接口</a>。</li></ul>
<p><strong>2. 设计一个能接收不同硬币、出售不同货物的自动售货机。</strong></p>
<p>这是一个比较开放的设计问题，你可以使用它练习文档设计、写代码和JUnit单元测试，而不是仅仅是解决问题。这道题的目标绝不会仅仅是想测出你多久能够得到解决方案。理想情况下，这个问题应该在3小时内给出一个可工作版本。</p>
<p><strong>3. 你有一个Smartphone类和它派生类iPhone、 AndroidPhone、WindowsPhone等，以及以品牌名称命名的派生类如SonyPhone等。你该如何设计这一类的系统？</strong></p>
<p>这是另一种设计模式的练习，你充分利用面向对象的设计技巧，保证它有足够的灵活性来支持新产品，并且在现有模型改变时能够保证足够的稳定性。</p>
<p><strong>4. 在Java中，什么时候该使用overload，什么时候使用override？</strong></p>
<p>对于一个经验丰富的设计师来说这是一个非常简单的问题。重载和覆盖在Java里实现的都是同一个功能，但overload的输入变量不同，override则完全相同。</p>
<p><strong>5. 设计ATM机</strong></p>
<p>我们几乎都使用过ATM机，但你想过该怎么设计它吗？金融系统的设计原则之一就是必须能在所有预期情况下都能够正常运行。所以无论是发生断电还是什么其它暴力问题，ATM机都必须能够保证正确的状态。 考虑下锁、事务处理、错误状态、临界条件等等。即使你拿不定确切的设计方案，但是能够指出非功能性需求、提出一些问题或者考虑考虑临界条件都会对你有帮助。</p>
<p><strong>6. 假设你正在设计市场数据类来保证能够切换不同的信息供应商，比如Reuters、wombat等等，或者直接交换信息，你该如何设计这个市场信息系统？</strong></p>
<p>这是非常有趣的设计面试问题，实际上在大型投资银行里是个很普遍的问题。关键在于你需要提供拥有getBid()、getPrice()和getLevel()方法的MarketData接口供客户请求，同时还需要有一个使用依赖注入的MarketDataProvider组件。这样在你改变MarketDataProvider时就不会对系统产生影响，因为客户是通过MarketData接口或者类调用方法的。</p>
<p><strong>7. 为什么Java里不允许从静态方法中获取非静态变量？</strong></p>
<p>Java里不允许从静态方法中获取非静态变量仅仅是因为非静态变量会和特定的对象实例相关联，而静态变量不会。你也可以看看<a href="http://javarevisited.blogspot.com/2012/02/why-non-static-variable-cannot-be.html" target="_blank">这篇文章</a>的详细解释。</p>
<p><strong>8. 用Java设计一个并发规则管道？</strong></p>
<p>并发编程和并行设计非常热门，因为它能更高效地利用现在越来越先进的处理器，而且Java被认为是多线程语言也主要因为此原因。设计一个并发系统的关键在于线程安全、不可变性、本地变量，还有避免使用局部变量和实例变量。你只需要保证多个线程能够在同一时间执行同一个类，所以最佳解决方案就是每个线程只操作自己的数据，尽量使用最小的同步，尤其是在管道开始时。这个问题可以从初始讨论到最终类和接口的编写实现，但是只要你记得注意并发问题的关键，比如<a href="http://javarevisited.blogspot.com/2012/02/what-is-race-condition-in.html" target="_blank">竞争状态</a>、<a href="http://javarevisited.blogspot.com/2010/10/what-is-deadlock-in-java-how-to-fix-it.html" target="_blank">死锁</a>、内存冲突、原子操作、<a href="http://javarevisited.blogspot.com/2012/05/how-to-use-threadlocal-in-java-benefits.html" target="_blank">ThreadLocal</a>变量等等，尽量绕过这些问题。</p>
<p>以上这些设计模式经常出现在面试环节中，比如Google，Amazon, Microsoft等。如果您在面试过程中遇到了一些有趣的话题，不妨与我们分享下。</p><img src ="http://www.blogjava.net/zhb8015/aggbug/380159.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zhb8015/" target="_blank">zhb8015</a> 2012-06-06 17:33 <a href="http://www.blogjava.net/zhb8015/articles/380159.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>什么是hashcode    （转） </title><link>http://www.blogjava.net/zhb8015/articles/379568.html</link><dc:creator>zhb8015</dc:creator><author>zhb8015</author><pubDate>Wed, 30 May 2012 08:31:00 GMT</pubDate><guid>http://www.blogjava.net/zhb8015/articles/379568.html</guid><wfw:comment>http://www.blogjava.net/zhb8015/comments/379568.html</wfw:comment><comments>http://www.blogjava.net/zhb8015/articles/379568.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zhb8015/comments/commentRss/379568.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zhb8015/services/trackbacks/379568.html</trackback:ping><description><![CDATA[<div>                                              <strong>什么是hashcode</strong>&nbsp;&nbsp;&nbsp; （转）&nbsp;&nbsp; <div>http://www.iteye.com/topic/838030</div><br />&nbsp;&nbsp;&nbsp;  分析HashMap之前先介绍下什么Hashcode(散列码)。它是一个int，每个对象都会有一个hashcode，它在内存的存放位置是放在对象的 头部（对象头部存放的信息有hashcode，指向Class的引用，和一些有关垃圾回收信息）。具体如何生成hashcode，这个相当复杂，由于我们 的主题是&#8220;浅析&#8221;，所以不深入探讨。有个问题需要讲的是，如果在你的类中覆盖了Object的equals(Object)方法，那么你必须覆盖 hashCode方法，不然，当你使用HashMap，HashSet，HashTable时会出现问题。具体原因下文会详细描述。 <br /><strong>String类的hashcode</strong> <br />&nbsp;&nbsp;&nbsp;  String类重写了Object类中的equals和hashCode方法，原因很简单，Object中的equals方法是指比较两个对象是不是指向 同一个引用对象，而String类指需要比较内容相不相等就可以了。所以String覆盖了equals方法，同时覆盖了hashCode方法。这里需要 提一下Object规范里规定：如果两个对象根据equals(Object)方式是相等的，那么这两个对象的hashCode一定要相等。 <br />String中的hashcode算法很简单如下： <br /><div id=""><div><div>Java代码 &nbsp;<a title="收藏这段代码"><img src="http://www.iteye.com/images/icon_star.png" alt="收藏代码" /></a></div></div><ol start="1"><li><span>for&nbsp;(int&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;len;&nbsp;i++)&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;h&nbsp;=&nbsp;<span>31*h&nbsp;+&nbsp;val[off++];&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li></ol></div> <br />Val是一个char[]，存放的是字符串的各个字符；Len是字符串长度；off从0开始；h从0开始。比如一个字符串&#8220;abc&#8221;(a的ascii码是97)，它的hashcode算法是： <br />h = 31 * 0 + 97 ==&gt; h = 97; <br />h = 31 * 97 + 98 ==&gt; h = 3105; <br />h = 31 * 3105 + 99 ==&gt; h = 96354; <br />所以&#8220;abc&#8221;的hashCode就是96354 <br /><strong>存储方式</strong> <br />&nbsp;&nbsp;&nbsp; 列表的存储方式是基于数组，如下图： <br /><img src="http://dl.iteye.com/upload/attachment/364586/1a9c44da-41a4-368d-8c54-5532a58daa47.jpg"  alt="" /> <br /> <br />&nbsp;&nbsp;&nbsp; 链表的存储方式是基于指针，如下图：（单向链表） <br /><img src="http://dl.iteye.com/upload/attachment/364588/7319d809-a000-331f-96da-760f1785ca0e.jpg"  alt="" /> <br /> <br />&nbsp;&nbsp;&nbsp; HashMap的存储方式是上面两种的结合，如下图： <br /><img src="http://dl.iteye.com/upload/attachment/364590/1c28849c-b67c-3461-b48f-54bd4b023b53.jpg"  alt="" /> <br /> <br /><strong>HashMap的存取</strong> <br />&nbsp;&nbsp;&nbsp; HashMap的功能是通过&#8220;键(key)&#8221;能够快速的找到&#8220;值&#8221;。下面我们分析下HashMap存数据的基本流程： <br />&nbsp;&nbsp;&nbsp; 1、	当调用put(key,value)时，首先获取key的hashcode，int hash = key.hashCode(); <br />&nbsp;&nbsp;&nbsp; 2、	再把hash通过一下运算得到一个int h. <br />hash ^= (hash &gt;&gt;&gt; 20) ^ (hash &gt;&gt;&gt; 12); <br />int h = hash ^ (hash &gt;&gt;&gt; 7) ^ (hash &gt;&gt;&gt; 4); <br />为什么要经过这样的运算呢？这就是HashMap的高明之处。先看个例子，一个十进制数32768(二进制1000 0000 0000  0000)，经过上述公式运算之后的结果是35080(二进制1000 1001 0000  1000)。看出来了吗？或许这样还看不出什么，再举个数字61440(二进制1111 0000 0000  0000)，运算结果是65263(二进制1111 1110 1110  1111)，现在应该很明显了，它的目的是让&#8220;1&#8221;变的均匀一点，散列的本意就是要尽量均匀分布。那这样有什么意义呢？看第3步。 <br />&nbsp;&nbsp;&nbsp; 3、	 得到h之后，把h与HashMap的承载量（HashMap的默认承载量length是16，可以自动变长。在构造HashMap的时候也可以指定一个长 度。这个承载量就是上图所描述的数组的长度。）进行逻辑与运算，即 h &amp;  (length-1)，这样得到的结果就是一个比length小的正数，我们把这个值叫做index。其实这个index就是索引将要插入的值在数组中的 位置。第2步那个算法的意义就是希望能够得出均匀的index，这是HashTable的改进，HashTable中的算法只是把key的 hashcode与length相除取余，即hash %  length，这样有可能会造成index分布不均匀。还有一点需要说明，HashMap的键可以为null，它的值是放在数组的第一个位置。 <br />&nbsp;&nbsp;&nbsp; 4、	 我们用table[index]表示已经找到的元素需要存储的位置。先判断该位置上有没有元素（这个元素是HashMap内部定义的一个类Entity， 基本结构它包含三个类，key，value和指向下一个Entity的next）,没有的话就创建一个Entity&lt;K,V&gt;对象，在 table[index]位置上插入，这样插入结束；如果有的话，通过链表的遍历方式去逐个遍历，看看有没有已经存在的key，有的话用新的value替 换老的value；如果没有，则在table[index]插入该Entity，把原来在table[index]位置上的Entity赋值给新的 Entity的next，这样插入结束。 <br />再回头看看前面提到的为什么覆盖了equals方法之后一定要覆盖hashCode方法，很简单，比如，String a = new  String(&#8220;abc&#8221;);String b = new  String(&#8220;abc&#8221;);如果不覆盖hashCode的话，那么a和b的hashCode就会不同，把这两个类当做key存到HashMap中的话就 会出现问题，就会和key的唯一性相矛盾。 <br /> <br />&nbsp;&nbsp;&nbsp; HashMap取的过程也类似。太累了，不写了。赶紧结束。 <br />&nbsp;&nbsp;&nbsp; 文中可能会有错误的地方请指出，谢谢！ <br /> </div><img src ="http://www.blogjava.net/zhb8015/aggbug/379568.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zhb8015/" target="_blank">zhb8015</a> 2012-05-30 16:31 <a href="http://www.blogjava.net/zhb8015/articles/379568.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>hashcode面试题 </title><link>http://www.blogjava.net/zhb8015/articles/379565.html</link><dc:creator>zhb8015</dc:creator><author>zhb8015</author><pubDate>Wed, 30 May 2012 08:08:00 GMT</pubDate><guid>http://www.blogjava.net/zhb8015/articles/379565.html</guid><wfw:comment>http://www.blogjava.net/zhb8015/comments/379565.html</wfw:comment><comments>http://www.blogjava.net/zhb8015/articles/379565.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zhb8015/comments/commentRss/379565.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zhb8015/services/trackbacks/379565.html</trackback:ping><description><![CDATA[<div><dl><dt>Java code</dt><dd><pre><div><span style="color: #0000FF;">public</span> <span style="color: #0000FF;">class</span><span style="color: #000000;"> ValuePair {    </span><span style="color: #0000FF;">public</span> <span style="color: #0000FF;">int</span><span style="color: #000000;"> a </span><span style="color: #000000;">=</span> <span style="color: #000000;">4</span><span style="color: #000000;">,b;    </span><span style="color: #0000FF;">public</span> <span style="color: #0000FF;">boolean</span><span style="color: #000000;"> equals(Object other){       </span><span style="color: #0000FF;">try</span><span style="color: #000000;">{          ValuePair o </span><span style="color: #000000;">=</span><span style="color: #000000;"> (ValuePair) other;          </span><span style="color: #0000FF;">return</span><span style="color: #000000;"> (a</span><span style="color: #000000;">==</span><span style="color: #000000;">o.a</span><span style="color: #000000;">&amp;&amp;</span><span style="color: #000000;">b</span><span style="color: #000000;">==</span><span style="color: #000000;">o.b)</span><span style="color: #000000;">||</span><span style="color: #000000;">(a</span><span style="color: #000000;">==</span><span style="color: #000000;">o.b</span><span style="color: #000000;">&amp;&amp;</span><span style="color: #000000;">b</span><span style="color: #000000;">==</span><span style="color: #000000;">o.a);       }</span><span style="color: #0000FF;">catch</span><span style="color: #000000;">(ClassCastException cce){          </span><span style="color: #0000FF;">return</span> <span style="color: #0000FF;">false</span><span style="color: #000000;">;       }    }    </span><span style="color: #0000FF;">public</span> <span style="color: #0000FF;">int</span><span style="color: #000000;"> hashCode(){       </span><span style="color: #008000;">//</span><span style="color: #008000;">请选择下边的答案（多选）</span><span style="color: #008000;"> </span><span style="color: #000000;">   } }</span></div> </pre></dd></dl><br />A。return 0;<br />B. return a;<br />C. return a+b;<br />D. return a-b;<br />E. return a^b;<br />F. return (a&lt;&lt;16)|b;<br />请说明理由。</div><br /><br /><div>根据一般约定，如果2个对象 equals 比较为true,那么hashCode也最好(不是必须)相同。<br /> &nbsp;             如果2个对象 equals 比如为false,那么hashCode也最好(不是必须)不同<br /><br /><br />因此对于这个题目，如果从纯语法层面考虑，全部都是可选的<br />但是从程序运行效率来看，最好是该hashCode里，a,b值可以互换，而又尽可能做到不同的a,b值返回不同的值。因为C,E最好.<br /> &nbsp;&nbsp; <br />A。return 0;       效率太低<br />B. return a;       不满足a,b的互换性<br />D. return a-b;     不满足a,b的互换性<br />F. return (a &lt; &lt;16)|b; 不满足a,b的互换性<br /><br />另外，比如 a * b  也满足互换性，但是效率稍低，毕竟没加法和位运算快<br /><br /><br /><div>* Whenever it is invoked on the same object more than once during an  execution of a Java application, the hashCode method must consistently  return the same integer, provided no information used in equals  comparisons on the object is modified. This integer need not remain  consistent from one execution of an application to another execution of  the same application.&nbsp; <br /> &nbsp;   * If two objects are equal according to  the equals(Object) method, then calling the hashCode method on each of  the two objects must produce the same integer result.&nbsp; <br /> &nbsp;   * It is  not required that if two objects are unequal according to the  equals(java.lang.Object) method, then calling the hashCode method on  each of the two objects must produce distinct integer results. However,  the programmer should be aware that producing distinct integer results  for unequal objects may improve the performance of hashtables.&nbsp; </div></div><img src ="http://www.blogjava.net/zhb8015/aggbug/379565.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zhb8015/" target="_blank">zhb8015</a> 2012-05-30 16:08 <a href="http://www.blogjava.net/zhb8015/articles/379565.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JVM小结</title><link>http://www.blogjava.net/zhb8015/articles/376935.html</link><dc:creator>zhb8015</dc:creator><author>zhb8015</author><pubDate>Sat, 28 Apr 2012 02:45:00 GMT</pubDate><guid>http://www.blogjava.net/zhb8015/articles/376935.html</guid><wfw:comment>http://www.blogjava.net/zhb8015/comments/376935.html</wfw:comment><comments>http://www.blogjava.net/zhb8015/articles/376935.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zhb8015/comments/commentRss/376935.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zhb8015/services/trackbacks/376935.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 1、&nbsp;Java总体（java编程语言、java&nbsp;API、java文件格式和虚拟机） 12、&nbsp;java虚拟机结束生命周期 13、&nbsp;类的加载、连接和初始化 24、&nbsp;java对类的使用方式分为两种： 24、&nbsp;类的加载 25、&nbsp;加载.class文件的方式 26、&nbsp;两种类加载器 37、&nbsp;类的...&nbsp;&nbsp;<a href='http://www.blogjava.net/zhb8015/articles/376935.html'>阅读全文</a><img src ="http://www.blogjava.net/zhb8015/aggbug/376935.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zhb8015/" target="_blank">zhb8015</a> 2012-04-28 10:45 <a href="http://www.blogjava.net/zhb8015/articles/376935.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JVM内存管理机制</title><link>http://www.blogjava.net/zhb8015/articles/376780.html</link><dc:creator>zhb8015</dc:creator><author>zhb8015</author><pubDate>Fri, 27 Apr 2012 07:58:00 GMT</pubDate><guid>http://www.blogjava.net/zhb8015/articles/376780.html</guid><wfw:comment>http://www.blogjava.net/zhb8015/comments/376780.html</wfw:comment><comments>http://www.blogjava.net/zhb8015/articles/376780.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zhb8015/comments/commentRss/376780.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zhb8015/services/trackbacks/376780.html</trackback:ping><description><![CDATA[<div id="blog_content" class="blog_content">
<h2>1.JVM内存管理的机制</h2>
<p>&nbsp;</p>
<p>内存空间划分为：Sun JDK在实现时遵照JVM规范，将内存空间划分为堆、JVM方法栈、方法区、本地方法栈、PC寄存器。</p>
<ul><li>堆：堆用于存储对象实例及数组值，可以认为Java中所有通过new创建的对象的内存都在此分配，Heap中对象所占用的内存由GC进行回收，在32位操作系统上最大为2GB，在64位操作系统上则没有限制，其大小可通过-Xms和-Xmx来控制，-Xms为JVM启动时申请的最小Heap内存，默认为物理内存的1/64但小于1GB；-Xmx为JVM可申请的最大Heap内存，默认为物理内存的1/4但小于1GB，默认当空余堆内存小于40%时，JVM会增大Heap到-Xmx指定的大小，可通过-XX:MinHeapFreeRatio=来指定这个比例；当空余堆内存大于70%时，JVM会减小Heap的大小到-Xms指定的大小，可通过-XX:MaxHeapFreeRatio=来指定这个比例，对于运行系统而言，为避免在运行时频繁调整Heap 的大小，通常将-Xms和-Xmx的值设成一样。</li></ul>
<ul><li>JVM方法栈：为线程私有，其在内存分配上非常高效。当方法运行完毕时，其对应的栈帧所占用的内存也会自动释放。当JVM方法栈空间不足时，会抛出StackOverflowError的错误，在Sun JDK中可以通过-Xss来指定其大小。</li></ul>
<ul><li>方法区：要加载的类的信息（名称、修饰符等）、类中的静态变量、类中定义为final类型的常量、类中的Field信息、类中的方法信息。方法区域也是全局共享的，在一定条件下它也会被GC，当方法区域要使用的内存超过其允许的大小时，会抛出OutOfMemory的错误信息。在Sun JDK中这块区域对应Permanet Generation，又称为持久代，默认最小值为16MB，最大值为64MB，可通过-XX:PermSize及-XX:MaxPermSize来指定最小值和最大值。</li></ul>
<ul><li>本地方法栈：用于支持native方法的执行，存储了每个native方法调用的状态。在Sun JDK的实现中，和JVM方法栈是同一个。</li></ul>
<ul><li>PC寄存器：占用的可能为CPU寄存器或操作系统内存。</li></ul>
<p>&nbsp;</p>
<h2>2.Java堆和栈的区别</h2>
<p>Java把内存划分成两种：一种是栈内存，一种是堆内存。</p>
<p>在函数中定义的一些基本类型的变量和对象的引用变量都在函数的栈内存中分配。当在一段代码块定义一个变量时，Java就在栈中为这个变量分配内存空间，当超过变量的作用域后，Java会自动释放掉为该变量所分配的内存空间，该内存空间可以立即被另作他用。</p>
<p>堆内存用来存放由new创建的对象和数组。在堆中分配的内存，由Java虚拟机的自动垃圾回收器来管理。在堆中产生了一个数组或对象后，还可以在栈中定义一个特殊的变量，让栈中这个变量的取值等于数组或对象在堆内存中的首地址，在栈中的这个特殊的变量就变成了数组或者对象的引用变量，以后就可以在程序中使用栈内存中的引用变量来访问堆中的数组或者对象，引用变量相当于为数组或者对象起的一个别名，或者代号。</p>
<p>引用变量是普通变量，定义时在栈中分配内存，引用变量在程序运行到作用域外释放。而数组＆对象本身在堆中分配，即使程序运行到使用new产生数组和对象的语句所在地代码块之外，数组和对象本身占用的堆内存也不会被释放，数组和对象在没有引用变量指向它的时候，才变成垃圾，不能再被使用，但是仍然占着内存，在随后的一个不确定的时间被垃圾回收器释放掉。这个也是java比较占内存的主要原因。但是在写程序的时候，可以人为的控制。</p>
<p>&nbsp;</p>
<h2>3.Java内存泄露和内存溢出</h2>
<p>内存泄漏：分配出去的内存回收不了</p>
<p>内存溢出：指系统内存不够用了</p>
<p>&nbsp;</p>
<h2>4.Java类加载机制</h2>
<p>JVM将类加载过程划分为三个步骤：装载、链接和初始化。</p>
<ol><li>装载（Load）：装载过程负责找到二进制字节码并加载至JVM中，JVM通过类的全限定名（com.bluedavy. HelloWorld）及类加载器（ClassLoaderA实例）完成类的加载；</li><li>链接（Link）：链接过程负责对二进制字节码的格式进行校验、初始化装载类中的静态变量及解析类中调用的接口、类；</li><li>初始化（Initialize）：执行类中的静态初始化代码、构造器代码及静态属性的初始化。</li></ol>
<h2>5.内存回收</h2>
<p>收集器：引用计数收集器、跟踪收集器</p>
<ul><li>引用计数收集器：对于Java这种面向对象的会形成复杂引用关系(如ObjectB和ObjectC互相引用)的语言而言，引用计数收集器不是非常适合，Sun JDK在实现GC时也未采用这种方式。</li></ul>
<ul><li>跟踪收集器实现算法：复制（Copying）、标记-清除（Mark-Sweep）和标记-压缩（Mark-Compact）</li></ul>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 复制：当要回收的空间中存活对象较少时，复制算法会比较高效，其带来的成本是要增加一块空的内存空间及进行对象的移动。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 标记-清除：在空间中存活对象较多的情况下较为高效，但由于标记-清除采用的为直接回收不存活对象所占用的内存，因此会造成内存碎片。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 标记-压缩：在标记-清除的基础上还须进行对象的移动，成本相对更高，好处则是不产生内存碎片。</p></div>
<div id="bottoms" class="clearfix"></div><img src ="http://www.blogjava.net/zhb8015/aggbug/376780.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zhb8015/" target="_blank">zhb8015</a> 2012-04-27 15:58 <a href="http://www.blogjava.net/zhb8015/articles/376780.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一场IBM面试题引发的讨论：创建String对象过程中【内存分配】(转)</title><link>http://www.blogjava.net/zhb8015/articles/376777.html</link><dc:creator>zhb8015</dc:creator><author>zhb8015</author><pubDate>Fri, 27 Apr 2012 07:42:00 GMT</pubDate><guid>http://www.blogjava.net/zhb8015/articles/376777.html</guid><wfw:comment>http://www.blogjava.net/zhb8015/comments/376777.html</wfw:comment><comments>http://www.blogjava.net/zhb8015/articles/376777.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zhb8015/comments/commentRss/376777.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zhb8015/services/trackbacks/376777.html</trackback:ping><description><![CDATA[<span style="line-height: 23px; background-color: rgb(255,255,255); font-family: simsun">前不久，一个IBM面试题的帖子引发了很多关于创建String对象过程中的内存分配的讨论，既然大家对这个问题这么感兴趣，那么这篇帖子就通过深入Java虚拟机(JVM)解读其内部指令流程，来分析创建String对象的几种情况下的内存分配过程。<br /><br />先来了解一下JVM运行时数据区的内存模型。<br />《深入Java虚拟机》书中是这样描述的：JVM运行时数据区的内存模型由五部分组成：<br />【1】方法区<br />【2】堆<br />【3】Java栈<br />【4】PC寄存器<br />【5】本地方法栈<br /><br />对于String s = "hello" ,它的虚拟机指令：<br /></span>
<dl style="padding-bottom: 0px; overflow-x: auto; overflow-y: auto; margin: 0px; padding-left: 0px; width: 718px; padding-right: 0px; font-size: 12px; padding-top: 0px">
<dt style="line-height: 24px; background-color: rgb(245,245,245); text-indent: 6px; height: 24px; color: rgb(51,51,51); font-weight: bold"><span style="line-height: 23px; background-color: rgb(255,255,255); font-family: simsun">Java code</span> 
<dd style="border-bottom: rgb(221,221,221) 1px solid; border-left: rgb(221,221,221) 1px solid; margin: 0px; border-top: rgb(221,221,221) 1px solid; border-right: rgb(221,221,221) 1px solid">
<div><span style="line-height: 18px; color: rgb(0,0,0)">0</span><span style="line-height: 18px; color: rgb(0,0,0)">: ldc #</span><span style="line-height: 18px; color: rgb(0,0,0)">16</span><span style="line-height: 18px; color: rgb(0,0,0)">;</span> <span style="line-height: 18px; color: rgb(0,128,0)">//</span><span style="line-height: 18px; color: rgb(0,128,0)">string hello</span> <span style="line-height: 18px; color: rgb(0,0,0)">2</span><span style="line-height: 18px; color: rgb(0,0,0)">: astore_1</span> <span style="line-height: 18px; color: rgb(0,0,0)">3</span><span style="line-height: 18px; color: rgb(0,0,0)">:</span> <span style="line-height: 18px; color: rgb(0,0,255)">return</span></div><pre> </pre></dd></dl><br />对于上面虚拟机指令，其各自的指令流程在《深入Java虚拟机》这样描述到(结合上面实例)：<br /><br />ldc指令格式：ldc,index<br />ldc指令过程：<br />要执行ldc指令，jvm首先查找index所指定的常量池入口，在index指向的常量池入口，jvm将会查找constant_integer_info，constant_float_info和constant_string_info入口。如果还没有这些入口，jvm会解析它们。而对于上面的hahajvm会找到constant_string_info入口，同时，将把指向被拘留String对象（由解析该入口的进程产生）的引用压入操作数栈。<br /><br />astore_1指令格式：astore_1<br />astore_1指令过程：<br />要执行astore_1指令，jvm从操作数栈顶部弹出一个引用类型或者returnaddress类型值，然后将该值存入由索引1指定的局部变量中,即将引用类型或者returnaddress类型值存入局部变量1。<br /><br />return 指令的过程：<br />从方法中返回，返回值为void。<br /><br />谈一下我个人理解：<br />从上面的ldc指令的执行过程可以得出：s的值是来自被拘留string对象（由解析该入口的进程产生）的引用，即可以理解为是从被拘留string对象的引用复制而来的，故我个人的理解是s的值是存在栈当中。上面是对于s值得分析，接着是对于"hello"值的分析,我们知道，对于string s = "hello" 其中"hello"值在java程序编译期就确定下来了的。简单一点说，就是haha的值在程序编译成class文件后，就在class文件中生成了（大家可以用ue编辑器或其它文本编辑工具在打开class文件后的字节码文件中看到这个hello值）。执行java程序的过程中，第一步是class文件生成，然后被jvm装载到内存执行。那么jvm装载这个class到内存中，其中的hello这个值，在内存中是怎么为其开辟空间并存储在哪个区域中呢？<br /><br />说到这里，我们不妨先来了解一下jvm常量池这个结构，《深入Java虚拟机》书中有这样的描述：<br /><br />常量池<br />虚拟机必须为每个被装载的类型维护一个常量池。常量池就是该类型所用到常量的一个有序集和，包括直接常量（string,integer和floating point常量）和对其他类型，字段和方法的符号引用。对于string常量，它的值是在常量池中的。而jvm中的常量池在内存当中是以表的形式存在的，对于string类型，有一张固定长度的constant_string_info表用来存储文字字符串值，注意：该表只存储文字字符串值，不存储符号引用。说到这里，对常量池中的字符串值的存储位置应该有一个比较明了的理解了。<br /><br />在介绍完jvm常量池的概念后，接着谈开始提到的"hello"的值的内存分布的位置。对于haha的值，实际上是在class文件被jvm装载到内存当中并被引擎在解析ldc指令并执行ldc指令之前，jvm就已经为haha这个字符串在常量池的constant_string_info表中分配了空间来存储hello这个值。既然hello这个字符串常量存储在常量池中，根据《深入java虚拟机》书中描述：常量池是属于类型信息的一部分，类型信息也就是每一个被转载的类型，这个类型反映到jvm内存模型中是对应存在于jvm内存模型的方法区中，也就是这个类型信息中的常量池概念是存在于在方法区中，而方法区是在jvm内存模型中的堆中由jvm来分配的。所以，hello的值是应该是存在堆空间中的。<br /><br />而对于string s = new string("hello") ,它的jvm指令：<br />
<dl style="padding-bottom: 0px; overflow-x: auto; overflow-y: auto; margin: 0px; padding-left: 0px; width: 718px; padding-right: 0px; font-size: 12px; padding-top: 0px">
<dt style="line-height: 24px; background-color: rgb(245,245,245); text-indent: 6px; height: 24px; color: rgb(51,51,51); font-weight: bold">Java code 
<dd style="border-bottom: rgb(221,221,221) 1px solid; border-left: rgb(221,221,221) 1px solid; margin: 0px; border-top: rgb(221,221,221) 1px solid; border-right: rgb(221,221,221) 1px solid">
<div><span style="line-height: 18px; color: rgb(0,0,0)">0</span><span style="line-height: 18px; color: rgb(0,0,0)">:</span> <span style="line-height: 18px; color: rgb(0,0,255)">new</span> <span style="line-height: 18px; color: rgb(0,0,0)">#</span><span style="line-height: 18px; color: rgb(0,0,0)">16</span><span style="line-height: 18px; color: rgb(0,0,0)">;</span> <span style="line-height: 18px; color: rgb(0,128,0)">//</span><span style="line-height: 18px; color: rgb(0,128,0)">class string</span> <span style="line-height: 18px; color: rgb(0,0,0)">3</span><span style="line-height: 18px; color: rgb(0,0,0)">: dup</span> <span style="line-height: 18px; color: rgb(0,0,0)">4</span><span style="line-height: 18px; color: rgb(0,0,0)">: ldc #</span><span style="line-height: 18px; color: rgb(0,0,0)">18</span><span style="line-height: 18px; color: rgb(0,0,0)">;</span> <span style="line-height: 18px; color: rgb(0,128,0)">//</span><span style="line-height: 18px; color: rgb(0,128,0)">string hello</span> <span style="line-height: 18px; color: rgb(0,0,0)">6</span><span style="line-height: 18px; color: rgb(0,0,0)">: invokespecial #</span><span style="line-height: 18px; color: rgb(0,0,0)">20</span><span style="line-height: 18px; color: rgb(0,0,0)">;</span> <span style="line-height: 18px; color: rgb(0,128,0)">//</span><span style="line-height: 18px; color: rgb(0,128,0)">method java/lang/string."":(ljava/lang/string;)v</span> <span style="line-height: 18px; color: rgb(0,0,0)">9</span><span style="line-height: 18px; color: rgb(0,0,0)">: astore_1</span> <span style="line-height: 18px; color: rgb(0,0,0)">10</span><span style="line-height: 18px; color: rgb(0,0,0)">:</span> <span style="line-height: 18px; color: rgb(0,0,255)">return</span></div><pre> </pre></dd></dl><br />对于上面虚拟机指令，其各自的指令流程在《深入java虚拟机》这样描述到(结合上面实例)：<br /><br />new指令格式：new indexbyte1,indexbyte2<br />new指令过程：<br />要执行new指令，jvm通过计算(indextype1&lt;&lt;8)|indextype2生成一个指向常量池的无符号16位索引。然后jvm根据计算出的索引查找常量池入口。该索引所指向的常量池入口必须为constant_class_info。如果该入口尚不存在，那么jvm将解析这个常量池入口，该入口类型必须是类。jvm从堆中为新对象映像分配足够大的空间，并将对象的实例变量设为默认值。最后jvm将指向新对象的引用objectref压入操作数栈。<br /><br />dup指令格式：dup<br />dup指令过程：<br />要执行dup指令，jvm复制了操作数栈顶部一个字长的内容，然后再将复制内容压入栈。本指令能够从操作数栈顶部复制任何单位字长的值。但绝对不要使用它来复制操作数栈顶部任何两个字长(long型或double型)中的一个字长。上面例中，即复制引用objectref，这时在操作数栈存在2个引用。<br /><br />ldc指令格式：ldc,index<br />ldc指令过程：<br />要执行ldc指令，jvm首先查找index所指定的常量池入口，在index指向的常量池入口，jvm将会查找constant_integer_info，constant_float_info和constant_string_info入口。如果还没有这些入口，jvm会解析它们。而对于上面的haha,jvm会找到constant_string_info入口，同时，将把指向被拘留string对象（由解析该入口的进程产生）的引用压入操作数栈。<br /><br />invokespecial指令格式：invokespecial,indextype1,indextype2<br />invokespecial指令过程：对于该类而言，该指令是用来进行实例初始化方法的调用。鉴于该指令篇幅，具体可以查阅《深入java虚拟机》中描述。上面例子中，即通过其中一个引用调用string类的构造器，初始化对象实例，让另一个相同的引用指向这个被初始化的对象实例，然后前一个引用弹出操作数栈。<br /><br />astore_1指令格式：astore_1<br />astore_1指令过程：<br />要执行astore_1指令，jvm从操作数栈顶部弹出一个引用类型或者returnaddress类型值，然后将该值存入由索引1指定的局部变量中,即将引用类型或者returnaddress类型值存入局部变量1。<br /><br />return 指令的过程:<br />从方法中返回，返回值为void。<br /><br />要执行astore_1指令，jvm从操作数栈顶部弹出一个引用类型或者returnaddress类型值，然后将该值存入由索引1指定的局部变量中,即将引用类型或者returnaddress类型值存入局部变量1。<br /><br />通过上面6个指令，可以看出，string s = new string("hello");中的hello存储在堆空间中，而s则是在操作数栈中。<br />上面是对s和haha值的内存情况的分析和理解；那对于string s = new string("hello");语句,到底创建了几个对象呢?<br />我的理解：这里"hello"本身就是常量池中的一个对象，而在运行时执行new string()时，将常量池中的对象复制一份放到堆中，并且把堆中的这个对象的引用交给s持有。所以这条语句就创建了2个string对象。<br /><br /><br /><strong>下面是一些string相关的常见问题：</strong><br />String中的final用法和理解<br />final stringbuffer a = new stringbuffer("111");<br />final stringbuffer b = new stringbuffer("222");<br />a=b;//此句编译不通过<br />final stringbuffer a = new stringbuffer("111");<br />a.append("222");//编译通过<br />可见，final只对引用的"值"(即内存地址)有效，它迫使引用只能指向初始指向的那个对象，改变它的指向会导致编译期错误。至于它所指向的对象的变化，final是不负责的。<br /><br /><br /><strong>String 常量池问题的几个例子</strong><br />下面是几个常见例子的比较分析和理解：<br />【1】<br />
<dl style="padding-bottom: 0px; overflow-x: auto; overflow-y: auto; margin: 0px; padding-left: 0px; width: 718px; padding-right: 0px; font-size: 12px; padding-top: 0px">
<dt style="line-height: 24px; background-color: rgb(245,245,245); text-indent: 6px; height: 24px; color: rgb(51,51,51); font-weight: bold">Java code 
<dd style="border-bottom: rgb(221,221,221) 1px solid; border-left: rgb(221,221,221) 1px solid; margin: 0px; border-top: rgb(221,221,221) 1px solid; border-right: rgb(221,221,221) 1px solid">
<div><span style="line-height: 18px; color: rgb(0,0,0)"><span style="line-height: 18px; color: rgb(0,0,0)"></span><span style="line-height: 18px; color: rgb(0,0,0)"></span>String a</span> <span style="line-height: 18px; color: rgb(0,0,0)">=</span> <span style="line-height: 18px; color: rgb(0,0,0)">"</span><span style="line-height: 18px; color: rgb(0,0,0)">a1</span><span style="line-height: 18px; color: rgb(0,0,0)">"</span><span style="line-height: 18px; color: rgb(0,0,0)">; String b</span> <span style="line-height: 18px; color: rgb(0,0,0)">=</span> <span style="line-height: 18px; color: rgb(0,0,0)">"</span><span style="line-height: 18px; color: rgb(0,0,0)">a</span><span style="line-height: 18px; color: rgb(0,0,0)">"</span> <span style="line-height: 18px; color: rgb(0,0,0)">+</span> <span style="line-height: 18px; color: rgb(0,0,0)">1</span><span style="line-height: 18px; color: rgb(0,0,0)">; System.out.println((a</span> <span style="line-height: 18px; color: rgb(0,0,0)">==</span> <span style="line-height: 18px; color: rgb(0,0,0)">b));</span> <span style="line-height: 18px; color: rgb(0,128,0)">//</span><span style="line-height: 18px; color: rgb(0,128,0)">result = true</span> <span style="line-height: 18px; color: rgb(0,0,0)">String a</span> <span style="line-height: 18px; color: rgb(0,0,0)">=</span> <span style="line-height: 18px; color: rgb(0,0,0)">"</span><span style="line-height: 18px; color: rgb(0,0,0)">atrue</span><span style="line-height: 18px; color: rgb(0,0,0)">"</span><span style="line-height: 18px; color: rgb(0,0,0)">; String b</span> <span style="line-height: 18px; color: rgb(0,0,0)">=</span> <span style="line-height: 18px; color: rgb(0,0,0)">"</span><span style="line-height: 18px; color: rgb(0,0,0)">a</span><span style="line-height: 18px; color: rgb(0,0,0)">"</span> <span style="line-height: 18px; color: rgb(0,0,0)">+</span> <span style="line-height: 18px; color: rgb(0,0,0)">"</span><span style="line-height: 18px; color: rgb(0,0,0)">true</span><span style="line-height: 18px; color: rgb(0,0,0)">"</span><span style="line-height: 18px; color: rgb(0,0,0)">; System.out.println((a</span> <span style="line-height: 18px; color: rgb(0,0,0)">==</span> <span style="line-height: 18px; color: rgb(0,0,0)">b));</span> <span style="line-height: 18px; color: rgb(0,128,0)">//</span><span style="line-height: 18px; color: rgb(0,128,0)">result = true</span> <span style="line-height: 18px; color: rgb(0,0,0)">String a</span> <span style="line-height: 18px; color: rgb(0,0,0)">=</span> <span style="line-height: 18px; color: rgb(0,0,0)">"</span><span style="line-height: 18px; color: rgb(0,0,0)">a3.4</span><span style="line-height: 18px; color: rgb(0,0,0)">"</span><span style="line-height: 18px; color: rgb(0,0,0)">; String b</span> <span style="line-height: 18px; color: rgb(0,0,0)">=</span> <span style="line-height: 18px; color: rgb(0,0,0)">"</span><span style="line-height: 18px; color: rgb(0,0,0)">a</span><span style="line-height: 18px; color: rgb(0,0,0)">"</span> <span style="line-height: 18px; color: rgb(0,0,0)">+</span> <span style="line-height: 18px; color: rgb(0,0,0)">3.4</span><span style="line-height: 18px; color: rgb(0,0,0)">; System.out.println((a</span> <span style="line-height: 18px; color: rgb(0,0,0)">==</span> <span style="line-height: 18px; color: rgb(0,0,0)">b));</span> <span style="line-height: 18px; color: rgb(0,128,0)">//</span><span style="line-height: 18px; color: rgb(0,128,0)">result = true</span></div><pre> </pre></dd></dl><br />分析：jvm对于字符串常量的"+"号连接，将程序编译期，jvm就将常量字符串的"+"连接优化为连接后的值，拿"a" + 1来说，经编译器优化后在class中就已经是a1。在编译期其字符串常量的值就确定下来，故上面程序最终的结果都为true。<br /><br />【2】<br />
<dl style="padding-bottom: 0px; overflow-x: auto; overflow-y: auto; margin: 0px; padding-left: 0px; width: 718px; padding-right: 0px; font-size: 12px; padding-top: 0px">
<dt style="line-height: 24px; background-color: rgb(245,245,245); text-indent: 6px; height: 24px; color: rgb(51,51,51); font-weight: bold">Java code 
<dd style="border-bottom: rgb(221,221,221) 1px solid; border-left: rgb(221,221,221) 1px solid; margin: 0px; border-top: rgb(221,221,221) 1px solid; border-right: rgb(221,221,221) 1px solid">
<div><span style="line-height: 18px; color: rgb(0,0,0)">String a</span> <span style="line-height: 18px; color: rgb(0,0,0)">=</span> <span style="line-height: 18px; color: rgb(0,0,0)">"</span><span style="line-height: 18px; color: rgb(0,0,0)">ab</span><span style="line-height: 18px; color: rgb(0,0,0)">"</span><span style="line-height: 18px; color: rgb(0,0,0)">; String bb</span> <span style="line-height: 18px; color: rgb(0,0,0)">=</span> <span style="line-height: 18px; color: rgb(0,0,0)">"</span><span style="line-height: 18px; color: rgb(0,0,0)">b</span><span style="line-height: 18px; color: rgb(0,0,0)">"</span><span style="line-height: 18px; color: rgb(0,0,0)">; String b</span> <span style="line-height: 18px; color: rgb(0,0,0)">=</span> <span style="line-height: 18px; color: rgb(0,0,0)">"</span><span style="line-height: 18px; color: rgb(0,0,0)">a</span><span style="line-height: 18px; color: rgb(0,0,0)">"</span> <span style="line-height: 18px; color: rgb(0,0,0)">+</span> <span style="line-height: 18px; color: rgb(0,0,0)">bb; System.out.println((a</span> <span style="line-height: 18px; color: rgb(0,0,0)">==</span> <span style="line-height: 18px; color: rgb(0,0,0)">b));</span> <span style="line-height: 18px; color: rgb(0,128,0)">//</span><span style="line-height: 18px; color: rgb(0,128,0)">result = false</span></div><pre> </pre></dd></dl><br />分析：jvm对于字符串引用，由于在字符串的"+"连接中，有字符串引用存在，而引用的值在程序编译期是无法确定的，即"a" + bb无法被编译器优化，只有在程序运行期来动态分配并将连接后的新地址赋给b。所以上面程序的结果也就为false。<br /><br />【3】<br />
<dl style="padding-bottom: 0px; overflow-x: auto; overflow-y: auto; margin: 0px; padding-left: 0px; width: 718px; padding-right: 0px; font-size: 12px; padding-top: 0px">
<dt style="line-height: 24px; background-color: rgb(245,245,245); text-indent: 6px; height: 24px; color: rgb(51,51,51); font-weight: bold">Java code 
<dd style="border-bottom: rgb(221,221,221) 1px solid; border-left: rgb(221,221,221) 1px solid; margin: 0px; border-top: rgb(221,221,221) 1px solid; border-right: rgb(221,221,221) 1px solid">
<div><span style="line-height: 18px; color: rgb(0,0,0)">String a</span> <span style="line-height: 18px; color: rgb(0,0,0)">=</span> <span style="line-height: 18px; color: rgb(0,0,0)">"</span><span style="line-height: 18px; color: rgb(0,0,0)">ab</span><span style="line-height: 18px; color: rgb(0,0,0)">"</span><span style="line-height: 18px; color: rgb(0,0,0)">;</span> <span style="line-height: 18px; color: rgb(0,0,255)">final</span> <span style="line-height: 18px; color: rgb(0,0,0)">String bb</span> <span style="line-height: 18px; color: rgb(0,0,0)">=</span> <span style="line-height: 18px; color: rgb(0,0,0)">"</span><span style="line-height: 18px; color: rgb(0,0,0)">b</span><span style="line-height: 18px; color: rgb(0,0,0)">"</span><span style="line-height: 18px; color: rgb(0,0,0)">; String b</span> <span style="line-height: 18px; color: rgb(0,0,0)">=</span> <span style="line-height: 18px; color: rgb(0,0,0)">"</span><span style="line-height: 18px; color: rgb(0,0,0)">a</span><span style="line-height: 18px; color: rgb(0,0,0)">"</span> <span style="line-height: 18px; color: rgb(0,0,0)">+</span> <span style="line-height: 18px; color: rgb(0,0,0)">bb; System.out.println((a</span> <span style="line-height: 18px; color: rgb(0,0,0)">==</span> <span style="line-height: 18px; color: rgb(0,0,0)">b));</span> <span style="line-height: 18px; color: rgb(0,128,0)">//</span><span style="line-height: 18px; color: rgb(0,128,0)">result = true</span></div><pre> </pre></dd></dl><br />分析：和[3]中唯一不同的是bb字符串加了final修饰，对于final修饰的变量，它在编译时被解析为常量值的一个本地拷贝存储到自己的常量池中或嵌入到它的字节码流中。所以此时的"a" + bb和"a" + "b"效果是一样的。故上面程序的结果为true。<br /><br />【4】<br />
<dl style="padding-bottom: 0px; overflow-x: auto; overflow-y: auto; margin: 0px; padding-left: 0px; width: 718px; padding-right: 0px; font-size: 12px; padding-top: 0px">
<dt style="line-height: 24px; background-color: rgb(245,245,245); text-indent: 6px; height: 24px; color: rgb(51,51,51); font-weight: bold">Java code 
<dd style="border-bottom: rgb(221,221,221) 1px solid; border-left: rgb(221,221,221) 1px solid; margin: 0px; border-top: rgb(221,221,221) 1px solid; border-right: rgb(221,221,221) 1px solid">
<div><span style="line-height: 18px; color: rgb(0,0,0)">String a</span> <span style="line-height: 18px; color: rgb(0,0,0)">=</span> <span style="line-height: 18px; color: rgb(0,0,0)">"</span><span style="line-height: 18px; color: rgb(0,0,0)">ab</span><span style="line-height: 18px; color: rgb(0,0,0)">"</span><span style="line-height: 18px; color: rgb(0,0,0)">;</span> <span style="line-height: 18px; color: rgb(0,0,255)">final</span> <span style="line-height: 18px; color: rgb(0,0,0)">String bb</span> <span style="line-height: 18px; color: rgb(0,0,0)">=</span> <span style="line-height: 18px; color: rgb(0,0,0)">getbb(); String b</span> <span style="line-height: 18px; color: rgb(0,0,0)">=</span> <span style="line-height: 18px; color: rgb(0,0,0)">"</span><span style="line-height: 18px; color: rgb(0,0,0)">a</span><span style="line-height: 18px; color: rgb(0,0,0)">"</span> <span style="line-height: 18px; color: rgb(0,0,0)">+</span> <span style="line-height: 18px; color: rgb(0,0,0)">bb; System.out.println((a</span> <span style="line-height: 18px; color: rgb(0,0,0)">==</span> <span style="line-height: 18px; color: rgb(0,0,0)">b));</span> <span style="line-height: 18px; color: rgb(0,128,0)">//</span><span style="line-height: 18px; color: rgb(0,128,0)">result = false</span> <span style="line-height: 18px; color: rgb(0,0,255)">private</span> <span style="line-height: 18px; color: rgb(0,0,255)">static</span> <span style="line-height: 18px; color: rgb(0,0,0)">string getbb() {</span> <span style="line-height: 18px; color: rgb(0,0,255)">return</span> <span style="line-height: 18px; color: rgb(0,0,0)">"</span><span style="line-height: 18px; color: rgb(0,0,0)">b</span><span style="line-height: 18px; color: rgb(0,0,0)">"</span><span style="line-height: 18px; color: rgb(0,0,0)">; }</span></div><pre> </pre></dd></dl><br />分析：jvm对于字符串引用bb，它的值在编译期无法确定，只有在程序运行期调用方法后，将方法的返回值和"a"来动态连接并分配地址为b，故上面程序的结果为false。<br /><br />通过上面4个例子可以得出得知：<br />string s = "a" + "b" + "c"; &nbsp;<wbr>&nbsp;<wbr><br />就等价于string s = "abc";&nbsp;&nbsp;<wbr>&nbsp;<wbr><br /><br />string a = "a"; &nbsp;<wbr>&nbsp;<wbr><br />string b = "b"; &nbsp;<wbr>&nbsp;<wbr><br />string c = "c"; &nbsp;<wbr>&nbsp;<wbr><br />string s = a + b + c; &nbsp;<wbr>&nbsp;<wbr><br />这个就不一样了，最终结果等于： &nbsp;<wbr>&nbsp;<wbr><br />stringbuffer temp = new stringbuffer(); &nbsp;<wbr>&nbsp;<wbr><br />temp.append(a).append(b).append(c); &nbsp;<wbr>&nbsp;<wbr><br />string s = temp.tostring();<br />由上面的分析结果，可就不难推断出string 采用连接运算符（+）效率低下原因分析，形如这样的代码：<br />
<dl style="padding-bottom: 0px; overflow-x: auto; overflow-y: auto; margin: 0px; padding-left: 0px; width: 718px; padding-right: 0px; font-size: 12px; padding-top: 0px">
<dt style="line-height: 24px; background-color: rgb(245,245,245); text-indent: 6px; height: 24px; color: rgb(51,51,51); font-weight: bold">Java code 
<dd style="border-bottom: rgb(221,221,221) 1px solid; border-left: rgb(221,221,221) 1px solid; margin: 0px; border-top: rgb(221,221,221) 1px solid; border-right: rgb(221,221,221) 1px solid">
<div><span style="line-height: 18px; color: rgb(0,0,255)">public</span> <span style="line-height: 18px; color: rgb(0,0,255)">class</span> <span style="line-height: 18px; color: rgb(0,0,0)">test {</span> <span style="line-height: 18px; color: rgb(0,0,255)">public</span> <span style="line-height: 18px; color: rgb(0,0,255)">static</span> <span style="line-height: 18px; color: rgb(0,0,255)">void</span> <span style="line-height: 18px; color: rgb(0,0,0)">main (String args[]) { String s</span> <span style="line-height: 18px; color: rgb(0,0,0)">=</span> <span style="line-height: 18px; color: rgb(0,0,255)">null</span><span style="line-height: 18px; color: rgb(0,0,0)">;</span> <span style="line-height: 18px; color: rgb(0,0,255)">for</span> <span style="line-height: 18px; color: rgb(0,0,0)">(</span><span style="line-height: 18px; color: rgb(0,0,255)">int</span> <span style="line-height: 18px; color: rgb(0,0,0)">i</span> <span style="line-height: 18px; color: rgb(0,0,0)">=</span> <span style="line-height: 18px; color: rgb(0,0,0)">0</span><span style="line-height: 18px; color: rgb(0,0,0)">; i</span> <span style="line-height: 18px; color: rgb(0,0,0)">&lt;</span> <span style="line-height: 18px; color: rgb(0,0,0)">100</span><span style="line-height: 18px; color: rgb(0,0,0)">; i</span><span style="line-height: 18px; color: rgb(0,0,0)">++</span><span style="line-height: 18px; color: rgb(0,0,0)">) { s</span> <span style="line-height: 18px; color: rgb(0,0,0)">+=</span> <span style="line-height: 18px; color: rgb(0,0,0)">"</span><span style="line-height: 18px; color: rgb(0,0,0)">a</span><span style="line-height: 18px; color: rgb(0,0,0)">"</span><span style="line-height: 18px; color: rgb(0,0,0)">; } } }</span></div><pre> </pre></dd></dl><br />每做一次 + 就产生个stringbuilder对象，然后append后就扔掉。下次循环再到达时重新产生个stringbuilder对象，然后 append 字符串，如此循环直至结束。 如果我们直接采用 stringbuilder 对象进行 append 的话，我们可以节省 n - 1 次创建和销毁对象的时间。所以对于在循环中要进行字符串连接的应用，一般都是用stringbuffer或stringbulider对象来进行append操作。<br /><br /><strong>string对象的intern方法理解和分析：</strong><br />
<dl style="padding-bottom: 0px; overflow-x: auto; overflow-y: auto; margin: 0px; padding-left: 0px; width: 718px; padding-right: 0px; font-size: 12px; padding-top: 0px">
<dt style="line-height: 24px; background-color: rgb(245,245,245); text-indent: 6px; height: 24px; color: rgb(51,51,51); font-weight: bold">Java code 
<dd style="border-bottom: rgb(221,221,221) 1px solid; border-left: rgb(221,221,221) 1px solid; margin: 0px; border-top: rgb(221,221,221) 1px solid; border-right: rgb(221,221,221) 1px solid">
<div><span style="line-height: 18px; color: rgb(0,0,255)"><span style="line-height: 18px; color: rgb(0,0,255)"></span>public</span> <span style="line-height: 18px; color: rgb(0,0,255)">class</span> <span style="line-height: 18px; color: rgb(0,0,0)">test4 {</span> <span style="line-height: 18px; color: rgb(0,0,255)">private</span> <span style="line-height: 18px; color: rgb(0,0,255)">static</span> <span style="line-height: 18px; color: rgb(0,0,0)">String a</span> <span style="line-height: 18px; color: rgb(0,0,0)">=</span> <span style="line-height: 18px; color: rgb(0,0,0)">"</span><span style="line-height: 18px; color: rgb(0,0,0)">ab</span><span style="line-height: 18px; color: rgb(0,0,0)">"</span><span style="line-height: 18px; color: rgb(0,0,0)">;</span> <span style="line-height: 18px; color: rgb(0,0,255)">public</span> <span style="line-height: 18px; color: rgb(0,0,255)">static</span> <span style="line-height: 18px; color: rgb(0,0,255)">void</span> <span style="line-height: 18px; color: rgb(0,0,0)">main (String[] args){ String s1</span> <span style="line-height: 18px; color: rgb(0,0,0)">=</span> <span style="line-height: 18px; color: rgb(0,0,0)">"</span><span style="line-height: 18px; color: rgb(0,0,0)">a</span><span style="line-height: 18px; color: rgb(0,0,0)">"</span><span style="line-height: 18px; color: rgb(0,0,0)">; String s2</span> <span style="line-height: 18px; color: rgb(0,0,0)">=</span> <span style="line-height: 18px; color: rgb(0,0,0)">"</span><span style="line-height: 18px; color: rgb(0,0,0)">b</span><span style="line-height: 18px; color: rgb(0,0,0)">"</span><span style="line-height: 18px; color: rgb(0,0,0)">; String s</span> <span style="line-height: 18px; color: rgb(0,0,0)">=</span> <span style="line-height: 18px; color: rgb(0,0,0)">s1</span> <span style="line-height: 18px; color: rgb(0,0,0)">+</span> <span style="line-height: 18px; color: rgb(0,0,0)">s2; System.out.println(s</span> <span style="line-height: 18px; color: rgb(0,0,0)">==</span> <span style="line-height: 18px; color: rgb(0,0,0)">a);</span><span style="line-height: 18px; color: rgb(0,128,0)">//</span><span style="line-height: 18px; color: rgb(0,128,0)">false</span> <span style="line-height: 18px; color: rgb(0,0,0)">System.out.println(s.intern()</span> <span style="line-height: 18px; color: rgb(0,0,0)">==</span> <span style="line-height: 18px; color: rgb(0,0,0)">a);</span><span style="line-height: 18px; color: rgb(0,128,0)">//</span><span style="line-height: 18px; color: rgb(0,128,0)">true</span> <span style="line-height: 18px; color: rgb(0,0,0)">} }</span></div><pre> </pre></dd></dl><br />这里用到java里面是一个常量池的问题。对于s1+s2操作，其实是在堆里面重新创建了一个新的对象,s保存的是这个新对象在堆空间的的内容，所以s与a的值是不相等的。而当调用s.intern()方法，却可以返回s在常量池中的地址值，因为a的值存储在常量池中，故s.intern和a的值相等。 <img src ="http://www.blogjava.net/zhb8015/aggbug/376777.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zhb8015/" target="_blank">zhb8015</a> 2012-04-27 15:42 <a href="http://www.blogjava.net/zhb8015/articles/376777.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>openssl生成https证书  (转)</title><link>http://www.blogjava.net/zhb8015/articles/376402.html</link><dc:creator>zhb8015</dc:creator><author>zhb8015</author><pubDate>Mon, 23 Apr 2012 10:31:00 GMT</pubDate><guid>http://www.blogjava.net/zhb8015/articles/376402.html</guid><wfw:comment>http://www.blogjava.net/zhb8015/comments/376402.html</wfw:comment><comments>http://www.blogjava.net/zhb8015/articles/376402.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zhb8015/comments/commentRss/376402.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zhb8015/services/trackbacks/376402.html</trackback:ping><description><![CDATA[<p>&nbsp;</p>
<p>1.首先要生成服务器端的私钥(key文件):<br />openssl genrsa -des3 -out server.key 1024<br />运行时会提示输入密码,此密码用于加密key文件<br />去除key文件口令的命令:<br />openssl rsa -in server.key -out server.key</p>
<p>2.openssl req -new -key server.key -out server.csr -config openssl.cfg<br />生成Certificate Signing Request（CSR）,生成的csr文件交给CA签名后形成服务端自己的证书.屏幕上将有提示,依照其指示一步一步输入要求的个人信息即可.</p>
<p>3.对客户端也作同样的命令生成key及csr文件:<br />openssl genrsa -des3 -out client.key 1024<br />openssl req -new -key client.key -out client.csr -config openssl.cfg</p>
<p>4.CSR文件必须有CA的签名才可形成证书.可将此文件发送到verisign等地方由它验证.自己生成：<br />openssl req -new -x509 -keyout ca.key -out ca.crt -config openssl.cfg</p>
<p>5.用生成的CA的证书为刚才生成的server.csr,client.csr文件签名:<br />Openssl ca -in server.csr -out server.crt -cert ca.crt -keyfile ca.key -config openssl.cfg<br />Openssl ca -in client.csr -out client.crt -cert ca.crt -keyfile ca.key -config openssl.cfg</p>
<p>&nbsp;</p>
<p>PS:如报update database之类的错误，把index.txt.attr 文件内容更新为 unique_subject = no</p>
<p>注意: 此时会出错：Using configuration from /usr/share/ssl/openssl.cfg I am unable to access the ./demoCA/newcerts directory ./demoCA/newcerts: No such file or directory <br />解决方法： 1).mkdir -p ./demoCA/newcerts <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 　　 2).touch demoCA/index.txt <br />&nbsp;&nbsp;&nbsp; 　　　　 3).touch demoCA/serial <br />&nbsp;&nbsp; 　　　　　4).echo 01 &gt; demoCA/serial</p>
<p>6.合并证书文件（crt）和私钥文件（key） </p>
<p>1).cat client.crt client.key &gt; client.pem </p>
<p>2).cat server.crt server.key &gt; server.pem </p>
<p>7.合并成pfx证书 </p>
<p>1).openssl pkcs12 -export -clcerts -in client.crt -inkey client.key -out client.p12 <br />2).openssl pkcs12 -export -clcerts -in server.crt -inkey server.key -out server.p12 <br />8.文本化证书 </p>
<p>1).openssl pkcs12 -in client.p12 -out client.txt </p>
<p>2).openssl pkcs12 -in server.p12 -out server.txt </p>
<p>9.屏幕模式显式：（证书、私钥、公钥） </p>
<p>1).openssl x509 -in client.crt -noout -text -modulus </p>
<p>2).openssl rsa -in server.key -noout -text -modulus </p>
<p>3).openssl rsa -in server.pub -noout -text -modulus </p>
<p>10.得到DH </p>
<p>1).openssl dhparam -out dh1024.pem 1024</p>
<p><br />(8) 编辑apache的配置文件httpd.cfg<br />开启: LoadModule ssl_module modules/mod_ssl.so<br />去掉以下语句的注释, Include conf/extra/httpd-ssl.cfg<br /># Secure (SSL/TLS) connections<br />Include conf/extra/httpd-ssl.cfg<br />#&nbsp;&nbsp;&nbsp; <br />(9) 编辑 conf/extra/httpd-ssl.cfg</p>
<p>&lt;VirtualHost *:443&gt;<br />&nbsp;&nbsp; SSLEngine On<br />&nbsp;&nbsp; SSLCertificateFile conf/ssl/server.crt<br />&nbsp;&nbsp; SSLCertificateKeyFile conf/ssl/server.key<br />&nbsp;&nbsp; SSLCertificateChainFile conf/ssl/ca.crt<br />&lt;/VirtualHost&gt;&nbsp; </p>
<p>cd /usr/local/apache/conf<br />openssl genrsa -des3 -out server.key 1024<br />openssl req -new -key server.key -out server.csr -config /usr/local/ssl/openssl.cfg <br />openssl req -new -x509 -keyout ca.key -out ca.crt -config /usr/local/ssl/openssl.cfg <br />mkdir -p ./demoCA/newcerts <br />touch demoCA/index.txt<br />touch demoCA/serial<br />echo 01 &gt; demoCA/serial<br />openssl ca -in server.csr -out server.crt -cert ca.crt -keyfile ca.key -config /usr/local/ssl/openssl.cfg <br />bin/apachectl start<br /></p><img src ="http://www.blogjava.net/zhb8015/aggbug/376402.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zhb8015/" target="_blank">zhb8015</a> 2012-04-23 18:31 <a href="http://www.blogjava.net/zhb8015/articles/376402.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java深浅复制</title><link>http://www.blogjava.net/zhb8015/articles/374072.html</link><dc:creator>zhb8015</dc:creator><author>zhb8015</author><pubDate>Fri, 13 Apr 2012 06:47:00 GMT</pubDate><guid>http://www.blogjava.net/zhb8015/articles/374072.html</guid><wfw:comment>http://www.blogjava.net/zhb8015/comments/374072.html</wfw:comment><comments>http://www.blogjava.net/zhb8015/articles/374072.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/zhb8015/comments/commentRss/374072.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zhb8015/services/trackbacks/374072.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 一、概念二、实现方式及简单原理&nbsp; 三、实例四、参考五、单元测试六、代码下载&nbsp; （deepCopy.rar）一、概念A、浅复制：浅复制仅仅复制所考虑的对象，而不复制它所引用的对象被复制对象的所有变量都含有与原来的对象相同的值，而所有的对其他对象的引用仍然指向原来的对象。B、深复制：深复制把要复制的对象所引用的对象都复制了一遍被复制对象的所有变量都含有与原来的对...&nbsp;&nbsp;<a href='http://www.blogjava.net/zhb8015/articles/374072.html'>阅读全文</a><img src ="http://www.blogjava.net/zhb8015/aggbug/374072.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zhb8015/" target="_blank">zhb8015</a> 2012-04-13 14:47 <a href="http://www.blogjava.net/zhb8015/articles/374072.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>求质数，难以理解的代码，有兴趣可以看一下</title><link>http://www.blogjava.net/zhb8015/articles/373982.html</link><dc:creator>zhb8015</dc:creator><author>zhb8015</author><pubDate>Thu, 12 Apr 2012 08:21:00 GMT</pubDate><guid>http://www.blogjava.net/zhb8015/articles/373982.html</guid><wfw:comment>http://www.blogjava.net/zhb8015/comments/373982.html</wfw:comment><comments>http://www.blogjava.net/zhb8015/articles/373982.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/zhb8015/comments/commentRss/373982.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zhb8015/services/trackbacks/373982.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 求1.。x的质数？这样的问题相信大家都很熟悉，我这里有两个版本，其中有一点不太明白，希望大家指点一下。一、简单的版本二、复杂但艺术的版本(write by Robert C. Martin）问题：都用到了Math.sqrt(x),为什么用平方根，原理是什么呢？一、简单的版本Code highlighting produced by Actipro CodeHighlighter (freewa...&nbsp;&nbsp;<a href='http://www.blogjava.net/zhb8015/articles/373982.html'>阅读全文</a><img src ="http://www.blogjava.net/zhb8015/aggbug/373982.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zhb8015/" target="_blank">zhb8015</a> 2012-04-12 16:21 <a href="http://www.blogjava.net/zhb8015/articles/373982.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JUnit 4使用手册(转)</title><link>http://www.blogjava.net/zhb8015/articles/373776.html</link><dc:creator>zhb8015</dc:creator><author>zhb8015</author><pubDate>Wed, 11 Apr 2012 03:12:00 GMT</pubDate><guid>http://www.blogjava.net/zhb8015/articles/373776.html</guid><wfw:comment>http://www.blogjava.net/zhb8015/comments/373776.html</wfw:comment><comments>http://www.blogjava.net/zhb8015/articles/373776.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zhb8015/comments/commentRss/373776.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zhb8015/services/trackbacks/373776.html</trackback:ping><description><![CDATA[<h2>JUnit 4使用手册</h2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 笔者此前使用过JUnit 3，工作关系很长时间没再碰Java了。最近重新接触了一下，发现JUnit 4和3有较大区别，特总结一下JUnit 4的基本用法，供自己查阅也供朋友们参考。<br />
<h3><strong>一、JUnit简介</strong></h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; JUnit由Kent Beck和ErichGamma开发，几乎毫无疑问是迄今所开发的最重要的第三方Java库，它也成为了Java语言事实上的标准单元测试库。正如Martin Fowler所说，&#8220;在软件开发领域，从来就没有如此少的代码起到了如此重要的作用&#8221;。JUnit引导并促进了测试先行的编程和测试驱动的开发。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; JUnit 4是该库三年以来最具里程碑意义的一次发布。它的新特性主要是通过采用Java 5中的标记annotation）而不是利用子类、反射或命名机制来识别测试，从而简化测试代码。用Kent的话来说，&#8220;JUnit 4 的主题是通过进一步简化 JUnit，鼓励更多的开发人员编写更多的测试。&#8221;</p>
<h3><strong>二、JUnit4实践</strong></h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 选择一款IDE（Eclipse, NetBean, Idea等），基本上它们都全面支持JUnit了。创建工程后，为了避免代码混乱，建议为单元测试代码与被测试代码分别创建单独的目录。首先，写一个很简单的方法，判断输入的邮箱地址是否符合规范：</p>
<div id="highlighter_142090" class="syntaxhighlighter  java">
<div class="bar   ">
<div class="toolbar"><a style="width: 16px; height: 16px" class="item viewSource" title="查看源码" href="http://www.open-open.com/lib/view/1328078836812#viewSource" highlighterid="highlighter_142090" commandname="viewSource">查看源码</a> 
<div class="item copyToClipboard"></div><a style="width: 16px; height: 16px" class="item printSource" title="打印" href="http://www.open-open.com/lib/view/1328078836812#printSource" highlighterid="highlighter_142090" commandname="printSource">打印</a><a style="width: 16px; height: 16px" class="item about" title="?" href="http://www.open-open.com/lib/view/1328078836812#about" highlighterid="highlighter_142090" commandname="about">?</a></div></div>
<div class="lines">
<div class="line alt1">
<table>
<tbody>
<tr>
<td class="number"><code>1</code></td>
<td class="content"><code class="java keyword">public</code> <code class="java keyword">static</code> <code class="java keyword">boolean</code> <code class="java plain">checkEmail(String email) { </code></td></tr></tbody></table></div>
<div class="line alt2">
<table>
<tbody>
<tr>
<td class="number"><code>2</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java keyword">if</code> <code class="java plain">(!email.matches(</code><code class="java string">"[\\w\\.\\-]+@([\\w\\-]+\\.)+[\\w\\-]+"</code><code class="java plain">)) { </code></td></tr></tbody></table></div>
<div class="line alt1">
<table>
<tbody>
<tr>
<td class="number"><code>3</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java keyword">return</code> <code class="java keyword">false</code><code class="java plain">; </code></td></tr></tbody></table></div>
<div class="line alt2">
<table>
<tbody>
<tr>
<td class="number"><code>4</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java plain">} </code></td></tr></tbody></table></div>
<div class="line alt1">
<table>
<tbody>
<tr>
<td class="number"><code>5</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java keyword">return</code> <code class="java keyword">true</code><code class="java plain">; </code></td></tr></tbody></table></div>
<div class="line alt2">
<table>
<tbody>
<tr>
<td class="number"><code>6</code></td>
<td class="content"><code class="java plain">}</code></td></tr></tbody></table></div></div></div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OK，一切准备就绪，我们开始编写这个方法的单元测试用例。 
<p>&nbsp;</p>
<p><strong>1、测试由@Test注释开始</strong></p>
<p>&nbsp;</p>
<div id="highlighter_610318" class="syntaxhighlighter  java">
<div class="bar ">
<div class="toolbar"><a style="width: 16px; height: 16px" class="item viewSource" title="查看源码" href="http://www.open-open.com/lib/view/1328078836812#viewSource" highlighterid="highlighter_610318" commandname="viewSource">查看源码</a> 
<div class="item copyToClipboard"></div><a style="width: 16px; height: 16px" class="item printSource" title="打印" href="http://www.open-open.com/lib/view/1328078836812#printSource" highlighterid="highlighter_610318" commandname="printSource">打印</a><a style="width: 16px; height: 16px" class="item about" title="?" href="http://www.open-open.com/lib/view/1328078836812#about" highlighterid="highlighter_610318" commandname="about">?</a></div></div>
<div class="lines">
<div class="line alt1">
<table>
<tbody>
<tr>
<td class="number"><code>1</code></td>
<td class="content"><code class="java color1">@Test</code>&nbsp;</td></tr></tbody></table></div>
<div class="line alt2">
<table>
<tbody>
<tr>
<td class="number"><code>2</code></td>
<td class="content"><code class="java keyword">public</code> <code class="java keyword">void</code> <code class="java plain">checkEmail(){ </code></td></tr></tbody></table></div>
<div class="line alt1">
<table>
<tbody>
<tr>
<td class="number"><code>3</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java plain">assertEquals(</code><code class="java keyword">true</code><code class="java plain">, RegexUtil.checkEmail(</code><code class="java string">"add.dd@sina.com"</code><code class="java plain">)); </code></td></tr></tbody></table></div>
<div class="line alt2">
<table>
<tbody>
<tr>
<td class="number"><code>4</code></td>
<td class="content"><code class="java plain">}</code></td></tr></tbody></table></div></div></div>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 以前版本的JUnit通过命名约定和反射来定位测试用例，要求测试方法以&#8221;test&#8221;开头+方法名，并且测试类需要继承TestCase。JUnit 4中简化了这个操作，只需要在测试类中引入org.junit.Test，在测试方法前使用注解@Test，JUnit就可以侦测该测试方法了，保持了代码的简洁。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 注：在JUnit4中仍然可以以原来的方式进行测试（继承TestCase并在方法前加test）。但是如果这样就最好不要使用注解。因为一旦继承了TestCase，注解会失效，如果没有test前缀，会报：AssertionFailedError: No tests found&#8230;异常。</p>
<p><strong>2、Fixture</strong><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 它是指在执行一个或者多个测试方法时需要的一系列公共资源或者数据，例如测试环境，测试数据等。JUnit专门提供了设置公共Fixture的方法，同一测试类中的所有测试方法都可以共用它来初始化Fixture和注销Fixture。在以前的版本，JUnit使用SetUp和TearDown方法。在JUnit4中，使用注解org,junit.Before和org.junit.After。例如：</p>
<div id="highlighter_881311" class="syntaxhighlighter  java">
<div class="bar   ">
<div class="toolbar"><a style="width: 16px; height: 16px" class="item viewSource" title="查看源码" href="http://www.open-open.com/lib/view/1328078836812#viewSource" highlighterid="highlighter_881311" commandname="viewSource">查看源码</a> 
<div class="item copyToClipboard"></div><a style="width: 16px; height: 16px" class="item printSource" title="打印" href="http://www.open-open.com/lib/view/1328078836812#printSource" highlighterid="highlighter_881311" commandname="printSource">打印</a><a style="width: 16px; height: 16px" class="item about" title="?" href="http://www.open-open.com/lib/view/1328078836812#about" highlighterid="highlighter_881311" commandname="about">?</a></div></div>
<div class="lines">
<div class="line alt1">
<table>
<tbody>
<tr>
<td class="number"><code>1</code></td>
<td class="content"><code class="java color1">@Before</code>&nbsp;</td></tr></tbody></table></div>
<div class="line alt2">
<table>
<tbody>
<tr>
<td class="number"><code>2</code></td>
<td class="content"><code class="java keyword">public</code> <code class="java keyword">void</code> <code class="java plain">initialize (){&#8230;&#8230;} </code></td></tr></tbody></table></div>
<div class="line alt1">
<table>
<tbody>
<tr>
<td class="number"><code>3</code></td>
<td class="content"><code class="java color1">@After</code>&nbsp;</td></tr></tbody></table></div>
<div class="line alt2">
<table>
<tbody>
<tr>
<td class="number"><code>4</code></td>
<td class="content"><code class="java keyword">public</code> <code class="java keyword">void</code> <code class="java plain">dispose (){&#8230;&#8230;}</code></td></tr></tbody></table></div></div></div>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这样，在每一个测试方法执行之前，JUnit会保证注解了Before的方法提前执行。当测试方法执行完毕后，JUnit调用注解了After的方法注销测试环境。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 注：@Before和@After修饰的是方法级别的。它们都可以修饰多个方法，但是方法执行的顺序不能保证。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在JUnit 4中还引入了类级别的Fixture设置方法，即使用注解 BeforeClass和AfterClass。这两种方法都使用 public static void 修饰，且不能带有任何参数。类级别的Fixture仅会在测试类中所有测试方法执行之前和之后执行。</p>
<p><strong>3、异常和测试时间</strong><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; JUnit 4中引入了异常的测试，以前版本中异常测试是在抛出异常的代码中放入try块，然后在try块的末尾加入fail语句。在JUnit 4中，可以使用@Test中的expected参数，它表示测试方法期望抛出的异常，如果运行测试并没有抛出这个异常，则JUnit会认为这个测试没有通过。例如：</p>
<div id="highlighter_839722" class="syntaxhighlighter  java">
<div class="bar ">
<div class="toolbar"><a style="width: 16px; height: 16px" class="item viewSource" title="查看源码" href="http://www.open-open.com/lib/view/1328078836812#viewSource" highlighterid="highlighter_839722" commandname="viewSource">查看源码</a> 
<div class="item copyToClipboard"></div><a style="width: 16px; height: 16px" class="item printSource" title="打印" href="http://www.open-open.com/lib/view/1328078836812#printSource" highlighterid="highlighter_839722" commandname="printSource">打印</a><a style="width: 16px; height: 16px" class="item about" title="?" href="http://www.open-open.com/lib/view/1328078836812#about" highlighterid="highlighter_839722" commandname="about">?</a></div></div>
<div class="lines">
<div class="line alt1">
<table>
<tbody>
<tr>
<td class="number"><code>1</code></td>
<td class="content"><code class="java color1">@Test</code><code class="java plain">(expected= IndexOutOfBoundsException.</code><code class="java keyword">class</code><code class="java plain">) </code></td></tr></tbody></table></div>
<div class="line alt2">
<table>
<tbody>
<tr>
<td class="number"><code>2</code></td>
<td class="content"><code class="java keyword">public</code> <code class="java keyword">void</code> <code class="java plain">empty() { </code></td></tr></tbody></table></div>
<div class="line alt1">
<table>
<tbody>
<tr>
<td class="number"><code>3</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java keyword">new</code> <code class="java plain">ArrayList&lt;Object&gt;().get(</code><code class="java value">1</code><code class="java plain">); </code></td></tr></tbody></table></div>
<div class="line alt2">
<table>
<tbody>
<tr>
<td class="number"><code>4</code></td>
<td class="content"><code class="java plain">}</code></td></tr></tbody></table></div></div></div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @Test的另一个参数timeout，用来指定被测试方法被允许运行的最长时间。如果测试方法运行时间超过了指定的毫秒数，则JUnit认为测试失败。例如： 
<div id="highlighter_757244" class="syntaxhighlighter  java">
<div class="bar   ">
<div class="toolbar"><a style="width: 16px; height: 16px" class="item viewSource" title="查看源码" href="http://www.open-open.com/lib/view/1328078836812#viewSource" highlighterid="highlighter_757244" commandname="viewSource">查看源码</a> 
<div class="item copyToClipboard"></div><a style="width: 16px; height: 16px" class="item printSource" title="打印" href="http://www.open-open.com/lib/view/1328078836812#printSource" highlighterid="highlighter_757244" commandname="printSource">打印</a><a style="width: 16px; height: 16px" class="item about" title="?" href="http://www.open-open.com/lib/view/1328078836812#about" highlighterid="highlighter_757244" commandname="about">?</a></div></div>
<div class="lines">
<div class="line alt1">
<table>
<tbody>
<tr>
<td class="number"><code>1</code></td>
<td class="content"><code class="java color1">@Test</code><code class="java plain">(timeout = </code><code class="java value">10</code><code class="java plain">) </code></td></tr></tbody></table></div>
<div class="line alt2">
<table>
<tbody>
<tr>
<td class="number"><code>2</code></td>
<td class="content"><code class="java keyword">public</code> <code class="java keyword">void</code> <code class="java plain">checkEmail(){ </code></td></tr></tbody></table></div>
<div class="line alt1">
<table>
<tbody>
<tr>
<td class="number"><code>3</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java plain">assertEquals(</code><code class="java keyword">true</code><code class="java plain">, RegexUtil.checkEmail(</code><code class="java string">"add.dd@sina.com"</code><code class="java plain">)); </code></td></tr></tbody></table></div>
<div class="line alt2">
<table>
<tbody>
<tr>
<td class="number"><code>4</code></td>
<td class="content"><code class="java plain">}</code></td></tr></tbody></table></div></div></div>
<p><strong>4、忽略测试方法</strong><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; JUnit 4提供注解org.junit.Ignore用于暂时忽略某个测试方法。例如：</p>
<div id="highlighter_373323" class="syntaxhighlighter  java">
<div class="bar       ">
<div class="toolbar"><a style="width: 16px; height: 16px" class="item viewSource" title="查看源码" href="http://www.open-open.com/lib/view/1328078836812#viewSource" highlighterid="highlighter_373323" commandname="viewSource">查看源码</a> 
<div class="item copyToClipboard"></div><a style="width: 16px; height: 16px" class="item printSource" title="打印" href="http://www.open-open.com/lib/view/1328078836812#printSource" highlighterid="highlighter_373323" commandname="printSource">打印</a><a style="width: 16px; height: 16px" class="item about" title="?" href="http://www.open-open.com/lib/view/1328078836812#about" highlighterid="highlighter_373323" commandname="about">?</a></div></div>
<div class="lines">
<div class="line alt1">
<table>
<tbody>
<tr>
<td class="number"><code>1</code></td>
<td class="content"><code class="java color1">@Ignore</code><code class="java plain">(&#8220;db is down&#8221;) </code></td></tr></tbody></table></div>
<div class="line alt2">
<table>
<tbody>
<tr>
<td class="number"><code>2</code></td>
<td class="content"><code class="java color1">@Test</code><code class="java plain">(expected=UnsupportedDBVersionException.</code><code class="java keyword">class</code><code class="java plain">) </code></td></tr></tbody></table></div>
<div class="line alt1">
<table>
<tbody>
<tr>
<td class="number"><code>3</code></td>
<td class="content"><code class="java keyword">public</code> <code class="java keyword">void</code> <code class="java plain">unsupportedDBCheck(){　&#8230;&#8230;&nbsp; }</code></td></tr></tbody></table></div></div></div>
<p>&nbsp;</p>
<p><strong>5、测试用例的执行</strong><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; JUnit中所有的测试用例都是由测试运行器执行的。JUnit提供了默认的测试运行器，但并没有限制我们必须使用默认的运行器（所有的运行器都继承自Runner）。相反，我们不仅可以定制自己的运行器，而且还可以为每个测试类指定使用某个运行器（使用@RunWith）。例如JUnit的自测代码：</p>
<div id="highlighter_73197" class="syntaxhighlighter  java">
<div class="bar          ">
<div class="toolbar"><a style="width: 16px; height: 16px" class="item viewSource" title="查看源码" href="http://www.open-open.com/lib/view/1328078836812#viewSource" highlighterid="highlighter_73197" commandname="viewSource">查看源码</a> 
<div class="item copyToClipboard"></div><a style="width: 16px; height: 16px" class="item printSource" title="打印" href="http://www.open-open.com/lib/view/1328078836812#printSource" highlighterid="highlighter_73197" commandname="printSource">打印</a><a style="width: 16px; height: 16px" class="item about" title="?" href="http://www.open-open.com/lib/view/1328078836812#about" highlighterid="highlighter_73197" commandname="about">?</a></div></div>
<div class="lines">
<div class="line alt1">
<table>
<tbody>
<tr>
<td class="number"><code>01</code></td>
<td class="content"><code class="java keyword">public</code> <code class="java keyword">class</code> <code class="java plain">RunWithTest { </code></td></tr></tbody></table></div>
<div class="line alt2">
<table>
<tbody>
<tr>
<td class="number"><code>02</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java keyword">private</code> <code class="java keyword">static</code> <code class="java plain">String log; </code></td></tr></tbody></table></div>
<div class="line alt1">
<table>
<tbody>
<tr>
<td class="number"><code>03</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java keyword">public</code> <code class="java keyword">static</code> <code class="java keyword">class</code> <code class="java plain">ExampleRunner </code><code class="java keyword">extends</code> <code class="java plain">Runner { </code></td></tr></tbody></table></div>
<div class="line alt2">
<table>
<tbody>
<tr>
<td class="number"><code>04</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java keyword">public</code> <code class="java plain">ExampleRunner(Class&lt;?&gt; klass) { </code></td></tr></tbody></table></div>
<div class="line alt1">
<table>
<tbody>
<tr>
<td class="number"><code>05</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java plain">log+= </code><code class="java string">"initialize"</code><code class="java plain">; </code></td></tr></tbody></table></div>
<div class="line alt2">
<table>
<tbody>
<tr>
<td class="number"><code>06</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java plain">} </code></td></tr></tbody></table></div>
<div class="line alt1">
<table>
<tbody>
<tr>
<td class="number"><code>07</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java color1">@Override</code></td></tr></tbody></table></div>
<div class="line alt2">
<table>
<tbody>
<tr>
<td class="number"><code>08</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java keyword">public</code> <code class="java keyword">void</code> <code class="java plain">run(RunNotifier notifier) { </code></td></tr></tbody></table></div>
<div class="line alt1">
<table>
<tbody>
<tr>
<td class="number"><code>09</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java plain">log+= </code><code class="java string">"run"</code><code class="java plain">; </code></td></tr></tbody></table></div>
<div class="line alt2">
<table>
<tbody>
<tr>
<td class="number"><code>10</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java plain">} </code></td></tr></tbody></table></div>
<div class="line alt1">
<table>
<tbody>
<tr>
<td class="number"><code>11</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java color1">@Override</code></td></tr></tbody></table></div>
<div class="line alt2">
<table>
<tbody>
<tr>
<td class="number"><code>12</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java keyword">public</code> <code class="java plain">Description getDescription() { </code></td></tr></tbody></table></div>
<div class="line alt1">
<table>
<tbody>
<tr>
<td class="number"><code>13</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java plain">log+= </code><code class="java string">"plan"</code><code class="java plain">; </code></td></tr></tbody></table></div>
<div class="line alt2">
<table>
<tbody>
<tr>
<td class="number"><code>14</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java keyword">return</code> <code class="java plain">Description.createSuiteDescription(</code><code class="java string">"example"</code><code class="java plain">); </code></td></tr></tbody></table></div>
<div class="line alt1">
<table>
<tbody>
<tr>
<td class="number"><code>15</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java plain">} </code></td></tr></tbody></table></div>
<div class="line alt2">
<table>
<tbody>
<tr>
<td class="number"><code>16</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java plain">} </code></td></tr></tbody></table></div>
<div class="line alt1">
<table>
<tbody>
<tr>
<td class="number"><code>17</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java color1">@RunWith</code><code class="java plain">(ExampleRunner.</code><code class="java keyword">class</code><code class="java plain">) </code></td></tr></tbody></table></div>
<div class="line alt2">
<table>
<tbody>
<tr>
<td class="number"><code>18</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java keyword">public</code> <code class="java keyword">static</code> <code class="java keyword">class</code> <code class="java plain">ExampleTest { </code></td></tr></tbody></table></div>
<div class="line alt1">
<table>
<tbody>
<tr>
<td class="number"><code>19</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java plain">} </code></td></tr></tbody></table></div>
<div class="line alt2">
<table>
<tbody>
<tr>
<td class="number"><code>20</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java color1">@Test</code> <code class="java keyword">public</code> <code class="java keyword">void</code> <code class="java plain">run() { </code></td></tr></tbody></table></div>
<div class="line alt1">
<table>
<tbody>
<tr>
<td class="number"><code>21</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java plain">log= </code><code class="java string">""</code><code class="java plain">; </code></td></tr></tbody></table></div>
<div class="line alt2">
<table>
<tbody>
<tr>
<td class="number"><code>22</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java plain">JUnitCore.runClasses(ExampleTest.</code><code class="java keyword">class</code><code class="java plain">); </code></td></tr></tbody></table></div>
<div class="line alt1">
<table>
<tbody>
<tr>
<td class="number"><code>23</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java plain">assertTrue(log.contains(</code><code class="java string">"plan"</code><code class="java plain">)); </code></td></tr></tbody></table></div>
<div class="line alt2">
<table>
<tbody>
<tr>
<td class="number"><code>24</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java plain">assertTrue(log.contains(</code><code class="java string">"initialize"</code><code class="java plain">)); </code></td></tr></tbody></table></div>
<div class="line alt1">
<table>
<tbody>
<tr>
<td class="number"><code>25</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java plain">assertTrue(log.contains(</code><code class="java string">"run"</code><code class="java plain">)); </code></td></tr></tbody></table></div>
<div class="line alt2">
<table>
<tbody>
<tr>
<td class="number"><code>26</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java plain">} </code></td></tr></tbody></table></div>
<div class="line alt1">
<table>
<tbody>
<tr>
<td class="number"><code>27</code></td>
<td class="content"><code class="java plain">}</code></td></tr></tbody></table></div></div></div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 显而易见，如果测试类没有显式的声明使用哪一个测试运行器，JUnit 会启动默认的测试运行器执行测试类。一般情况下，默认测试运行器可以应对绝大多数的测试要求；当使用 JUnit 提供的一些高级特性或者针对特殊需求定制 JUnit 测试方式时，显式的声明测试运行器就必不可少了。 
<p>&nbsp;</p>
<p><strong>6、测试套件Suite</strong><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 正如JUnit以前版本中提供的Suite一样，JUnit4提供了一种批量运行测试类的方法，以方便我们在每次进行系统测试时，只需执行若干测试套件而不是执行无数测试用例。我们只需创建一个空类，并填写两个注解。例如：</p>
<div id="highlighter_17070" class="syntaxhighlighter  java">
<div class="bar ">
<div class="toolbar"><a style="width: 16px; height: 16px" class="item viewSource" title="查看源码" href="http://www.open-open.com/lib/view/1328078836812#viewSource" highlighterid="highlighter_17070" commandname="viewSource">查看源码</a> 
<div class="item copyToClipboard"></div><a style="width: 16px; height: 16px" class="item printSource" title="打印" href="http://www.open-open.com/lib/view/1328078836812#printSource" highlighterid="highlighter_17070" commandname="printSource">打印</a><a style="width: 16px; height: 16px" class="item about" title="?" href="http://www.open-open.com/lib/view/1328078836812#about" highlighterid="highlighter_17070" commandname="about">?</a></div></div>
<div class="lines">
<div class="line alt1">
<table>
<tbody>
<tr>
<td class="number"><code>1</code></td>
<td class="content"><code class="java color1">@RunWith</code><code class="java plain">(Suite.</code><code class="java keyword">class</code><code class="java plain">) </code></td></tr></tbody></table></div>
<div class="line alt2">
<table>
<tbody>
<tr>
<td class="number"><code>2</code></td>
<td class="content"><code class="java color1">@Suite</code><code class="java plain">.SuiteClasses({TestCheckEmail.</code><code class="java keyword">class</code><code class="java plain">, TestTimeUtil.</code><code class="java keyword">class</code><code class="java plain">}) </code></td></tr></tbody></table></div>
<div class="line alt1">
<table>
<tbody>
<tr>
<td class="number"><code>3</code></td>
<td class="content"><code class="java keyword">public</code> <code class="java keyword">class</code> <code class="java plain">CustomizeRunner{ </code></td></tr></tbody></table></div>
<div class="line alt2">
<table>
<tbody>
<tr>
<td class="number"><code>4</code></td>
<td class="content"><code class="java plain">}</code></td></tr></tbody></table></div></div></div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 测试套件中不仅可以包含基本的测试类，而且可以包含其它的测试套件。但是，一定要保证测试套件之间没有循环包含关系，否则将出现死循环。 
<p>&nbsp;</p>
<p><strong>7、参数化测试</strong><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当我们编写了大量的单元测试方法后，我们发现这些方法其实大同小异，只是参数不同（测试边界值或者测试异常值）。在以前的 JUnit版本上，并没有好的解决方法，而现在我们可以使用JUnit提供的参数化测试方式解决这个问题。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 首先在测试类中指定参数运行期@RunWith(Parameterized.class)。例如：</p>
<div id="highlighter_505030" class="syntaxhighlighter  java">
<div class="bar       ">
<div class="toolbar"><a style="width: 16px; height: 16px" class="item viewSource" title="查看源码" href="http://www.open-open.com/lib/view/1328078836812#viewSource" highlighterid="highlighter_505030" commandname="viewSource">查看源码</a> 
<div class="item copyToClipboard"></div><a style="width: 16px; height: 16px" class="item printSource" title="打印" href="http://www.open-open.com/lib/view/1328078836812#printSource" highlighterid="highlighter_505030" commandname="printSource">打印</a><a style="width: 16px; height: 16px" class="item about" title="?" href="http://www.open-open.com/lib/view/1328078836812#about" highlighterid="highlighter_505030" commandname="about">?</a></div></div>
<div class="lines">
<div class="line alt1">
<table>
<tbody>
<tr>
<td class="number"><code>01</code></td>
<td class="content"><code class="java color1">@RunWith</code><code class="java plain">(Parameterized.</code><code class="java keyword">class</code><code class="java plain">) </code></td></tr></tbody></table></div>
<div class="line alt2">
<table>
<tbody>
<tr>
<td class="number"><code>02</code></td>
<td class="content"><code class="java keyword">public</code> <code class="java keyword">class</code> <code class="java plain">TestWithParam { </code></td></tr></tbody></table></div>
<div class="line alt1">
<table>
<tbody>
<tr>
<td class="number"><code>03</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java color1">@Parameterized</code><code class="java plain">.Parameters </code></td></tr></tbody></table></div>
<div class="line alt2">
<table>
<tbody>
<tr>
<td class="number"><code>04</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java keyword">public</code> <code class="java keyword">static</code> <code class="java plain">List&lt;Object[]&gt; data() { </code></td></tr></tbody></table></div>
<div class="line alt1">
<table>
<tbody>
<tr>
<td class="number"><code>05</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java keyword">return</code> <code class="java plain">Arrays.asList(</code><code class="java keyword">new</code> <code class="java plain">Object[][]{ </code></td></tr></tbody></table></div>
<div class="line alt2">
<table>
<tbody>
<tr>
<td class="number"><code>06</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java plain">{</code><code class="java value">0</code><code class="java plain">, </code><code class="java value">0</code><code class="java plain">}, {</code><code class="java value">1</code><code class="java plain">, </code><code class="java value">1</code><code class="java plain">}, {</code><code class="java value">2</code><code class="java plain">, </code><code class="java value">1</code><code class="java plain">}, {</code><code class="java value">3</code><code class="java plain">, </code><code class="java value">2</code><code class="java plain">}, {</code><code class="java value">4</code><code class="java plain">, </code><code class="java value">3</code><code class="java plain">}, {</code><code class="java value">5</code><code class="java plain">, </code><code class="java value">5</code><code class="java plain">}, {</code><code class="java value">6</code><code class="java plain">, </code><code class="java value">8</code><code class="java plain">},{</code><code class="java value">10</code><code class="java plain">,</code><code class="java value">55</code><code class="java plain">} </code></td></tr></tbody></table></div>
<div class="line alt1">
<table>
<tbody>
<tr>
<td class="number"><code>07</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java plain">}); </code></td></tr></tbody></table></div>
<div class="line alt2">
<table>
<tbody>
<tr>
<td class="number"><code>08</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java plain">} </code></td></tr></tbody></table></div>
<div class="line alt1">
<table>
<tbody>
<tr>
<td class="number"><code>09</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java keyword">private</code> <code class="java keyword">int</code> <code class="java plain">fInput; </code></td></tr></tbody></table></div>
<div class="line alt2">
<table>
<tbody>
<tr>
<td class="number"><code>10</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java keyword">private</code> <code class="java keyword">int</code> <code class="java plain">fExpected; </code></td></tr></tbody></table></div>
<div class="line alt1">
<table>
<tbody>
<tr>
<td class="number"><code>11</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java keyword">public</code> <code class="java plain">testWithParam(</code><code class="java keyword">int</code> <code class="java plain">input, </code><code class="java keyword">int</code> <code class="java plain">expected) { </code></td></tr></tbody></table></div>
<div class="line alt2">
<table>
<tbody>
<tr>
<td class="number"><code>12</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java plain">fInput = input; </code></td></tr></tbody></table></div>
<div class="line alt1">
<table>
<tbody>
<tr>
<td class="number"><code>13</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java plain">fExpected = expected; </code></td></tr></tbody></table></div>
<div class="line alt2">
<table>
<tbody>
<tr>
<td class="number"><code>14</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java plain">} </code></td></tr></tbody></table></div>
<div class="line alt1">
<table>
<tbody>
<tr>
<td class="number"><code>15</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java color1">@Test</code></td></tr></tbody></table></div>
<div class="line alt2">
<table>
<tbody>
<tr>
<td class="number"><code>16</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java keyword">public</code> <code class="java keyword">void</code> <code class="java plain">test() { </code></td></tr></tbody></table></div>
<div class="line alt1">
<table>
<tbody>
<tr>
<td class="number"><code>17</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java plain">assertEquals(fExpected, Fibonacci.compute(fInput)); </code></td></tr></tbody></table></div>
<div class="line alt2">
<table>
<tbody>
<tr>
<td class="number"><code>18</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java plain">} </code></td></tr></tbody></table></div>
<div class="line alt1">
<table>
<tbody>
<tr>
<td class="number"><code>19</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java keyword">private</code> <code class="java keyword">static</code> <code class="java keyword">class</code> <code class="java plain">Fibonacci{ </code></td></tr></tbody></table></div>
<div class="line alt2">
<table>
<tbody>
<tr>
<td class="number"><code>20</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java keyword">public</code> <code class="java keyword">static</code> <code class="java keyword">int</code> <code class="java plain">compute(</code><code class="java keyword">int</code> <code class="java plain">input){ </code></td></tr></tbody></table></div>
<div class="line alt1">
<table>
<tbody>
<tr>
<td class="number"><code>21</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java keyword">if</code><code class="java plain">(input ==</code><code class="java value">0</code><code class="java plain">) </code></td></tr></tbody></table></div>
<div class="line alt2">
<table>
<tbody>
<tr>
<td class="number"><code>22</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java keyword">return</code> <code class="java value">0</code><code class="java plain">; </code></td></tr></tbody></table></div>
<div class="line alt1">
<table>
<tbody>
<tr>
<td class="number"><code>23</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java keyword">else</code> <code class="java keyword">if</code> <code class="java plain">(input==</code><code class="java value">1</code><code class="java plain">) </code></td></tr></tbody></table></div>
<div class="line alt2">
<table>
<tbody>
<tr>
<td class="number"><code>24</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java keyword">return</code> <code class="java value">1</code><code class="java plain">; </code></td></tr></tbody></table></div>
<div class="line alt1">
<table>
<tbody>
<tr>
<td class="number"><code>25</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java keyword">else</code> <code class="java keyword">if</code> <code class="java plain">(input==</code><code class="java value">2</code><code class="java plain">) </code></td></tr></tbody></table></div>
<div class="line alt2">
<table>
<tbody>
<tr>
<td class="number"><code>26</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java keyword">return</code> <code class="java value">1</code><code class="java plain">; </code></td></tr></tbody></table></div>
<div class="line alt1">
<table>
<tbody>
<tr>
<td class="number"><code>27</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java keyword">else</code> <code class="java keyword">return</code> <code class="java plain">compute(input-</code><code class="java value">1</code><code class="java plain">)+compute(input-</code><code class="java value">2</code><code class="java plain">); </code></td></tr></tbody></table></div>
<div class="line alt2">
<table>
<tbody>
<tr>
<td class="number"><code>28</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java plain">} </code></td></tr></tbody></table></div>
<div class="line alt1">
<table>
<tbody>
<tr>
<td class="number"><code>29</code></td>
<td class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="java plain">} </code></td></tr></tbody></table></div>
<div class="line alt2">
<table>
<tbody>
<tr>
<td class="number"><code>30</code></td>
<td class="content"><code class="java plain">}</code></td></tr></tbody></table></div></div></div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在静态方法data中，我们使用二维数组来构建测试所需要的参数列表，其中每个数组中的元素的放置顺序只要和构造函数中的顺序保持一致就可以了。 
<p>&nbsp;</p>
<p><strong>参考文献</strong>：</p>
<p>1.单元测试利器 JUnit 4：<a href="http://www.ibm.com/developerworks/cn/java/j-lo-junit4/">http://www.ibm.com/developerworks/cn/java/j-lo-junit4/</a><br />2.JUnit 4 JavaDoc</p><img src ="http://www.blogjava.net/zhb8015/aggbug/373776.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zhb8015/" target="_blank">zhb8015</a> 2012-04-11 11:12 <a href="http://www.blogjava.net/zhb8015/articles/373776.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>