<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
<channel>
<title><![CDATA[Frank's Blog - 软件开发]]></title>
<link>http://www.wolf2999.cn/</link>
<description><![CDATA[虎年大吉.赞助本站,请点击广告.]]></description>
<language>zh-cn</language>
<copyright><![CDATA[Copyright 2005 PBlog2 v2.4]]></copyright>
<webMaster><![CDATA[wolf2999@tom.com(wolf2999)]]></webMaster>
<generator>PBlog2 v2.4</generator> 
<image>
	<title>Frank&#39;s Blog</title> 
	<url>http://www.wolf2999.cn/images/logos.gif</url> 
	<link>http://www.wolf2999.cn/</link> 
	<description>Frank&#39;s Blog</description> 
</image>

			<item>
			<link>http://www.wolf2999.cn/default.asp?id=956</link>
			<title><![CDATA[十条不错的编程观点]]></title>
			<author>wolf2999@tom.com(wolf2999)</author>
			<category><![CDATA[软件开发]]></category>
			<pubDate>Sat,12 Jun 2010 14:38:16 +0800</pubDate>
			<guid>http://www.wolf2999.cn/default.asp?id=956</guid>	
		<description><![CDATA[原贴：<a href="http://coolshell.cn/?p=2424" target="_blank">http://coolshell.cn/?p=2424</a><br/><strong>1） The only “best practice” you should be using all the time is “Use Your Brain”.</strong><br/><br/>唯一的“Best Practice”并不是使用各种各样被前人总结过的各种设计方法、模式，框架，那些著名的方法、模式、框架只代码赞同他们的人多，并不代表他们适合你，你应该更多的去使用你的大脑，独立地思考那些方法、模式、框架出现的原因和其背后的想法和思想，那才是“best practice”。事实上来说，那些所谓的“Best Practice”只不过是限制那些糟糕的程序员们的破坏力。<br/><br/><strong>2）Programmers who don’t code in their spare time for fun will never become as good as those that do.</strong><br/><br/>如果你对编程没有感到一种快乐，没有在你空闲的时候去以一种的娱乐方式去生活，无论是编程，还是运动，还是去旅游，那么你只不过是在应付你的工作，无时无刻不扎在程序堆中，这样下来，就算是你是一个非常聪明，非常有才华的人，你也不会成为一个优秀的编程员，要么只会平平凡凡，要么只会整天扎在技术中成为书呆子。当然，这个观点是有争议，热情和能力的差距也是很大的。不过我们可以从中汲取其正面的观点。<br/><br/><strong>3）Most comments in code are in fact a pernicious form of code duplication.</strong><br/><br/>注释应该是注释Why，而不是How和What，参看《惹恼程序员的十件事》，代码告诉你How，而注释应该告诉你Why。但大多数的程序并不知道什么是好的注释，那些注释其实和code是重复的，毫无意义。<br/><br/><br/><strong>4）XML is highly overrated</strong><br/><br/>XML可能被高估了。XML对于Web上的应用是不错的，但是我们把其用到了各种地方，好像没有XML，我们都不会编程了。<br/><br/><strong>5）Not all programmers are cr&#101;ated equal</strong><br/><br/>这是那些junior经理或是流程爱犯的错，他们总是认为，DeveloperA == DeveloperB，只要他们的title一样，他们以为他们的能力、工作速度、解决问题的方法，掌握的技能等等都是一样的。呵呵。更扯的是，在某些时候，就算是最差的程序员，他们也会认为其比别人强十倍，这就是现代的SB管理。<br/><br/><strong>6）”Googling it” is okay!</strong><br/><br/>Google只会给你知识，并不会教给你技能。那里只有“鱼”，没有“渔”，过度的使用Google，只会让你越来越离不开他，你越来越去要去立马告诉你答案，而你越来越不会自己去思考，自己去探索，去专研。如果KFC快餐是垃圾食品对我们的身体没有好处，那么使用Google也一种快餐文化对我们的智力发展大大的没有好处。<br/><br/><strong>7）If you only know one language, no matter how well you know it, you’re not a great programmer.</strong><br/><br/>如果你只懂一种语言，准确的说，如果你只懂一类语类，如：Java和C#，PHP和Perl，那么，你将会被局限起来，只有了解了各种各样的语言，了解了不同语言的不同方法 ，你才会有比较，只有了比较，你才会明白各种语言的长处和短处，才会让你有更为成熟的观点，而且不整天和别的程序在网上斗嘴争论是Windows好还是Unix好，是C好还是C++好，有这点工夫能干好多事了。世界因为不同而精彩，只知道事物的一面是有害的。<br/><br/><strong>8）Your job is to put yourself out of work.</strong><br/><br/>你的工作不是保守，那种教会徒弟，饿死师父的想法，不但是相当短浅的，而且还是相当脑残的。因为，在计算机世界里，你掌握的老技术越多，你就越没用，因为技术更新的太快。你对工作越保守，这个工作就越来越离不开你，你就越不越不能抽身去学新的东西，你也就越来越OUT了。记住：If you can’t be replaced then you can’t be promoted!<br/><br/><strong>9）Design patterns are hurting good design more than they’re helping it.</strong><br/><br/>很多程序员把设计模式奉为天神，他们过度的追求设计模式以至都都忘了需求是什么，结果整个系统设计被设计模式搞得乱七八糟，我们叫这种编程为“设计模式驱动编程”，正如第一点所说，如果你不懂得用自己的大脑思考的话，知其然，不知所以然的话，那么你不但得不到其好处，反而受其所累。<br/><br/><strong>10）Unit Testing won’t help you write good code</strong><br/><br/>准确地说，我们可以认为这是Test-Driven开发，其实，这种开发就是先写unit test case，这样的开发方式的主要目的是，为了防止你不会因为一个改动而引入Bug，但这并不会让你能写出更好的代码。这只会让你写出不会出错的代码。同第一点，这样的方法，只不过是防止糟糕的程序员，而并不是让程序员或代码质量更有长进。反而，通过Unit Test会为程序员的为自己代码做辩解的一种托辞。<br/><br/>]]></description>
		</item>
		
			<item>
			<link>http://www.wolf2999.cn/default.asp?id=837</link>
			<title><![CDATA[strcpy ,strncpy ,strlcpy的用法]]></title>
			<author>wolf2999@tom.com(wolf2999)</author>
			<category><![CDATA[软件开发]]></category>
			<pubDate>Sat,05 Dec 2009 08:48:50 +0800</pubDate>
			<guid>http://www.wolf2999.cn/default.asp?id=837</guid>	
		<description><![CDATA[好多人已经知道利用strncpy替代strcpy来防止缓冲区越界。<br/>但是如果还要考虑运行效率的话，也许strlcpy是一个更好的方式。<br/>1. strcpy<br/><br/>我们知道，strcpy 是依据 \0 作为结束判断的，如果 to 的空间不够，则会引起 buffer overflow。strcpy 常规的实现代码如下（来自 OpenBSD 3.9）：<br/><br/><div class="UBBPanel"><div class="UBBTitle"><img src="http://www.wolf2999.cn/images/code.gif" style="margin:0px 2px -3px 0px" alt="程序代码"/> 程序代码</div><div class="UBBContent"><br/>char *<br/>strcpy(char *to, const char *from)<br/>{<br/>char *save = to;<br/><br/>for (; (*to = *from) != &#39;\0&#39;; ++from, ++to);<br/>return(save);<br/>}<br/></div></div><br/><br/>但通常，我们的 from 都来源于用户的输入，很可能是非常大的一个字符串，因此 strcpy 不够安全。<br/><br/><br/>2. strncpy<br/><br/>在 ANSI C 中，strcpy 的安全版本是 strncpy。<br/><br/><div class="UBBPanel"><div class="UBBTitle"><img src="http://www.wolf2999.cn/images/code.gif" style="margin:0px 2px -3px 0px" alt="程序代码"/> 程序代码</div><div class="UBBContent">char *strncpy(char *s1, const char *s2, size_t n);</div></div><br/><br/>但 strncpy 其行为是很诡异的（不符合我们的通常习惯）。标准规定 n 并不是 sizeof(s1)，而是要复制的 char 的个数。一个最常见的问题，就是 strncpy 并不帮你保证 \0<br/><br/>结束。<br/><br/><div class="UBBPanel"><div class="UBBTitle"><img src="http://www.wolf2999.cn/images/code.gif" style="margin:0px 2px -3px 0px" alt="程序代码"/> 程序代码</div><div class="UBBContent"><br/>char buf[8];<br/>strncpy( buf, &#34;abcdefgh&#34;, 8 );<br/></div></div><br/><br/>看这个程序，buf 将会被 &#34;abcdefgh&#34; 填满，但却没有 \0 结束符了。<br/><br/>另外，如果 s2 的内容比较少，而 n 又比较大的话，strncpy 将会把之间的空间都用 \0 填充。这又出现了一个效率上的问题，如下：<br/><br/><div class="UBBPanel"><div class="UBBTitle"><img src="http://www.wolf2999.cn/images/code.gif" style="margin:0px 2px -3px 0px" alt="程序代码"/> 程序代码</div><div class="UBBContent"><br/>char buf[80];<br/>strncpy( buf, &#34;abcdefgh&#34;, 79 );<br/></div></div><br/><br/>上面的 strncpy 会填写 79 个 char，而不仅仅是 &#34;abcdefgh&#34; 本身。<br/><br/><br/>strncpy 的标准用法为：（手工写上 \0）<br/><br/><div class="UBBPanel"><div class="UBBTitle"><img src="http://www.wolf2999.cn/images/code.gif" style="margin:0px 2px -3px 0px" alt="程序代码"/> 程序代码</div><div class="UBBContent"><br/>strncpy(path, src, sizeof(path) - 1);<br/>path[sizeof(path) - 1] = &#39;\0&#39;;<br/>len = strlen(path);<br/></div></div><br/><br/><br/>3. strlcpy<br/><br/><div class="UBBPanel"><div class="UBBTitle"><img src="http://www.wolf2999.cn/images/code.gif" style="margin:0px 2px -3px 0px" alt="程序代码"/> 程序代码</div><div class="UBBContent">// Copy src to string dst of size siz. At most siz-1 characters<br/>// will be copied. Always NUL terminates (unless siz == 0).<br/>// Returns strlen(src); if retval &gt;= siz, truncation occurred.<br/>size_t<br/>strlcpy(char *dst, const char *src, size_t siz);<br/><br/>而使用 strlcpy，就不需要我们去手动负责 \0 了，仅需要把 sizeof(dst) 告之 strlcpy 即可：<br/><br/>strlcpy(path, src, sizeof(path));<br/>len = strlen(path);<br/><br/>if ( len &gt;= sizeof(path) )<br/>printf(&#34;src is truncated.&#34;);</div></div><br/><br/>并且 strlcpy 传回的是 strlen(str)，因此我们也很方便的可以判断数据是否被截断。<br/><br/>///////////////////////////////////////////////////////////////////////////<br/>strncpy <br/>原型：extern char *strncpy(char *dest, char *src, int n); <br/><br/>用法：#include &lt;string.h&gt; <br/><br/>功能：把src所指由NULL结束的字符串的前n个字节复制到dest所指的数组中。 <br/><br/>说明： <br/>如果src的前n个字节不含NULL字符，则结果不会以NULL字符结束。 <br/>如果src的长度小于n个字节，则以NULL填充dest直到复制完n个字节。 <br/>src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。 <br/>返回指向dest的指针。]]></description>
		</item>
		
			<item>
			<link>http://www.wolf2999.cn/default.asp?id=836</link>
			<title><![CDATA[Subversion与CVS的对比]]></title>
			<author>wolf2999@tom.com(wolf2999)</author>
			<category><![CDATA[软件开发]]></category>
			<pubDate>Sat,05 Dec 2009 08:47:28 +0800</pubDate>
			<guid>http://www.wolf2999.cn/default.asp?id=836</guid>	
		<description><![CDATA[一、Subversion包含绝大部分CVS功能<br/><br/>Subversion 作为CVS 的重写版和改进版，其目标就是作为一个更好的版本控制软件，取代目前流行的CVS。Subversion 的主要开发人员都是业界知名的CVS 专家。Subversion支持绝大部分的CVS 功能/命令；Subversion 的命令风格和界面也与CVS 非常接近。当然，不同的地方正是对CVS 的改进。<br/><br/>二、全局性的版本编号<br/><br/>一个新的版本，并得到一个自增量的版本号N+1，该版本号并不针对某个特定的文件，而是全局性的、针对整个版本库的。因此，我们可以将Subversion 的版本库看作是一个文件系统或文件目录树的数组。<br/><br/>从技术的角度来说，在Subversion 中，“文件foo.c 的第5 版本”这个说法是错误的；正确的说法应该是：”文件foo.c 在版本库被修改了5 次，即执行5 次commit 后是什么样子？”。显然，在Subversion 中，版本库被修改5 次后foo.c 的内容，和被修改了6 次后foo.c 的内容很可能完全一样，因为版本库的第6 次修改很可能只修改了版本库的其他部分，而并没有对foo.c 的进行修改。相反，在CVS 中，文件foo.c 的第1.1 版本和第1.2 版本总是不同的。<br/><br/>Subversion 的全局性版本编号为Subversion 带来了诸多的优势：如对目录或文件执行拷贝，无论涉及多少文件，Subversion 不需要对单个文件依次执行拷贝命令，仅仅需要建立一个指向相应的全局版本号的一个指针即可。<br/><br/>三、目录的版本控制<br/><br/>CVS 只能对文件进行版本控制，不能对目录进行版本控制，因此CVS 没有任何关于文件“移动”（move） 操作的概念。当人为进行文件移动操作时，CVS 只能注意到，一个文件在一个位置被删除了，而在一个新位置创建了另外一个文件。由于它不会连接两个操作，因此也很容易使文件历史轨迹丢失。设置 CVS 存储库时，必须非常谨慎地为每个文件选择准确的位置，因为在设置之后，几乎就要一直使用这个位置了。<br/><br/>同样由于CVS 不记录目录的版本历史，CVS 不支持对文件的“重命名”（rename），人为的对文件进行重命名会使得命名前后的文件失去历史联系，而记录历史本来是版本管理的主要目的。<br/><br/>还有，CVS 不支持对文件的“拷贝”（copy），人为的拷贝对CVS 而言，只能看到新的文件的增加，而不能记录拷贝源文件和目标文件之间的联系。<br/><br/>综上所述，缺乏对文件“移动”、“重命名”、“拷贝”的支持的根源在于CVS 不能记录目录的版本历史，而这些操作在当前的软件开发过程中经常发生，这正是Subversion被开发并取代CVS 的主要原因之一。<br/><br/>Subversion 将目录作为一类特殊的文件来处理（事实上，从文件系统的角度来看，目录确实是一类特殊的文件，当目录中的子目录/文件被删除、重命名、或新的子目录/文件被创建时，目录的内容将发生改变）。因此，Subversion 象记录普通文件的修改历史一样记录对目录的修改历史，当发生文件/目录的移动、重命名或拷贝操作时，Subversion 能够准确记录操作前后的历史联系。同样，象对文件的不同历史版本进行比较一样，Subversion支持对目录的不同历史版本的比较，清晰展现目录的变化历史。<br/><br/><br/>四、原子性提交<br/><br/>从使用者的角度来看，CVS 和Subversion 都支持对多个文件修改的批量提交，但二者在实现方式上存在本质的区别。<br/><br/>CVS 采用线性、串行的批量提交，即依次地，一个接一个地执行提交，每成功提交一个文件，该文件的一个新的版本即被记录到版本库中，提交时用户提供的日志信息被重复地存储到每一个被修改的文件的版本历史中。<br/><br/>CVS 串行批量提交模式的弊端在于 － 当任何原因造成批量操作的中断时（典型原因包括：网络中断、客户端死机等），版本库往往处于一个不一致的状态：原本应该全部入库的文件只有一部分入库，很有可能版本库中的最新版本不能顺利编译，更为严重的是，随着其他的用户执行cvs up&#100;ate 操作，该不一致性将迅速在开发团队中扩散，从而严重影响团队的开发效率，并存在质量隐患。另外，假如该批量提交的中断没有被及时发现，开发团队往往要花更多的时间进行软件调试和排错。<br/><br/><br/><br/>CVS 即使在批量提交不发生中断时也会造成不一致：假设用户A 启动一个需要较长时间才能完成的批量提交；与此同时，用户B 执行cvs up&#100;ate 操作。此时，用户B 很有可能得到一个不一致的更新，即用户B 通过“更新”操作，得到用户A 的部分修改文件。<br/><br/><br/>Subversion 彻底消除了CVS 的以上弊端。无论批量提交包含多少文件修改，只有当全部文件修改都成功入库，该提交才变得有效，才对其他用户可见；否则，无论任何原因造成中断，Subversion 都会自动执行“回滚”（rollback）操作。换一个说法，Subversion 保证所有的修改要么全部入库生效，要么一个也不入库，即对版本库不作任何的修改。这就是Subversion 的原子性提交（atomic commit）。<br/><br/>由于Subversion 的原子性提交特性和全局版本编号方式，当提交成功完成时，一个唯一的、新的全局版本编号产生，而提交时用户提供的日志信息与该新的版本编号关联，只进行一次存储（区别于CVS 的按文件重复存储）。<br/><br/><br/><br/>五、支持变更集概念<br/><br/>由于Subversion 的所有提交是原子性的，每次成功提交形成的唯一的全局版本号对应此次批量提交的所有文件修改，也就是说，一个Subversion 版本号其实对应了一个逻辑上的变更集（change set），该变更集可能对应于对一个BUG 的修复，或者对应于对一个已有功能的改进，或者对应于一个新功能的实现。可以说，变更集是一个软件开发活动的逻辑结果，该变更集可以通过其对应的版本号在软件开发的其他过程中（如软件合并/集成过程，软件发布管理，变更管理系统，缺陷追踪系统）被引用。因此，Subversion 将版本管理从单纯的、单个的文件修改的层次通过逻辑上的抽象，上升到更便于理解和交流的开发活动的层次。<br/><br/>六、差异化的二进制文件处理<br/><br/>由于历史原因，CVS 主要是为早期的程序员设计的，CVS 能够有效处理文本文件（或ASCII文件，源代码文件），可以对文本文件进行差异化的存储、新旧版本的比较，文件合并等；但对于二进制文件，CVS 则明显力不从心。在CVS 的版本库中，对于二进制文件的历史版本，CVS 唯一能做的就是对不同的版本进行独立的、冗余的存储，哪怕版本之间其实只存在微小的差异。举例而言，一个10M 的二进制文件（照片、图形文件、机械设计文件、电子设计文件）假如每周修改一次，无论每次修改的大小，一年下来，仅该文件就要消耗500M 以上的存储空间。而且，客户端每次获取该文件的新版本都要消耗10M 的网络流量。<br/><br/>对于目前的开发团队，无论是软件开发，Web 站点的开发，手机等电子产品的研发，需要进行版本管理的不仅是源代码等文本文件，还需要管理需求文档、设计文档、测试文档、用户手册，图形图像文件，机械/电子设计文件等诸多的二进制文件，CVS 显然不是一个好的选择。<br/><br/><br/>与CVS 不同，Subversion 采用统一的二进制差异算法（binary differencing algorithm），即对文本文件和二进制文件采用相同的差异比较算法，并以相同的方式在版本库中进行存储：每次提交后版本库中只存储相对于先前版本的差异，从而可以节省大量的存储空间。<br/><br/><br/>该二进制差异算法不仅应用在版本的存储上，更为重要的是，Subversion 对二进制文件与文本文件一视同仁，当客户端需要获取新的版本时（如执行svn up&#100;ate），在网络上只有版本的差异被传输，从而大大减少对网络带宽的消耗。更多细节参见“七、双向的差异化－压缩网络传输”。<br/><br/><br/><br/>七、 双向的差异化－压缩网络传输<br/><br/>如上所述，CVS 对二进制文件不能进行有效的差异化处理。对于文本文件，CVS 仅仅支持单向的差异化传输：从CVS 服务器到客户端的传输是差异化的，即执行cvs up&#100;ate 时，只有差异的部分从服务器传输到客户端；而当执行cvs commit 时，无论代码变化多少，CVS 都需要从客户端向服务器完整传输被修改文件的全部内容，不能只传输差异。<br/><br/>相反，无论是文本文件还是二进制文件，Subversion 都进行双向的差异化传输，并且差异化内容还要进行压缩/解压缩的过程：在服务器端获取差异显而易见，与CVS 类似；Subversion 在客户端获取差异的秘密在于 — Subversion 在客户端的工作拷贝中隐含了每个文件的一个“只读的、干净的”副本（该副本隐藏在隐含目录.svn 里，通常不可见，该副本还有更多的妙用，参见“十二、更多的本地/离线操作”），通过比较用户在客户端的修改和该隐含的副本，Subversion 获取需要真正传送到服务器的差异，并对差异进行压缩后才进行网络传输。<br/><br/>对CVS 而言，操作的成本（网络带宽消耗是最大的操作成本）与被修改的文件的大小成比例，而与修改本身的大小无关；对Subversion 而言，操作成本只与修改本身的大小成比例，而与被修改的文件的大小无关。因此，与CVS 相比，Subversion 消耗更少的网络带宽（以客户端的存储空间换取更少的带宽消耗在目前的计算环境下应该是个相当不错的选择！）。Subversion 更加适合基于互联网（或广域网）进行协作开发的地理上分布的团队 — 版本服务器集中、单一；客户端广泛分布。<br/><br/><br/>八、高效、快捷创建分支和基线<br/><br/>CVS 和Subversion 都支持分支（branch）和基线（tag），通过分支与合并，可以有效支持大项目的并行开发模式；通过基线管理，可以准确标识一组文件的版本，有效进行软件发布管理和必要时的历史回溯。<br/><br/>但CVS 和Subversion 在实现分支和基线的方式上存在很大的不同。CVS 在创建分支的时候，需要对所有进行分支的文件进行依次的操作，因此分支的建立成本（主要是建立分支所需的时间，或消耗的计算资源）与参与分支的文件数量成比例，项目越大，版本库越大，文件越多，分支的建立成本越高；基线（tag）的建立与此类似。<br/><br/>Subversion 的分支和基线是通过执行“拷贝”来建立的：回想一下在没有引入版本管理工具的时候我们是如何进行所谓的“分支”和“基线”管理的？答案显然是“拷贝” — 我们通过“拷贝”或“备份”来建立基线；同样，为支持多个开发人员可以同时进行开发，我们为每个开发人员创建一份“拷贝”。由此看来，Subversion 通过“拷贝”来建立分支和基线显得非常自然，有点“返朴归真”的意思。<br/><br/>由于Subversion 的全局版本号特性，Subversion 中分支或基线的创建过程，或Subversion中的“拷贝”过程，真正的操作是在版本库中创建一个到某一全局版本号的指针（pointer），不再需要针对众多的单个文件依次执行操作。因此，该操作的成本为一个很小的常数，与项目大小，版本库大小，文件数目的多少无关；并且，分支或基线的建立不需要进行版本的冗余存储，新建立的分支或基线基本不占用版本库空间，分支的后续存储空间的开销也只与修改的大小有关。<br/><br/><br/>九、集成Apache Web Server，提供更多的特性<br/><br/>Subversion 通过与Apache Web Server 的集成，可以提供基于http/https 协议的版本库访问机制，从而支持Subversion 跨越防火墙的安全访问。除此以外，Subversion 还可以利用更多的Apache 特性，包括但不限于：Apache 丰富的用户认证机制（包括通过LDAP服务器如Windows Active Directory 服务器的用户认证），基于目录路径的精细粒度的访问控制，对传输的网络流量进行压缩/解压缩，浏览版本库目录结构等等。<br/><br/>十、支持WebDAV<br/><br/>WebDAV（Web-based Distributed Authoring and Versioning）是一种基于 HTTP 1.1 协议的通信协议.它扩展了HTTP 1.1，在GET、POST、HEAD 等几个HTTP 标准方法以外添加了一些新的方法，使应用程序可直接对Web Server 直接读写，并支持写文件锁定(Locking)及解锁(Unlock)，还可以支持文件的版本控制。<br/><br/>Microsoft windows2000/XP 及IE, Office 还有Adobe/MicroMedia 的DW 等都支持WebDAV，这又大大增强了Web 应用的价值，以及效能。对于需要大量发布内容的用户而言，应用WebDAV 可以降低对CMS 系统的依赖，而且能够更自由的进行创作。上传、下载变得轻松自如。<br/><br/>Subversion 通过与Apache Web Server 的集成，支持WebDAV 协议，使得业务用户（business users）或非技术用户在不安装任何版本管理客户端的情况下轻松访问Subversion 版本库，不改变业务用户已有使用习惯，支持分布的业务用户对文档的评审、修改并实现版本控制，真正将软件开发的生命周期从开发/技术团队扩展到项目的全部干系人（stakeholder），避免通过电子邮件传递文档的混乱与无序、通过Windows 操作系统共享造成的安全漏洞、病毒攻击、历史版本被覆盖或丢失、审计困难等诸多典型问题。<br/><br/><br/>十一、更好的冲突标识与处理<br/><br/><br/>CVS 和Subversion 都支持通过分支与合并进行并行开发，并可以自动检测到合并时的冲突（conflicts），并在合并结果中以&lt;&lt;&lt;&lt;&lt;&lt; … &gt;&gt;&gt;&gt;&gt;&gt;标识合并的冲突部分。<br/><br/>在CVS 中，经常会出现由于用户的疏忽（如，没有注意到冲突，或没有完全处理好冲突）而将仍然带有&lt;&lt;&lt;&lt;&lt;&lt; … &gt;&gt;&gt;&gt;&gt;&gt;冲突标识符号的文件直接进行提交（commit），从而在版本库中产生垃圾版本。<br/><br/>Subversion 有效解决了CVS 的以上问题：Subversion 记录并保持文件的冲突状态，只有当用户明确执行svn resolved 命令后，该冲突状态标识才被复位，该文件才能被提交，从而大大减少了将仍然带有&lt;&lt;&lt;&lt;&lt;&lt; … &gt;&gt;&gt;&gt;&gt;&gt;冲突标识符号的文件直接进行提交的可能性。<br/><br/>十二、 更多的本地/离线操作<br/><br/>众所周知，CVS 客户端的工作拷贝中包含了一个隐含目录CVS，该目录中记录了客户端需要的一些管理信息；与此类似，Subversion 的客户端工作拷贝中也包含了一个隐含目录.svn，该目录中同样记录了客户端需要的一些管理信息，如版本库URL，当前访问版本号等。<br/><br/>与CVS 不同的是，Subversion 的.svn 目录中还包含了工作拷贝中每一个文件的一个“只读的、干净的”副本。正是由于该副本的存在，使得Subversion 与CVS 相比，可以执行更多的本地/离线操作，即某些操作不需要访问版本库服务器，因此不需要存在从客户端到服务器的网络链接，当然也不消耗任何网络带宽，这进一步增强了Subversion 对广域网的友好支持。<br/><br/>Subversion 的以下命令可以进行离线操作：<br/>svn status － 显示工作拷贝上的本地修改概况；<br/>svn diff －显示工作拷贝上的本地修改细节，比较修改前后的内容；<br/>svn revert － 撤销工作拷贝上的本地修改；<br/><br/>十三、 对符号链接进行版本管理<br/><br/>在Unix 文件系统中，符号链接（symbolic links，包括硬链接和软链接）是一种重要的文件系统元素。CVS 不能对符号链接进行版本管理；Subversion 则可以对符号链接进行版本管理。<br/><br/>十四、 元数据管理<br/><br/>与CVS 相比，Subversion 增加了元数据（metadata）管理机制。即可以对版本库中的文件或目录附加任意的“属性”（property），并记录属性的变化历史，也就是对元数据进行版本管理。一个Subversion 属性是一个“属性名称/属性值”的二元组，如“BugNumber= 100”就是一个属性，可以将该属性附加到版本N 上，以说明版本N 改正了编号为100的BUG。<br/><br/>Subversion 元数据的目的是提供附件的信息以满足流程或过程自动化的需要，以增强Subversion 的管理能力和自动化程度。Subversion 自身就通过“属性”来存储一些特殊的信息。一个使用Subversion 元数据的例子：可以在一些批处理的脚本程序或Subversion的钩子程序（hooks）中创建、访问、修改“属性”元数据来满足流程自动化的要求。]]></description>
		</item>
		
			<item>
			<link>http://www.wolf2999.cn/default.asp?id=832</link>
			<title><![CDATA[软件可靠性工程述评]]></title>
			<author>wolf2999@tom.com(wolf2999)</author>
			<category><![CDATA[软件开发]]></category>
			<pubDate>Sat,05 Dec 2009 08:36:33 +0800</pubDate>
			<guid>http://www.wolf2999.cn/default.asp?id=832</guid>	
		<description><![CDATA[摘要： 本文介绍了软件可靠性技术的发展情况，对各种软件可靠性分析模型进行了分类评述，分析了软件可靠性工程的发展趋势。<br/><br/>关键词： 软件工程 可靠性模型 趋势分析<br/><br/>1 软件危机<br/><br/>随着计算机技术迅猛发展，软件的销售量和使用量呈几何级数增长，软件的规模也越来越大，复杂性急剧提高。例如，航天飞机的飞行软件达50万行源代码，F－22战斗机更达150多万行源代码，软件失效已成为系统瘫痪的主要原因。根据美国国防部和NASA的统计，当今武器系统和航天项目中的软件可靠性比硬件系统大约低一个数量级。因软件故障而造成的重大事故也不乏其例，如F－18战斗机在海湾战争中，飞行控制软件共发生了500多次故障，爱国者导弹因软件问题误伤了28名美国士兵；阿里安5型火箭的发动机控制系统软件的错误导致飞行试验失败等。软件危机使得软件可靠性研究在国际上十分活跃。<br/><br/>2.影响软件可靠性的主要因素<br/><br/>软件产品是由某一计算机语言写成的语句有序集合，也就是计算机程序。它的作用是将输入转换成相应的输出，可以用一映射函数f表示。软件可靠性是指在给定时间内，特定环境下软件无错运行的概率。影响软件可靠性的因素主要包括：<br/><br/>1)软件规模；<br/>&nbsp;&nbsp;2)软件对实际需求的表述上的符合度；<br/>&nbsp;&nbsp;3)软件的运行剖面；<br/>&nbsp;&nbsp;4)软件的内部结构，即软件复杂度；<br/>&nbsp;&nbsp;5)软件的开发方法；<br/>&nbsp;&nbsp;6)软件开发人员的能力和经验；<br/>&nbsp;&nbsp;7)软件开发的支持环境；<br/>&nbsp;&nbsp;8)软件可靠性设计技术；<br/>&nbsp;&nbsp;9)软件的测试与投放方式等。<br/><br/>如何准确评价／预计软件的使用可靠性是软件工程的重大问题之一。<br/><br/>3.软件可靠性模型及其分类<br/><br/>一个有效的软件可靠性模型应尽可能地将上面所述的因素在软件可靠性建模时加以考虑，尽可能简明地反映出来。自1972年第一个软件可靠性分析模型发表的二十多年来，见之于文献的软件可靠性统计分析模型将近百种。<br/><br/>这些可靠性模型大致可分为10类［1］：<br/>&nbsp;&nbsp;1)种子法；<br/>&nbsp;&nbsp;2)失效率类；<br/>&nbsp;&nbsp;3)曲线拟合类；<br/>&nbsp;&nbsp;4)可靠性增长模型；<br/>&nbsp;&nbsp;5)程序结构分析模型；<br/>&nbsp;&nbsp;6)输入域分类模型；<br/>&nbsp;&nbsp;7)执行路径分析方法模型；<br/>&nbsp;&nbsp;8)非齐次Poisson过程模型；<br/>&nbsp;&nbsp;9)马尔可夫过程模型；<br/>&nbsp;&nbsp;10)贝叶斯模型类。<br/><br/>种子法<br/><br/>这是利用捕获—再捕获抽样技术估计程序中错误数。在程序中预先有意“播种”一些设定的错误“种子”，然后根据测试出的原始错误数和发现的诱导错误的比例来估计程序中残留的错误数。其优点是简便易行，缺点是诱导错误的“种子”与实际的原始错误之间的类比性估量困难。<br/><br/>失效率分析<br/><br/>这类模型用来研究程序的失效率的。因为MTBF是失效率的倒数，所以以MTBF为分析直接变量的模型亦属于此类。这类模型有<br/>&nbsp;&nbsp;1)Jelinski－Moranda的de－eutrophication模型<br/>&nbsp;&nbsp;2)Jelinski－Moranda的几何de－eutrophication模型<br/>&nbsp;&nbsp;3)Schick－Wolverton模型<br/>&nbsp;&nbsp;4)改进的Schick－Wolverton模型<br/>&nbsp;&nbsp;5)Moranda的几何Poisson模型<br/>&nbsp;&nbsp;6)Goal和Okumoto不完全排错模型<br/><br/>曲线拟合<br/><br/>用回归分析的方法研究软件复杂性、程序中的缺陷数、失效率、失效间隔时间。包括参数方法和非参数方法。<br/><br/>可靠性增长<br/><br/>预测软件在检错过程中的可靠性改进，用一增长函数来描述软件的改进过程。这类模型有：<br/>&nbsp;&nbsp;1)Duane模型<br/>&nbsp;&nbsp;2)Weibull模型<br/>&nbsp;&nbsp;3)Wagoner的Weibull改进模型<br/>&nbsp;&nbsp;4)Yamada和Osaki的逻辑增长曲线<br/>&nbsp;&nbsp;5)Gompertz的增长曲线<br/><br/>程序结构分析<br/><br/>程序结构模型是根据程序、子程序及其相互间的调用关系，形成一个可靠性分析网络。网络中的每一结点代表一个子程序或一个模块，网络中的每一有向弧代表模块间的程序执行顺序。假定各结点的可靠性是相互独立的，通过对每一个结点可靠性、结点间转换的可靠性和网络在结点间的转换概率，得出该持续程序的整体可靠性。在软件测试领域，有人形象地称这种方法为“白盒子”方法(white box)。这类模型有：<br/>&nbsp;&nbsp;1)Littewoood马尔可夫结构模型<br/>&nbsp;&nbsp;2)Cheung的面向用户的马尔可夫模型<br/><br/>输入域<br/><br/>选取软件输入域中的某些样本“点”运行程序，根据这些样本点在“实际”使用环境中的使用概率的测试运行时的成功率／失效率，推断软件的使用可靠性。这类模型的重点(亦是难点)是输入域的概率分布的确定及对软件运行剖面的正确描述。这种方法不考虑软件的结构和运行路径及开发过程，亦称“黑盒子”方法(black box)。这类模型有两个：<br/>&nbsp;&nbsp;1)Nelson模型<br/>&nbsp;&nbsp;2)Bastani的基于输入域的随机过程模型<br/><br/>执行路径<br/><br/>这类模型的分析方法与上面的模型相似，先计算程序各逻辑路径的执行概率和程序中错误路径的执行概率，再综合出该软件的使用可靠性。<br/><br/>Shooman分解模型属于此类<br/><br/>NHPP<br/><br/>NHPP，即非齐次Poisson过程模型是以软件测试过程中单位时间的失效次数为独立Poisson随机变量，来预测在今后软件的某使用时间点的累计失效数。有：<br/>&nbsp;&nbsp;1)Musa的指数模型<br/>&nbsp;&nbsp;2)Goel和Okumoto的NHPP模型<br/>&nbsp;&nbsp;3)S－型可靠性增长模型<br/>&nbsp;&nbsp;4)超指数增长模型<br/>&nbsp;&nbsp;5)Pham改进的NHPP模型<br/><br/>Markov模型<br/><br/>这类模型有：<br/>&nbsp;&nbsp;1)完全改错的线性死亡模型<br/>&nbsp;&nbsp;2)不完全改错的线性死亡模型<br/>&nbsp;&nbsp;3)完全改错的非静态线性死亡模型<br/><br/>Bayesian类<br/><br/>这是利用失效率的验前分布和当前的测试失效信息来评估软件的可靠性。这是一类当软件可靠性工程师对软件的开发过程有充分的了解，软件的继承性比较好时具有良好效果的可靠性分析模型。<br/><br/>连续时间的离散型Markov链 <br/>Shock模型 <br/>此外，Musa和Okumoto依据模型的如下特征对模型进行分类：<br/>&nbsp;&nbsp;(1)时间域：有两种：a.时钟时间；b.CPU时间。<br/>&nbsp;&nbsp;(2)失效数类：在有限时间间隔内设定软件的失效数为有限还是无限。<br/>&nbsp;&nbsp;(3)相对于时间系统失效数的统计分布形式。主要的两类是：Poisson分布型和二项分布型。<br/>&nbsp;&nbsp;(4)对有限失效数而言，用时间表示的失效强度的函数形式。<br/>&nbsp;&nbsp;(5)对有限失效数而言，用经验期望失效数表示的失效强度的函数形式。<br/><br/>4.软件可靠性模型研究的<br/><br/>五个方向<br/><br/>以上归类介绍了的几十个软件可靠性模型，其中有的已被西方某些可靠性公司制成标准的工具软件出售［4］，如Musa－Okumoto模型、Jelinski－Moranda模型、NHPP模型、S－shaped模型、Duane模型、Little－Verral模型等。而且还有新的模型发表。这些模型的应用都有局限性，要根据具体软件的规模、开发和使用环境、开发人员的素质、开发方法进行妥善选择，读者可参考［5］中的有关模型选用的章节。<br/><br/>由于软件缺陷的特殊性，至今尚没有一种软件可靠性的通用统计分析模型。其主要原因是这些模型对系统所做的假设固定不变，而软件在其开发过程中受各种因素影响，使得软件的故障行为千差万别；在进行模型的参数估计时又难以实时获得充分的统计数据，无法在各种模型之间作识别，导致估计结果与实际情况的不一致，即产生模型的不适配问题。<br/><br/>为了使对软件可靠性的分析、预计更加精确，除了应用标准的软件可靠性模型的传统方法外，目前软件可靠性研究的内容有：<br/>&nbsp;&nbsp;1)对传统模型的分析结果用U－结构图进行校正，以减少评价模型的偏差。<br/>&nbsp;&nbsp;2)将两个或多个传统模型用加权的方法进行线性组合，或者在软件寿命周期的不同阶段使用不同的评价模型。<br/>&nbsp;&nbsp;3)在传统模型中引入软件复杂性和测试类型、开发方法类型影响因子，以增强可靠性评价的准确性。<br/>&nbsp;&nbsp;4)软件可靠性仿真技术(以后将专门介绍)。<br/>&nbsp;&nbsp;5)神经网络分析技术<br/><br/>人工神经网络是基于现代科学对生物神经系统的认识，得出的一种抽象的新型数学模型，借助于计算机技术，使它具有人工智能、自适应能力和学习功能。它不事先确定模型，而是按实例研究的原则运行，是一种非参数软件可靠性估计，克服了模型的实配问题，通用性好(缺点是模型复杂)。从八十年代末和九十年代初期以来和工具，研究保证软件可靠性的开发方法和可靠性管理措施是软件可靠性工程师的责任。软件规模、复杂程度的大幅度提高，大型系统对软件的严重依赖，国际上开展了神经网络技术在软件可靠性工程中的应用研究，取得了一些成果，其工程应用亦在试验之中。我们中心正在开展这一技术的理论研究，并着手开发相应的通用软件工具，相信会有良好的工程应用前景。<br/><br/>5.软件工程化与软件可靠性<br/><br/>在近可能短的开发周期内向用户提供高可靠软件是软件工程师的艰巨任务。提供有效的软件可靠性评测方法，要求软件的开发从“自编、自导、自演”的初级模式向工程化方向转化。<br/><br/>软件工程是一项新兴的系统工程，软件的工程化提出了一些软件开发的基本原则和要求。其中，为保证大型软件的可靠性，必须遵循的原则包括：<br/>&nbsp;&nbsp;1)软件的设计(design)、编码(coding)、测试(testing)由不同的人员完成，独立的验证／确认(IV&amp;V)、象硬件那样设计、生产、检验分开；<br/>&nbsp;&nbsp;2)软件开发和使用过程具有可追溯性，象硬件有设计图纸、生产记录、检验结果那样有各种文档；<br/>&nbsp;&nbsp;3)像硬件那样尽可能使用标准件(标准子程序／模块)和成熟技术(经过验证的开发过程和算法)。<br/><br/>软件工程、软件可靠性工程研究与应用的共性技术包括：<br/>&nbsp;&nbsp;1)软件故障树分析(S－FTA)<br/>&nbsp;&nbsp;2)软件故障模式和影响分析(S－FMEA)<br/>&nbsp;&nbsp;3)危险性分析<br/>&nbsp;&nbsp;4)软件潜在通路分析<br/>&nbsp;&nbsp;5)安全性分析(Petri Net等)。<br/>&nbsp;&nbsp;6)软件的避错(fault avoidance)、排错(fault removal)、容错(fault tolerance)、预错(fault forcasting)等。<br/><br/>软件可靠性的提高依赖于软件工程化的步伐。<br/><br/>参考文献<br/><br/>1.Pham,H,Software Reliability and Testing,IEEE Computer Society Press,1996.<br/><br/>2.Jelinski,Z.,and P.B.Moranda,W.Freiberger ed.,Statistical ComputerPerformance Evaluation,Academic Press,New York,1972.<br/><br/>3.Schick,G.J.,and R.W.Wolerton,“An Analysis of Competing Software Reliability Models”,IEEE Trans.Software Engineering,Vol.SE－4，No.2,Mar.,1978.<br/><br/>4.Michael R.Lyu,Handbook of Software Reliability Engineering,Computing Mc GrawHill,New York,1996.<br/><br/>5.何国伟主编 软件可靠性，国防工业出版社，1998。<br/><br/>6.IEEE Std 6 10.12－1990，Glossary of Software Engineering Terminology.<br/><br/>7.Shooman,M.L,&#34;Structure Models for Software Reliability Prediction”Proc,International Conference of Software Engineering.,IEEE Cs Press,Los Alamitos，Califolia.,1984.<br/><br/>8.Yamada,S &#34;S－shaped Software Reliability Growth Models and Their Applications”，IEEETrans.Reliability,Vol.R－33，No.4，Oct.1984.<br/><br/>9.Musa.J.D.A Logarithmic Poisson Execution Time Model For Software Reliability Measurement，Proc.7th International Conf.Software Ing.,1984.<br/><br/>10.Littlewood,B.,“Software Reliability Model for Modular Program Structure”,IEEE Trsans.Reliability,Vol.R－28，No.3,Aug.1979.]]></description>
		</item>
		
			<item>
			<link>http://www.wolf2999.cn/default.asp?id=831</link>
			<title><![CDATA[写出漂亮代码的七种方法]]></title>
			<author>wolf2999@tom.com(wolf2999)</author>
			<category><![CDATA[软件开发]]></category>
			<pubDate>Sat,05 Dec 2009 08:34:10 +0800</pubDate>
			<guid>http://www.wolf2999.cn/default.asp?id=831</guid>	
		<description><![CDATA[原文地址:<a href="http://news.csdn.net/n/20081217/121810.html" target="_blank">http://news.csdn.net/n/20081217/121810.html</a> <br/><br/>首先我想说明我本文阐述的是纯粹从美学的角度来写出代码，而非技术、逻辑等。以下为写出漂亮代码的七种方法：<br/><br/>1， 尽快结束 if语句<br/><br/>例如下面这个JavaScript语句，看起来就很恐怖：<br/><div class="UBBPanel"><div class="UBBTitle"><img src="http://www.wolf2999.cn/images/code.gif" style="margin:0px 2px -3px 0px" alt="程序代码"/> 程序代码</div><div class="UBBContent"><br/> function findShape(flags, point, attribute, list) {<br/>&nbsp;&nbsp;&nbsp;&nbsp;if(!findShapePoints(flags, point, attribute)) {<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(!doFindShapePoints(flags, point, attribute)) {<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(!findInShape(flags, point, attribute)) {<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(!findFromGuide(flags,point) {<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(list.count() &gt; 0 &amp;&amp; flags == 1) {<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;doSomething();<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br/>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp; <br/>&nbsp;&nbsp;}<br/></div></div><br/><br/>但如果这么写就好看得多：<br/><div class="UBBPanel"><div class="UBBTitle"><img src="http://www.wolf2999.cn/images/code.gif" style="margin:0px 2px -3px 0px" alt="程序代码"/> 程序代码</div><div class="UBBContent"><br/> function findShape(flags, point, attribute, list) {<br/>&nbsp;&nbsp;&nbsp;&nbsp;if(findShapePoints(flags, point, attribute)) {<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return;<br/>&nbsp;&nbsp;&nbsp;&nbsp;}<br/> <br/>&nbsp;&nbsp;&nbsp;&nbsp;if(doFindShapePoints(flags, point, attribute)) {<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return;<br/>&nbsp;&nbsp;&nbsp;&nbsp;}<br/> <br/>&nbsp;&nbsp;&nbsp;&nbsp;if(findInShape(flags, point, attribute)) { <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return;<br/>&nbsp;&nbsp;&nbsp;&nbsp;}<br/> <br/>&nbsp;&nbsp;&nbsp;&nbsp;if(findFromGuide(flags,point) {<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return;<br/>&nbsp;&nbsp;&nbsp;&nbsp;}<br/> <br/>&nbsp;&nbsp;&nbsp;&nbsp;if (!(list.count() &gt; 0 &amp;&amp; flags == 1)) {<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return;<br/>&nbsp;&nbsp;&nbsp;&nbsp;}<br/> <br/>&nbsp;&nbsp;&nbsp;&nbsp;doSomething();<br/> <br/>}</div></div><br/><br/>你可能会很不喜欢第二种的表述方式，但反映出了迅速返回if值的思想，也可以理解为：避免不必要的else陈述。<br/><br/>2， 如果只是简单的布尔运算（逻辑运算），不要使用if语句<br/><br/>例如：<br/><div class="UBBPanel"><div class="UBBTitle"><img src="http://www.wolf2999.cn/images/code.gif" style="margin:0px 2px -3px 0px" alt="程序代码"/> 程序代码</div><div class="UBBContent"><br/> function isStringEmpty(str){<br/>&nbsp;&nbsp;&nbsp;&nbsp;if(str === &#34;&#34;) { <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return true;<br/>&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;else {<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return false;<br/>&nbsp;&nbsp;&nbsp;&nbsp;}<br/> }</div></div><br/><br/>可以写为：<br/><div class="UBBPanel"><div class="UBBTitle"><img src="http://www.wolf2999.cn/images/code.gif" style="margin:0px 2px -3px 0px" alt="程序代码"/> 程序代码</div><div class="UBBContent"><br/> function isStringEmpty(str){<br/>&nbsp;&nbsp;&nbsp;&nbsp;return (str === &#34;&#34;);<br/> }</div></div><br/><br/>3， 使用空白，这是免费的<br/>例如：<br/><div class="UBBPanel"><div class="UBBTitle"><img src="http://www.wolf2999.cn/images/code.gif" style="margin:0px 2px -3px 0px" alt="程序代码"/> 程序代码</div><div class="UBBContent"><br/> function getSomeAngle() {<br/>&nbsp;&nbsp;&nbsp;&nbsp;// Some code here then<br/>&nbsp;&nbsp;&nbsp;&nbsp;radAngle1 = Math.atan(slope(center, point1));<br/>&nbsp;&nbsp;&nbsp;&nbsp;radAngle2 = Math.atan(slope(center, point2));<br/>&nbsp;&nbsp;&nbsp;&nbsp;firstAngle = getStartAngle(radAngle1, point1, center);<br/>&nbsp;&nbsp;&nbsp;&nbsp;secondAngle = getStartAngle(radAngle2, point2, center);<br/>&nbsp;&nbsp;&nbsp;&nbsp;radAngle1 = degreesToRadians(firstAngle);<br/>&nbsp;&nbsp;&nbsp;&nbsp;radAngle2 = degreesToRadians(secondAngle);<br/>&nbsp;&nbsp;&nbsp;&nbsp;baseRadius = distance(point, center);<br/>&nbsp;&nbsp;&nbsp;&nbsp;radius = baseRadius + (lines * y);<br/>&nbsp;&nbsp;&nbsp;&nbsp;p1[&#34;x&#34;] = roundValue(radius * Math.cos(radAngle1) + center[&#34;x&#34;]);<br/>&nbsp;&nbsp;&nbsp;&nbsp;p1[&#34;y&#34;] = roundValue(radius * Math.sin(radAngle1) + center[&#34;y&#34;]);<br/>&nbsp;&nbsp;&nbsp;&nbsp;pt2[&#34;x&#34;] = roundValue(radius * Math.cos(radAngle2) + center[&#34;y&#34;]);<br/>&nbsp;&nbsp;&nbsp;&nbsp;pt2[&#34;y&#34;] = roundValue(radius * Math.sin(radAngle2) + center[&#34;y&#34;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;// Now some more code<br/> }</div></div><br/><br/>很多开发者不愿意使用空白，就好像这要收费一样。我在此并非刻意地添加空白，粗鲁地打断代码的连贯性。在实际编写代码的过程中，会很容易地发现在什么地方加入空白，这不但美观而且让读者易懂，如下：<br/><div class="UBBPanel"><div class="UBBTitle"><img src="http://www.wolf2999.cn/images/code.gif" style="margin:0px 2px -3px 0px" alt="程序代码"/> 程序代码</div><div class="UBBContent"> function getSomeAngle() {<br/>&nbsp;&nbsp;&nbsp;&nbsp;// Some code here then<br/>&nbsp;&nbsp;&nbsp;&nbsp;radAngle1 = Math.atan(slope(center, point1));<br/>&nbsp;&nbsp;&nbsp;&nbsp;radAngle2 = Math.atan(slope(center, point2));<br/> <br/>&nbsp;&nbsp;&nbsp;&nbsp;firstAngle = getStartAngle(radAngle1, point1, center);<br/>&nbsp;&nbsp;&nbsp;&nbsp;secondAngle = getStartAngle(radAngle2, point2, center);<br/> <br/>&nbsp;&nbsp;&nbsp;&nbsp;radAngle1 = degreesToRadians(firstAngle);<br/>&nbsp;&nbsp;&nbsp;&nbsp;radAngle2 = degreesToRadians(secondAngle);<br/> <br/>&nbsp;&nbsp;&nbsp;&nbsp;baseRadius = distance(point, center);<br/>&nbsp;&nbsp;&nbsp;&nbsp;radius = baseRadius + (lines * y);<br/> <br/>&nbsp;&nbsp;&nbsp;&nbsp;p1[&#34;x&#34;] = roundValue(radius * Math.cos(radAngle1) + center[&#34;x&#34;]);<br/>&nbsp;&nbsp;&nbsp;&nbsp;p1[&#34;y&#34;] = roundValue(radius * Math.sin(radAngle1) + center[&#34;y&#34;]);<br/> <br/>&nbsp;&nbsp;&nbsp;&nbsp;pt2[&#34;x&#34;] = roundValue(radius * Math.cos(radAngle2) + center[&#34;y&#34;]);<br/>&nbsp;&nbsp;&nbsp;&nbsp;pt2[&#34;y&#34;] = roundValue(radius * Math.sin(radAngle2) + center[&#34;y&#34;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;// Now some more code<br/> }</div></div><br/><br/>4， 不要使用无谓的注释<br/>无谓的注释让人费神，这实在很讨厌。不要标出很明显的注释。在以下的例子中，每个人都知道代码表达的是“students id”，因而没必要标出。<br/><div class="UBBPanel"><div class="UBBTitle"><img src="http://www.wolf2999.cn/images/code.gif" style="margin:0px 2px -3px 0px" alt="程序代码"/> 程序代码</div><div class="UBBContent"> function existsStudent(id, list) {<br/>&nbsp;&nbsp;&nbsp;&nbsp;for(i = 0; i &lt; list.length; i++) {<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; student = list;<br/> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Get the student&#39;s id<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; thisId = student.getId();<br/> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(thisId === id) {<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return true;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br/>&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;return false;&nbsp;&nbsp; <br/> }</div></div><br/><br/>5， 不要在源文件中留下已经删除的代码，哪怕你标注了<br/>如果你使用了版本控制，那么你就可以轻松地找回前一个版本的代码。如果别人大费周折地读了你的代码,却发现是要删除的代码，这实在太恨人了。<br/><br/><div class="UBBPanel"><div class="UBBTitle"><img src="http://www.wolf2999.cn/images/code.gif" style="margin:0px 2px -3px 0px" alt="程序代码"/> 程序代码</div><div class="UBBContent"><br/>//function thisReallyHandyFunction() {<br/>//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;someMagic();<br/>//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;someMoreMagic();<br/>//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;magicNumber = evenMoreMagic();<br/>//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return magicNumber;<br/>//}</div></div><br/><br/>6，不要有太长的代码<br/><br/>看太长的代码实在太费劲，尤其是代码本身的功能又很小。如下：<br/><br/><div class="UBBPanel"><div class="UBBTitle"><img src="http://www.wolf2999.cn/images/code.gif" style="margin:0px 2px -3px 0px" alt="程序代码"/> 程序代码</div><div class="UBBContent"> public static EnumMap&lt;Category, IntPair&gt; getGroupCategoryDistribution(EnumMap&lt;Category, Integer&gt; sizes, int groups) {<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; EnumMap&lt;Category, IntPair&gt; categoryGroupCounts = new EnumMap&lt;Category,IntPair&gt;(Category.class);<br/> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(Category cat : Category.values()) {<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; categoryGroupCounts.put(cat, getCategoryDistribution(sizes.get(cat), groups));<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</div></div><br/><br/>我并不是说非要坚持70个字符以内，但是一个比较理想的长度是控制在120个字符内。如果你把代码发布在互联网上，用户读起来就很困难。<br/><br/>7，不要在一个功能（或者函数内）有太多代码行<br/>我的一个老同事曾经说Visual C++很臭，因为它不允许你在一个函数内拥有超过10，000行代码。我记不清代码行数的上限，不知道他说的是否正确，但我很不赞成他的观点。如果一个函数超过了50行，看起来有多费劲你知道么，还有没完没了的if循环，而且你还的滚动鼠标前后对照这段代码。对我而言，超过35行的代码理解起来就很困难了。我的建议是超过这个数字就把一个函数代码分割成两个。]]></description>
		</item>
		
			<item>
			<link>http://www.wolf2999.cn/default.asp?id=826</link>
			<title><![CDATA[BUG管理的经验和实践]]></title>
			<author>wolf2999@tom.com(wolf2999)</author>
			<category><![CDATA[软件开发]]></category>
			<pubDate>Sat,05 Dec 2009 08:07:07 +0800</pubDate>
			<guid>http://www.wolf2999.cn/default.asp?id=826</guid>	
		<description><![CDATA[<a href="http://www.wolf2999.cn/down/Bug1.pdf" target="_blank">http://www.wolf2999.cn/down/Bug1.pdf</a><br/><br/><a href="http://www.wolf2999.cn/down/Bug2.pdf" target="_blank">http://www.wolf2999.cn/down/Bug2.pdf</a><br/><br/><a href="http://www.wolf2999.cn/down/Bug3.pdf" target="_blank">http://www.wolf2999.cn/down/Bug3.pdf</a><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>]]></description>
		</item>
		
			<item>
			<link>http://www.wolf2999.cn/default.asp?id=712</link>
			<title><![CDATA[Java异常]]></title>
			<author>wolf2999@tom.com(wolf2999)</author>
			<category><![CDATA[软件开发]]></category>
			<pubDate>Tue,14 Jul 2009 23:06:17 +0800</pubDate>
			<guid>http://www.wolf2999.cn/default.asp?id=712</guid>	
		<description><![CDATA[转自：<a href="http://www.blogjava.net/freeman1984/archive/2007/09/27/148850.html" target="_blank">http://www.blogjava.net/freeman1984/archive/2007/09/27/148850.html</a><br/><br/>六种异常处理的陋习<br/><br/>你觉得自己是一个Java专家吗？是否肯定自己已经全面掌握了Java的异常处理机制？在下面这段代码中，你能够迅速找出异常处理的六个问题吗？ <br/><br/><br/><div class="UBBPanel"><div class="UBBTitle"><img src="http://www.wolf2999.cn/images/code.gif" style="margin:0px 2px -3px 0px" alt="程序代码"/> 程序代码</div><div class="UBBContent"><br/> OutputStreamWriter out = ... <br/>java.sql.Connection conn = ... <br/> try { // ⑸ <br/> 　Statement stat = conn.cr&#101;ateStatement(); <br/> 　ResultSet rs = stat.executeQuery( <br/> 　　&#34;sel&#101;ct uid, name from user&#34;); <br/> 　while (rs.next()) <br/> 　{ <br/>　　out.println(&#34;ID：&#34; + rs.getString(&#34;uid&#34;) // ⑹ <br/> 　　　&#34;，姓名：&#34; + rs.getString(&#34;name&#34;)); <br/> 　} <br/> 　conn.close(); // ⑶ <br/> 　out.close(); <br/> } <br/> catch(Exception ex) // ⑵ <br/> { <br/> 　ex.printStackTrace(); //⑴，⑷ <br/> } <br/><br/></div></div><br/><br/>　　作为一个Java程序员，你至少应该能够找出两个问题。但是，如果你不能找出全部六个问题，请继续阅读本文。 <br/><br/>　　本文讨论的不是Java异常处理的一般性原则，因为这些原则已经被大多数人熟知。我们要做的是分析各种可称为“反例”（anti-pattern）的违背优秀编码规范的常见坏习惯，帮助读者熟悉这些典型的反面例子，从而能够在实际工作中敏锐地察觉和避免这些问题。 <br/><br/>　　反例之一：丢弃异常 <br/><br/>　　代码：15行-18行。 <br/><br/>　　这段代码捕获了异常却不作任何处理，可以算得上Java编程中的杀手。从问题出现的频繁程度和祸害程度来看，它也许可以和C/C++程序的一个恶名远播的问题相提并论??不检查缓冲区是否已满。如果你看到了这种丢弃（而不是抛出）异常的情况，可以百分之九十九地肯定代码存在问题（在极少数情况下，这段代码有存在的理由，但最好加上完整的注释，以免引起别人误解）。 <br/><br/>　　这段代码的错误在于，异常（几乎）总是意味着某些事情不对劲了，或者说至少发生了某些不寻常的事情，我们不应该对程序发出的求救信号保持沉默和无动于衷。调用一下printStackTrace算不上“处理异常”。不错，调用printStackTrace对调试程序有帮助，但程序调试阶段结束之后，printStackTrace就不应再在异常处理模块中担负主要责任了。 <br/><br/>　　丢弃异常的情形非常普遍。打开JDK的ThreadDeath类的文档，可以看到下面这段说明：“特别地，虽然出现ThreadDeath是一种‘正常的情形’，但ThreadDeath类是Error而不是Exception的子类，因为许多应用会捕获所有的Exception然后丢弃它不再理睬。”这段话的意思是，虽然ThreadDeath代表的是一种普通的问题，但鉴于许多应用会试图捕获所有异常然后不予以适当的处理，所以JDK把ThreadDeath定义成了Error的子类，因为Error类代表的是一般的应用不应该去捕获的严重问题。可见，丢弃异常这一坏习惯是如此常见，它甚至已经影响到了Java本身的设计。 <br/><br/>　　那么，应该怎样改正呢？主要有四个选择： <br/><br/>　　1、处理异常。针对该异常采取一些行动，例如修正问题、提醒某个人或进行其他一些处理，要根据具体的情形确定应该采取的动作。再次说明，调用printStackTrace算不上已经“处理好了异常”。 <br/><br/>　　2、重新抛出异常。处理异常的代码在分析异常之后，认为自己不能处理它，重新抛出异常也不失为一种选择。 <br/><br/>　　3、把该异常转换成另一种异常。大多数情况下，这是指把一个低级的异常转换成应用级的异常（其含义更容易被用户了解的异常）。 <br/><br/>　　4、不要捕获异常。 <br/><br/>　　结论一：既然捕获了异常，就要对它进行适当的处理。不要捕获异常之后又把它丢弃，不予理睬。 <br/><br/>　　反例之二：不指定具体的异常 <br/><br/>　　代码：15行。 <br/><br/>　　许多时候人们会被这样一种“美妙的”想法吸引：用一个catch语句捕获所有的异常。最常见的情形就是使用catch(Exception ex)语句。但实际上，在绝大多数情况下，这种做法不值得提倡。为什么呢？ <br/><br/>　　要理解其原因，我们必须回顾一下catch语句的用途。catch语句表示我们预期会出现某种异常，而且希望能够处理该异常。异常类的作用就是告诉Java编译器我们想要处理的是哪一种异常。由于绝大多数异常都直接或间接从java.lang.Exception派生，catch(Exception ex)就相当于说我们想要处理几乎所有的异常。 <br/><br/>　　再来看看前面的代码例子。我们真正想要捕获的异常是什么呢？最明显的一个是SQLException，这是JDBC操作中常见的异常。另一个可能的异常是IOException，因为它要操作OutputStreamWriter。显然，在同一个catch块中处理这两种截然不同的异常是不合适的。如果用两个catch块分别捕获SQLException和IOException就要好多了。这就是说，catch语句应当尽量指定具体的异常类型，而不应该指定涵盖范围太广的Exception类。 <br/><br/>　　另一方面，除了这两个特定的异常，还有其他许多异常也可能出现。例如，如果由于某种原因，executeQuery返回了null，该怎么办？答案是让它们继续抛出，即不必捕获也不必处理。实际上，我们不能也不应该去捕获可能出现的所有异常，程序的其他地方还有捕获异常的机会??直至最后由JVM处理。 <br/><br/>　　结论二：在catch语句中尽可能指定具体的异常类型，必要时使用多个catch。不要试图处理所有可能出现的异常。 <br/><br/>　　反例之三：占用资源不释放 <br/><br/>　　代码：3行-14行。 <br/><br/>　　异常改变了程序正常的执行流程。这个道理虽然简单，却常常被人们忽视。如果程序用到了文件、Socket、JDBC连接之类的资源，即使遇到了异常，也要正确释放占用的资源。为此，Java提供了一个简化这类操作的关键词finally。 <br/><br/>　　finally是样好东西：不管是否出现了异常，Finally保证在try/catch/finally块结束之前，执行清理任务的代码总是有机会执行。遗憾的是有些人却不习惯使用finally。 <br/><br/>　　当然，编写finally块应当多加小心，特别是要注意在finally块之内抛出的异常??这是执行清理任务的最后机会，尽量不要再有难以处理的错误。 <br/><br/>　　结论三：保证所有资源都被正确释放。充分运用finally关键词。<br/><br/>反例之四：不说明异常的详细信息 <br/><br/>　　代码：3行-18行。 <br/><br/>　　仔细观察这段代码：如果循环内部出现了异常，会发生什么事情？我们可以得到足够的信息判断循环内部出错的原因吗？不能。我们只能知道当前正在处理的类发生了某种错误，但却不能获得任何信息判断导致当前错误的原因。 <br/><br/>　　printStackTrace的堆栈跟踪功能显示出程序运行到当前类的执行流程，但只提供了一些最基本的信息，未能说明实际导致错误的原因，同时也不易解读。 <br/><br/>　　因此，在出现异常时，最好能够提供一些文字信息，例如当前正在执行的类、方法和其他状态信息，包括以一种更适合阅读的方式整理和组织printStackTrace提供的信息。 <br/><br/>　　结论四：在异常处理模块中提供适量的错误原因信息，组织错误信息使其易于理解和阅读。 <br/><br/>　　反例之五：过于庞大的try块 <br/><br/>　　代码：3行-14行。 <br/><br/>　　经常可以看到有人把大量的代码放入单个try块，实际上这不是好习惯。这种现象之所以常见，原因就在于有些人图省事，不愿花时间分析一大块代码中哪几行代码会抛出异常、异常的具体类型是什么。把大量的语句装入单个巨大的try块就象是出门旅游时把所有日常用品塞入一个大箱子，虽然东西是带上了，但要找出来可不容易。 <br/><br/>　　一些新手常常把大量的代码放入单个try块，然后再在catch语句中声明Exception，而不是分离各个可能出现异常的段落并分别捕获其异常。这种做法为分析程序抛出异常的原因带来了困难，因为一大段代码中有太多的地方可能抛出Exception。 <br/><br/>　　结论五：尽量减小try块的体积。 <br/><br/>　　反例之六：输出数据不完整 <br/><br/>　　代码：7行-11行。 <br/><br/>　　不完整的数据是Java程序的隐形杀手。仔细观察这段代码，考虑一下如果循环的中间抛出了异常，会发生什么事情。循环的执行当然是要被打断的，其次，catch块会执行??就这些，再也没有其他动作了。已经输出的数据怎么办？使用这些数据的人或设备将收到一份不完整的（因而也是错误的）数据，却得不到任何有关这份数据是否完整的提示。对于有些系统来说，数据不完整可能比系统停止运行带来更大的损失。 <br/><br/>　　较为理想的处置办法是向输出设备写一些信息，声明数据的不完整性；另一种可能有效的办法是，先缓冲要输出的数据，准备好全部数据之后再一次性输出。 <br/><br/>　　结论六：全面考虑可能出现的异常以及这些异常对执行流程的影响。 <br/><br/>　　改写后的代码 <br/><br/>　　根据上面的讨论，下面给出改写后的代码。也许有人会说它稍微有点?嗦，但是它有了比较完备的异常处理机制。 <br/><div class="UBBPanel"><div class="UBBTitle"><img src="http://www.wolf2999.cn/images/code.gif" style="margin:0px 2px -3px 0px" alt="程序代码"/> 程序代码</div><div class="UBBContent"><br/>OutputStreamWriter out = ... <br/>java.sql.Connection conn = ... <br/>try { <br/>　Statement stat = conn.cr&#101;ateStatement(); <br/>　ResultSet rs = stat.executeQuery( <br/>　　&#34;sel&#101;ct uid, name from user&#34;); <br/>　while (rs.next()) <br/>　{ <br/>　　out.println(&#34;ID：&#34; + rs.getString(&#34;uid&#34;) + &#34;，姓名: &#34; + rs.getString(&#34;name&#34;)); <br/>　} <br/>} <br/>catch(SQLException sqlex) <br/>{ <br/>　out.println(&#34;警告：数据不完整&#34;); <br/>　throw new ApplicationException(&#34;读取数据时出现SQL错误&#34;, sqlex); <br/>} <br/>catch(IOException ioex) <br/>{ <br/>　throw new ApplicationException(&#34;写入数据时出现IO错误&#34;, ioex); <br/>} <br/>finally <br/>{ <br/>　if (conn != null) { <br/>　　try { <br/>　　　conn.close(); <br/>　　} <br/>　　catch(SQLException sqlex2) <br/>　　{ <br/>　　　System.err(this.getClass().getName() + &#34;.mymethod - 不能关闭数据库连接: &#34; + sqlex2.toString()); <br/>　　} <br/>　} <br/><br/>　if (out != null) { <br/>　　try { <br/>　　　out.close(); <br/>　　} <br/>　　catch(IOException ioex2) <br/>　　{ <br/>　　　System.err(this.getClass().getName() + &#34;.mymethod - 不能关闭输出文件&#34; + ioex2.toString()); <br/>　　} <br/>　} <br/>}&nbsp;&nbsp;<br/><br/></div></div><br/>　　本文的结论不是放之四海皆准的教条，有时常识和经验才是最好的老师。如果你对自己的做法没有百分之百的信心，务必加上详细、全面的注释。 <br/><br/>　　另一方面，不要笑话这些错误，不妨问问你自己是否真地彻底摆脱了这些坏习惯。即使最有经验的程序员偶尔也会误入歧途，原因很简单，因为它们确确实实带来了“方便”。所有这些反例都可以看作Java编程世界的恶魔，它们美丽动人，无孔不入，时刻诱惑着你。也许有人会认为这些都属于鸡皮蒜毛的小事，不足挂齿，但请记住：勿以恶小而为之，勿以善小而不为。<br/><br/><br/><br/><br/><br/>------------------------------------------------------------------下面是一些java异常集-------------------------------------------------------------------------------------------<br/><br/><br/> <br/><br/>算术异常类：ArithmeticExecption<br/><br/>空指针异常类：NullPointerException<br/><br/>类型强制转换异常：ClassCastException<br/><br/>数组负下标异常：NegativeArrayException<br/><br/>数组下标越界异常：ArrayIndexOutOfBoundsException<br/><br/>违背安全原则异常：SecturityException<br/><br/>文件已结束异常：EOFException<br/><br/>文件未找到异常：FileNotFoundException<br/><br/>字符串转换为数字异常：NumberFormatException<br/><br/><br/>操作数据库异常：SQLException<br/><br/><br/>输入输出异常：IOException<br/><br/><br/>方法未找到异常：NoSuchMethodException<br/><br/>java.lang.AbstractMethodError<br/><br/>抽象方法错误。当应用试图调用抽象方法时抛出。<br/><br/>java.lang.AssertionError<br/><br/>断言错。用来指示一个断言失败的情况。<br/><br/>java.lang.ClassCircularityError<br/><br/>类循环依赖错误。在初始化一个类时，若检测到类之间循环依赖则抛出该异常。<br/><br/>java.lang.ClassFormatError<br/><br/>类格式错误。当Java虚拟机试图从一个文件中读取Java类，而检测到该文件的内容不符合类的有效格式时抛出。<br/><br/>java.lang.Error<br/><br/>错误。是所有错误的基类，用于标识严重的程序运行问题。这些问题通常描述一些不应被应用程序捕获的反常情况。<br/><br/>java.lang.ExceptionInInitializerError<br/><br/>初始化程序错误。当执行一个类的静态初始化程序的过程中，发生了异常时抛出。静态初始化程序是指直接包含于类中的static语句段。<br/><br/>java.lang.IllegalAccessError<br/><br/>违法访问错误。当一个应用试图访问、修改某个类的域（Field）或者调用其方法，但是又违反域或方法的可见性声明，则抛出该异常。<br/><br/>java.lang.IncompatibleClassChangeError<br/><br/>不兼容的类变化错误。当正在执行的方法所依赖的类定义发生了不兼容的改变时，抛出该异常。一般在修改了应用中的某些类的声明定义而没有对整个应用重新编译而直接运行的情况下，容易引发该错误。<br/><br/>java.lang.InstantiationError<br/><br/>实例化错误。当一个应用试图通过Java的new操作符构造一个抽象类或者接口时抛出该异常.<br/><br/>java.lang.InternalError<br/><br/>内部错误。用于指示Java虚拟机发生了内部错误。<br/><br/>java.lang.LinkageError<br/><br/>链接错误。该错误及其所有子类指示某个类依赖于另外一些类，在该类编译之后，被依赖的类改变了其类定义而没有重新编译所有的类，进而引发错误的情况。<br/><br/>java.lang.NoClassDefFoundError<br/><br/>未找到类定义错误。当Java虚拟机或者类装载器试图实例化某个类，而找不到该类的定义时抛出该错误。<br/><br/>java.lang.NoSuchFieldError<br/><br/>域不存在错误。当应用试图访问或者修改某类的某个域，而该类的定义中没有该域的定义时抛出该错误。<br/><br/>java.lang.NoSuchMethodError<br/><br/>方法不存在错误。当应用试图调用某类的某个方法，而该类的定义中没有该方法的定义时抛出该错误。<br/><br/>java.lang.OutOfMemoryError<br/><br/>内存不足错误。当可用内存不足以让Java虚拟机分配给一个对象时抛出该错误。<br/><br/>java.lang.StackOverflowError<br/><br/>堆栈溢出错误。当一个应用递归调用的层次太深而导致堆栈溢出时抛出该错误。<br/><br/>java.lang.ThreadDeath<br/><br/>线程结束。当调用Thread类的stop方法时抛出该错误，用于指示线程结束。<br/><br/>java.lang.UnknownError<br/><br/>未知错误。用于指示Java虚拟机发生了未知严重错误的情况。<br/><br/>java.lang.UnsatisfiedLinkError<br/><br/>未满足的链接错误。当Java虚拟机未找到某个类的声明为native方法的本机语言定义时抛出。<br/><br/>java.lang.UnsupportedClassVersionError<br/><br/>不支持的类版本错误。当Java虚拟机试图从读取某个类文件，但是发现该文件的主、次版本号不被当前Java虚拟机支持的时候，抛出该错误。<br/><br/>java.lang.VerifyError<br/><br/>验证错误。当验证器检测到某个类文件中存在内部不兼容或者安全问题时抛出该错误。<br/><br/>java.lang.VirtualMachineError<br/><br/>虚拟机错误。用于指示虚拟机被破坏或者继续执行操作所需的资源不足的情况。<br/><br/><br/>java.lang.ArithmeticException<br/><br/>算术条件异常。譬如：整数除零等。<br/><br/>java.lang.ArrayIndexOutOfBoundsException<br/><br/>数组索引越界异常。当对数组的索引值为负数或大于等于数组大小时抛出。<br/><br/>java.lang.ArrayStoreException<br/><br/>数组存储异常。当向数组中存放非数组声明类型对象时抛出。<br/><br/>java.lang.ClassCastException<br/><br/>类造型异常。假设有类A和B（A不是B的父类或子类），O是A的实例，那么当强制将O构造为类B的实例时抛出该异常。该异常经常被称为强制类型转换异常。<br/><br/>java.lang.ClassNotFoundException<br/><br/>找不到类异常。当应用试图根据字符串形式的类名构造类，而在遍历CLASSPAH之后找不到对应名称的class文件时，抛出该异常。<br/><br/>java.lang.CloneNotSupportedException<br/><br/>不支持克隆异常。当没有实现Cloneable接口或者不支持克隆方法时,调用其clone()方法则抛出该异常。<br/><br/>java.lang.EnumConstantNotPresentException<br/><br/>枚举常量不存在异常。当应用试图通过名称和枚举类型访问一个枚举对象，但该枚举对象并不包含常量时，抛出该异常。<br/><br/>java.lang.Exception<br/><br/>根异常。用以描述应用程序希望捕获的情况。<br/><br/>java.lang.IllegalAccessException<br/><br/>违法的访问异常。当应用试图通过反射方式创建某个类的实例、访问该类属性、调用该类方法，而当时又无法访问类的、属性的、方法的或构造方法的定义时抛出该异常。<br/><br/>java.lang.IllegalMonitorStateException<br/><br/>违法的监控状态异常。当某个线程试图等待一个自己并不拥有的对象（O）的监控器或者通知其他线程等待该对象（O）的监控器时，抛出该异常。<br/><br/>java.lang.IllegalStateException<br/><br/>违法的状态异常。当在Java环境和应用尚未处于某个方法的合法调用状态，而调用了该方法时，抛出该异常。<br/><br/>java.lang.IllegalThreadStateException<br/><br/>违法的线程状态异常。当县城尚未处于某个方法的合法调用状态，而调用了该方法时，抛出异常。<br/><br/>java.lang.IndexOutOfBoundsException<br/><br/>索引越界异常。当访问某个序列的索引值小于0或大于等于序列大小时，抛出该异常。<br/><br/>java.lang.InstantiationException<br/><br/>实例化异常。当试图通过newInstance()方法创建某个类的实例，而该类是一个抽象类或接口时，抛出该异常。<br/><br/>java.lang.InterruptedException<br/><br/>被中止异常。当某个线程处于长时间的等待、休眠或其他暂停状态，而此时其他的线程通过Thread的interrupt方法终止该线程时抛出该异常。<br/><br/>java.lang.NegativeArraySizeException<br/><br/>数组大小为负值异常。当使用负数大小值创建数组时抛出该异常。<br/><br/>java.lang.NoSuchFieldException<br/><br/>属性不存在异常。当访问某个类的不存在的属性时抛出该异常。<br/><br/>java.lang.NoSuchMethodException<br/><br/>方法不存在异常。当访问某个类的不存在的方法时抛出该异常。<br/><br/>java.lang.NullPointerException<br/><br/>空指针异常。当应用试图在要求使用对象的地方使用了null时，抛出该异常。譬如：调用null对象的实例方法、访问null对象的属性、计算null对象的长度、使用throw语句抛出null等等。<br/><br/>java.lang.NumberFormatException<br/><br/>数字格式异常。当试图将一个String转换为指定的数字类型，而该字符串确不满足数字类型要求的格式时，抛出该异常。<br/><br/>java.lang.RuntimeException<br/><br/>运行时异常。是所有Java虚拟机正常操作期间可以被抛出的异常的父类。<br/><br/>java.lang.SecurityException<br/><br/>安全异常。由安全管理器抛出，用于指示违反安全情况的异常。<br/><br/>java.lang.StringIndexOutOfBoundsException<br/><br/>字符串索引越界异常。当使用索引值访问某个字符串中的字符，而该索引值小于0或大于等于序列大小时，抛出该异常。<br/><br/>java.lang.TypeNotPresentException<br/><br/>类型不存在异常。当应用试图以某个类型名称的字符串表达方式访问该类型，但是根据给定的名称又找不到该类型是抛出该异常。该异常与ClassNotFoundException的区别在于该异常是unchecked（不被检查）异常，而ClassNotFoundException是checked（被检查）异常。<br/><br/>java.lang.UnsupportedOperationException<br/><br/>不支持的方法异常。指明请求的方法不被支持情况的异常。<br/><br/>异常<br/>javax.servlet.jsp.JspException: Cannot retrieve mapping for action /Login （/Login是你的action名字）&nbsp;&nbsp; <br/><br/>可能原因<br/>action没有再struts-config.xml 中定义，或没有找到匹配的action，例如在JSP文件中使用 &lt;html:form action=&#34;Login.do&#34;.将表单提交给Login.do处理，如果出现上述异常，请查看struts-config.xml中的定义部分，有时可能是打错了字符或者是某些不符合规则，可以使用strutsconsole工具来检查。<br/>-----------------------------------------------------------------------------------------------------------------<br/>异常<br/>o&#114;g.apache.jasper.JasperException: Cannot retrieve definition for form bean null<br/><br/>可能原因&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br/>这个异常是因为Struts根据struts-config.xml中的mapping没有找到action期望的form bean。大部分的情况可能是因为在form-bean中设置的name属性和action中设置的name属性不匹配所致。换句话说，action和form都应该各自有一个name属性，并且要精确匹配，包括大小写。这个错误当没有name属性和action关联时也会发生，如果没有在action中指定name属性，那么就没有name属性和action相关联。当然当action制作某些控制时，譬如根据参数值跳转到相应的jsp页面，而不是处理表单数据，这是就不用name属性，这也是action的使用方法之一。<br/>-----------------------------------------------------------------------------------------------------------------<br/>异常<br/>No action instance for path /xxxx could be cr&#101;ated<br/><br/>可能原因<br/>特别提示：因为有很多中情况会导致这个错误的发生，所以推荐大家调高你的web服务器的日志/调试级别，这样可以从更多的信息中看到潜在的、在试图创建action类时发生的错误，这个action类你已经在struts-config.xml中设置了关联（即添加了&lt;action&gt;标签）。<br/><br/>在struts-config.xml中通过action标签的class属性指定的action类不能被找到有很多种原因，例如：定位编译后的.class文件失败。Failure to place compiled .class file for the action in the classpath (在web开发中，class的的位置在r WEB-INF/classes，所以你的action class必须要在这个目录下。例如你的action类位于WEB-INF/classes/action/Login.class,那么在struts-config.xml中设置action的属性type时就是action.Login).<br/>拼写错误，这个也时有发生，并且不易找到，特别注意第一个字母的大小写和包的名称。 <br/>-----------------------------------------------------------------------------------------------------------------<br/>异常<br/>javax.servlet.jsp.JspException: No getter method for property username of bean o&#114;g.apache.struts.taglib.html.BEAN<br/><br/>可能原因<br/>没有位form bean中的某个变量定义getter 方法<br/><br/>这个错误主要发生在表单提交的FormBean中，用struts标记&lt;html:text property=”username”&gt;时，在FormBean中必须有一个getUsername()方法。注意字母“U”。<br/>-----------------------------------------------------------------------------------------------------------------<br/>异常<br/>java.lang.NoClassDefFoundError: o&#114;g/apache/struts/action/ActionForm<br/><br/>可能原因<br/>这个错误主要发生在在classpath中找不到相应的Java .class文件。如果这个错误发生在web应用程序的运行时，主要是因为指定的class文件不在web server的classpath中（/WEB-INF/classes 和 /WEB-INF/lib）。在上面的错误中，原因是找不到ActionForm类。<br/>-----------------------------------------------------------------------------------------------------------------<br/>异常<br/>javax.servlet.jsp.JspException: Exception creating bean of class o&#114;g.apache.struts.action.ActionForm: {1}<br/><br/>可能原因<br/>Instantiating Struts-provided ActionForm class directly instead of instantiating a class derived off ActionForm. This mightoccur implicitly if you specify that a form-bean is this Struts ActionForm class rather than specifying a child of this classfor the form-bean.<br/><br/>Not associating an ActionForm-descended class with an action can also lead to this error.<br/>-----------------------------------------------------------------------------------------------------------------<br/>异常<br/>javax.servlet.jsp.JspException: Cannot find ActionMappings o&#114; ActionFormBeans collection<br/><br/>可能原因<br/>不是标识Struts actionServlet的&lt;servlet&gt;标记就是映射.do扩展名的&lt;sevlet-mapping&gt;标记或者两者都没有在web.xml中声明。<br/><br/>在struts-config.xml中的打字或者拼写错误也可导致这个异常的发生。例如缺少一个标记的关闭符号/&gt;。最好使用struts console工具检查一下。<br/><br/>另外，load-on-startup必须在web.xml中声明，这要么是一个空标记，要么指定一个数值，这个数值用来表servlet运行的优先级，数值越大优先级越低。<br/><br/>还有一个和使用load-on-startup有关的是使用Struts预编译JSP文件时也可能导致这个异常。<br/>-----------------------------------------------------------------------------------------------------------------<br/>异常<br/>java.lang.NullPointerException at o&#114;g.apache.struts.util.RequestUtils.forwardURL(RequestUtils.java:1223)<br/><br/>可能原因<br/>在struts-config.xml中的forward元素缺少path属性。例如应该是如下形式：<br/>&lt;forward name=&#34;userhome&#34; path=&#34;/user/userhome.jsp&#34;/&gt;<br/>-----------------------------------------------------------------------------------------------------------------<br/>异常<br/>javax.servlet.jsp.JspException: Cannot find bean o&#114;g.apache.struts.taglib.html.BEAN in any scope<br/><br/><br/>&nbsp;&nbsp;<br/><br/>Probable Causes<br/>试图在Struts的form标记外使用form的子元素。这常常发生在你在&lt;/html:form&gt;后面使用Struts的html标记。另外要注意可能你不经意使用的无主体的标记，如&lt;html:form … /&gt;，这样web 服务器解析时就当作一个无主体的标记，随后使用的所有&lt;html&gt;标记都被认为是在这个标记之外的，如又使用了&lt;html:text property=”id”&gt;还有就是在使用taglib引入HTML标记库时，你使用的prefix的值不是html。<br/>-----------------------------------------------------------------------------------------------------------------<br/>异常<br/>javax.servlet.jsp.JspException: Missing message for key xx.xx.xx<br/><br/>Probable Causes<br/>这个key的值对没有在资源文件ApplicationResources.properties中定义。如果你使用eclipse时经常碰到这样的情况，当项目重新编译时，eclipse会自动将classes目录下的资源文件删除。<br/><br/>资源文件ApplicationResources.properties 不在classpath中应将资源文件放到 WEB-INF/classes 目录下，当然要在struts-config.xml中定义)<br/>-----------------------------------------------------------------------------------------------------------------<br/>异常<br/>Cannot find message resources under key o&#114;g.apache.struts.action.MESSAGE<br/><br/>可能原因<br/>很显然，这个错误是发生在使用资源文件时，而Struts没有找到资源文件。<br/><br/>Implicitly trying to use message resources that are not available (such as using empty html:options tag instead of specifyingthe options in its body -- this assumes options are specified in ApplicationResources.properties file)<br/><br/>XML parser issues -- too many, too few, incorrect/incompatible versions<br/>-----------------------------------------------------------------------------------------------------------------<br/>异常<br/>Strange and seemingly random characters in HTML and on screen, but not in o&#114;iginal JSP o&#114; servlet.<br/><br/>可能原因<br/>混和使用Struts的html:form标记和标准的HTML标记不正确。<br/><br/>使用的编码样式在本页中不支持。<br/>-----------------------------------------------------------------------------------------------------------------<br/>异常<br/>&#34;Document contained no data&#34; in Netscape<br/><br/>No data rendered (completely empty) page in Microsoft Internet Explorer<br/><br/>可能原因<br/>使用一个Action的派生类而没有实现perform()方法或execute()方法。在Struts1.0中实现的是perform()方法，在Struts1.1中实现的是execute()方法，但Struts1.1向后兼容perform()方法。但你使用Struts1.1创建一个Action的派生类，并且实现了execute()方法，而你在Struts1.0中运行的话，就会得到&#34;Document contained nodata&#34; error message in Netscape o&#114; a completely empty (no HTML whatsoever) page rendered in Microsoft Internet Explorer.”的错误信息。<br/><br/>---------------------------------------------------------------------------------------------------------------------------<br/>异常<br/>ServletException: BeanUtils.populate<br/>解决方案<br/>在用Struts上传文件时,遇到了javax.servlet.ServletException: BeanUtils.populate异常。<br/>我的ActionServlet并没有用到BeanUtils这些工具类。后来仔细检查代码发现是在jsp文件里的form忘了加enctype=&amp;quot;multipart/form-data&amp;quot; 了。所以写程序遇到错误或异常应该从多方面考虑问题存在的可能性，想到系统提示信息以外的东西。<br/>----------------------------------------------------------------------------------------------------------------------------<br/>1. 定义Action后, 如果指定了name, 那么必须要定义一个与它同名的FormBean才能进行form映射.2. 如果定义Action后, 提交页面时出现 &#34;No input attribute for mapping path...&#34; 错误, 则需要在其input属性中定义转向的页面.3. 如果插入新的数据时出现 &#34;Batch up&#100;ate row count wrong:...&#34; 错误, 则说明XXX.hbm.xml中指定的key的类型为原始类型(int, long),因为这种类型会自动分配值, 而这个值往往会让系统认为已经存在该记录, 正确的方法是使用java.lang.Integer或java.lang.Long对象.4. 如果插入数据时出现 &#34;argument type mismatch&#34; 错误, 可能是你使用了Date等特殊对象, 因为struts不能自动从String型转换成Date型,所以, 你需要在Action中手动把String型转换成Date型.5. Hibernate中, Query的iterator()比list()方法快很多.6. 如果出现 &#34;equal symbol expected&#34; 错误, 说明你的strtus标签中包含另一个标签或者变量, 例如:<br/>&lt;html:sel&#101;ct property=&#34;test&#34; onchange=&#34;&lt;%=test%&gt;&#34;/&gt;<br/>或者<br/>&lt;html:hidden property=&#34;test&#34; value=&#34;&lt;bean:write name=&#34;t&#34; property=&#34;p&#34;/&gt;&#34;/&gt;<br/>这样的情况... <br/>---------------------------------------------------------------------------------------------------------------------------<br/>错误：Exception in thread &#34;main&#34; o&#114;g.hibernate.exception.SQLGrammarException: Could not execute JDBC batch up&#100;ate原因与解决：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;因为Hibernate Tools（或者Eclipse本身的Database Explorer）生成*.hbn.xml工具中包含有catalog=&#34;***&#34;（*表示数据库名称）这样的属性,将该属性删除就可以了<br/>---------------------------------------------------------------------------------------------------------------------------<br/>错误：org.hibernate.ObjectDel&#101;tedException: del&#101;ted object would be re-saved by cascade (remove del&#101;ted object from associations)<br/>原因与解决：<br/>方法1 删除Set方的cascade<br/>方法2 解决关联关系后，再删除<br/>方法3 在many-to-one方增加cascade 但值不能是none<br/>最后一招：<br/>检查一下hashCode equals是否使用了id作为唯一标示的选项了；我用uuid.hex时是没有问题的；但是用了native，就不行了，怎么办？删除啊！<br/>----------------------------------------------------------------------------------------------------------------------------<br/>问题：今天用Tomcat 5.5.12，发现原来很好用的系统不能用了，反复测试发现页面中不能包含 taglib，否则会出现以下提示：HTTP Status 500 -type Exception reportMessage description The server encountered an internal error () that prevented it from fulfilling this request.exceptionorg.apache.jasper.JasperException: /index.jsp(1,1) Unable to read TLD &#34;META-INF/tlds/struts-bean.tld&#34; from JAR file&#34;file:*****/WEB-INF/lib/struts.jar&#34;:原因：更新了工程用的lib文件夹下的jar，发布时也发布了servlet.jar和jsp-api.jar。解决：把jsp-api.jar删除就解决这个问题了。-----------------------------------------------------------------------------------------------------------------------------<br/>错误： java.lang.NullPointerException<br/>原因： 发现 dao 实例、 manage 实例等需要注入的东西没有被注入（俗称空指针异常）解决：这个时候，你应该查看日志文件；默认是应用服务器的 log 文件，比如 Tomcat 就是 [Tomcat 安装目录 ]/logs ；你会发现提示你：可能是：org.springframework.beans.factory.BeanCreationException: Error creating bean with name &#39;sf&#39; defined in ServletContextresource [/WEB-INF/applicationContext.xml]: Initialization of bean failed; nested exception isorg.hibernate.HibernateException: could not configure from URL: file:src/hibernate.cfg.xmlorg.hibernate.HibernateException: could not configure from URL: file:src/hibernate.cfg.xml……………………….Caused by: java.io.FileNotFoundException: src\hibernate.cfg.xml可能是：org.springframework.beans.factory.BeanCreationException: Error creating bean with name &#39;sessionFactory&#39; defined inServletContext resource [/WEB-INF/applicationContext.xml]: Initialization of bean failed; nested exception isorg.hibernate.MappingException: Resource: com/mcc/coupon/model/UserRole.hbm.xml not foundorg.hibernate.MappingException: Resource: com/mcc/coupon/model/UserRole.hbm.xml not found然后你就知道原因是因为配置文件的解析出了错误，这个通过 Web 页面是看不出来的。更多的是持久化影射文件出的错误；导致了没有被解析；当然你需要的功能就无法使用了。<br/>----------------------------------------------------------------------------------------------------------------------------<br/>错误：StandardWrapperValve[action]: Servlet.service() for servlet action threw exception<br/>javax.servlet.jsp.JspException: Cannot retrieve mapping for action /settlementTypeManage<br/>或者：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;type Status report&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;message Servlet action is not available&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;description The requested resource (Servlet action is not available) is not available.<br/>原因： 同 上<br/>----------------------------------------------------------------------------------------------------------------------------<br/>错误StandardWrapperValve[jsp]: Servlet.service() for servlet jsp threw exceptionjava.lang.ClassNotFoundException: o&#114;g.apache.struts.taglib.bean.CookieTei界面错误具体描述：<br/>o&#114;g.apache.jasper.JasperException: Failed to load o&#114; instantiate TagExtraInfo class: o&#114;g.apache.struts.taglib.bean.CookieTei<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;原因与解决：&nbsp;&nbsp;&nbsp;&nbsp;<br/>&nbsp;&nbsp; &lt;方案一&gt;你的“html:”开头的标签没有放在一个&lt;html:form&gt;中&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br/>&nbsp;&nbsp; &lt;方案二&gt;重新启动你的应用服务器，自动就没有这个问题<br/><br/><br/>]]></description>
		</item>
		
			<item>
			<link>http://www.wolf2999.cn/default.asp?id=710</link>
			<title><![CDATA[记住这张图]]></title>
			<author>wolf2999@tom.com(wolf2999)</author>
			<category><![CDATA[软件开发]]></category>
			<pubDate>Tue,14 Jul 2009 15:34:12 +0800</pubDate>
			<guid>http://www.wolf2999.cn/default.asp?id=710</guid>	
		<description><![CDATA[使用svn以后，电脑变慢。<br/><br/>估计是这里的问题。。<br/><br/>具体操作步骤如下：<br/>a) 右击任意目录打开右键菜单,打开&#34;tortoisesvn&#34; =&gt; &#34;settings&#34;下的设置窗口<br/>b) 找到&#34;icon overlays&#34;的设置项，将&#34;status cache&#34;设置成&#34;none&#34;<br/><br/><a target="_blank" href="http://www.wolf2999.cn/attachments/month_0907/s2009714153329.png">来张图</a><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>]]></description>
		</item>
		
			<item>
			<link>http://www.wolf2999.cn/default.asp?id=707</link>
			<title><![CDATA[VC time事件]]></title>
			<author>wolf2999@tom.com(wolf2999)</author>
			<category><![CDATA[软件开发]]></category>
			<pubDate>Sun,21 Jun 2009 09:20:01 +0800</pubDate>
			<guid>http://www.wolf2999.cn/default.asp?id=707</guid>	
		<description><![CDATA[Timer事件，即定时器事件，是在游戏编程中，经常使用的一个事件。借助它可以产生定时执行动作的效果。这篇文章，就和大家一起探讨一下如何使用SetTimer（）函数。 <br/>1、SetTimer定义在那里？<br/><br/>SetTimer表示的是定义个定时器。根据定义指定的窗口，在指定的窗口（CWnd）中实现OnTimer事件，这样，就可以相应事件了。<br/><br/>SetTimer有两个函数。一个是全局的函数::SetTimer()<br/><br/>UINT SetTimer(<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HWND hWnd,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // handle of window for timer messages<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UINT nIDEvent,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // timer identifier<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UINT uElapse,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// time-out value<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TIMERPROC lpTimerFunc&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// address of timer procedure<br/>);<br/><br/>其中hWnd 是指向CWnd的指针，即处理Timer事件的窗口类。说道窗口类（CWnd），我们有必要来看一下CWnd的继承情况：CWnd有以下子类：CFrameWnd,CDialog,CView,CControlBar等类。这也意味这些类中都可以定义SetTimer事件。<br/><br/>同时，SetTimer（）在CWnd中也有定义，即SetTimer（）是CWnd的一个成员函数。CWnd的子类可以调用该函数，来设置触发器。<br/><br/>UINT SetTimer( UINT nIDEvent, UINT nElapse, void (CALLBACK EXPORT* lpfnTimer)(HWND, UINT, UINT, DWORD) );<br/><br/>参数含义：<br/><br/>nIDEvent:是指设置这个定时器的iD，即身份标志，这样在OnTimer（）事件中，才能根据不同的定时器，来做不同的事件响应。这个ID是一个无符号的整型。<br/><br/>nElapse<br/><br/>是指时间延迟。单位是毫秒。这意味着，每隔nElapse毫秒系统调用一次Ontimer（）。<br/><br/>void (CALLBACK EXPORT* lpfnTimer)(HWND, UINT, UINT, DWORD)<br/><br/>Specifies the address of the application-supplied TimerProc callback function that processes the WM_TIMER messages. If this parameter is NULL, the WM_TIMER messages are placed in the application’s message queue and handled by the CWnd object。<br/><br/>意思是，指定应用程序提供的TimerProc回调函数的地址，来处里这个Timer事件。如果是NULL，处理这个Timer事件的定义这个Timer的CWnd对象。他将WM_TIMER消息传递给这个对象，通过实现这个对象的OnTimer（）事件来处理这个Timer事件。<br/><br/>所以，一般情况下，我们将这个值设为NULL，有设置该定时器的对象中的OnTimer（）函数来处理这个事件。<br/><br/>同样的，我们再看看KillTimer（）和OnTimer（）的定义:<br/><br/>KillTimer同SetTimer（）一样，他也有两个，一个是全局的::KillTimer(),另一个是CWnd的一个函数。他的声明如下：<br/><br/><br/>//全局函数<br/><br/>BOOL KillTimer(<br/>&nbsp;&nbsp;&nbsp;&nbsp; HWND hWnd,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // handle of window that installed timer<br/>&nbsp;&nbsp;&nbsp;&nbsp; UINT uIDEvent&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// timer identifier<br/>);<br/><br/>//CWnd函数<br/><br/>BOOL KillTimer( int nIDEvent );<br/><br/>这两个函数表示的意思是将iD为nIDEVENT的定时器移走。使其不再作用。其用法如同SetTimer（）一样。<br/><br/>再看看OnTimer（）<br/><br/>CWnd::OnTimer&nbsp;&nbsp;<br/>afx_msg void OnTimer( UINT nIDEvent );<br/><br/>ontimer（）是响应CWnd对象产生的WM_Timer消息。nIDEvent表示要响应TIMER事件的ID。<br/><br/>二、Timer事件的使用：<br/><br/>由以上的分析，我们应该很清楚，如何来使用Timer事件。假定我们在视图上画一个渐变的动画。我们首先在菜单栏上添加一个菜单项，给这个菜单添加命令响应：<br/><br/>pView-&gt;SetTimer(1,1000,NULL);//pView是视图类的指针，这里是在视图类当中设置一个定时器。<br/><br/>添加完毕，再给视图类添加一个WM_Timer事件的相应。在OnTimer（）函数中编写汉书，进行相应。<br/><br/>如此，就能做出动画。 <br/>]]></description>
		</item>
		
			<item>
			<link>http://www.wolf2999.cn/default.asp?id=692</link>
			<title><![CDATA[有关耦合]]></title>
			<author>wolf2999@tom.com(wolf2999)</author>
			<category><![CDATA[软件开发]]></category>
			<pubDate>Sat,02 May 2009 09:17:53 +0800</pubDate>
			<guid>http://www.wolf2999.cn/default.asp?id=692</guid>	
		<description><![CDATA[<strong>非直接耦合：</strong>两个模块之间没有直接关系，它们之间的联系完全是通过主模块的控制和调用来实现的<br/><strong>数据耦合：</strong>一个模块访问另一个模块时，彼此之间是通过简单数据参数 (不是控制参数、公共数据结构或外部变量) 来交换输入、输出信息的。<br/><strong>标记耦合：</strong>一组模块通过参数表传递记录信息，就是标记耦合。这个记录是某一数据结构的子结构，而不是简单变量。<br/><strong>控制耦合：</strong>如果一个模块通过传送开关、标志、名字等控制信息，明显地控制选择另一模块的功能，就是控制耦合。<br/><strong>外部耦合：</strong>一组模块都访问同一全局简单变量而不是同一全局数据结构，而且不是通过参数表传递该全局变量的信息，则称之为外部耦合。<br/><strong>公共耦合：</strong>若一组模块都访问同一个公共数据环境，则它们之间的耦合就称为公共耦合。公共的数据环境可以是全局数据结构、共享的通信区、内存的公共覆盖区等。<br/><strong>内容耦合：</strong>如果发生下列情形，两个模块之间就发生了内容耦合<br/>　(1) 一个模块直接访问另一个模块的内部数据;<br/>　(2) 一个模块不通过正常入口转到另一模块内部;<br/>　(3) 两个模块有一部分程序代码重迭(只可能出现在汇编语言中);<br/>　(4) 一个模块有多个入口。]]></description>
		</item>
		
</channel>
</rss>