﻿<?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-firtre</title><link>http://www.blogjava.net/firtre/</link><description>小蚂蚁，定语没想好。
精灵古怪，不是我。</description><language>zh-cn</language><lastBuildDate>Mon, 27 Apr 2026 03:54:38 GMT</lastBuildDate><pubDate>Mon, 27 Apr 2026 03:54:38 GMT</pubDate><ttl>60</ttl><item><title>开发流程 AN BD FD DD C UT CT TT IT OP 意思</title><link>http://www.blogjava.net/firtre/archive/2008/10/08/233088.html</link><dc:creator>笨蛋</dc:creator><author>笨蛋</author><pubDate>Wed, 08 Oct 2008 04:23:00 GMT</pubDate><guid>http://www.blogjava.net/firtre/archive/2008/10/08/233088.html</guid><wfw:comment>http://www.blogjava.net/firtre/comments/233088.html</wfw:comment><comments>http://www.blogjava.net/firtre/archive/2008/10/08/233088.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.blogjava.net/firtre/comments/commentRss/233088.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/firtre/services/trackbacks/233088.html</trackback:ping><description><![CDATA[AN BD FD DD C UT CT TT IT OP <br />
今天填简历,工程一栏给出这样的选项、网上没有查到准确解释.<br />
跟朋友讨论了一下,大体上猜测出几个,也有两个不知道何意,如果有知道正解的请不吝赐教!<br />
AN-要求分析<br />
BD-基本设计 <br />
FD-结构设计<br />
DD-详细设计<br />
C&nbsp; -编码<br />
UT-单体测试<br />
CT-不知道<br />
TT-结合测试<br />
IT-系统测试<br />
OP-发布<br />
<br />
以上只是个人理解,像OP这样的纯属猜测...欢迎指摘!<br />
<br />
<img src ="http://www.blogjava.net/firtre/aggbug/233088.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/firtre/" target="_blank">笨蛋</a> 2008-10-08 12:23 <a href="http://www.blogjava.net/firtre/archive/2008/10/08/233088.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Head First 设计模式之策略模式</title><link>http://www.blogjava.net/firtre/articles/191381.html</link><dc:creator>笨蛋</dc:creator><author>笨蛋</author><pubDate>Mon, 07 Apr 2008 15:03:00 GMT</pubDate><guid>http://www.blogjava.net/firtre/articles/191381.html</guid><wfw:comment>http://www.blogjava.net/firtre/comments/191381.html</wfw:comment><comments>http://www.blogjava.net/firtre/articles/191381.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/firtre/comments/commentRss/191381.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/firtre/services/trackbacks/191381.html</trackback:ping><description><![CDATA[设计原则:找出应用可能需要变化之处,把它们独立出来,不要和那个不需要变化的代码放在一起.<br />
设计原则:多用组合,少用继承.<br />
设计原则:针对接口编程,而不是针对实现编程.<br />
背景:需要设计一个鸭子类,有飞行和呱呱叫两种行为.可是后来引入了橡皮鸭,导致传统的继承处理无法使用(不能让橡皮鸭也会飞)而且还可能会有既不会飞也不会叫的鸭子,或者需要引入不同种鸭子的具体的飞行运行,叫的声音......<br />
策略模式:把易变的动作部分抽象出来成为单独的类(接口).<br />
定义:定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户.<br />
<br />
public abstract class Duck {<br />
&nbsp;FlyBehavior flyBehavior;<br />
&nbsp;QuackBehavior quackBehavior;<br />
&nbsp;public Duck(){<br />
&nbsp;}<br />
&nbsp;<br />
&nbsp;public abstract void display();<br />
&nbsp;public void performFly(){<br />
&nbsp;&nbsp;flyBehavior.fly();<br />
&nbsp;}<br />
&nbsp;<br />
&nbsp;public void performQuack(){<br />
&nbsp;&nbsp;quackBehavior.quack();<br />
&nbsp;}<br />
&nbsp;<br />
&nbsp;public void swim(){<br />
&nbsp;&nbsp;System.out.println("All ducks float,even decoys!");<br />
&nbsp;}<br />
}<br />
public interface FlyBehavior {<br />
&nbsp;public void fly();<br />
}<br />
<p>public class FlyNoWay implements FlyBehavior{</p>
<p>&nbsp;public void fly() {<br />
&nbsp;&nbsp;System.out.println("I can't fly");<br />
&nbsp;}<br />
}</p>
<p>public class FlyWithWings implements FlyBehavior{</p>
<p>&nbsp;public void fly() {<br />
&nbsp;&nbsp;System.out.println("I'm flying!!");<br />
&nbsp;}<br />
}</p>
public interface QuackBehavior {<br />
&nbsp;public void quack();<br />
}<br />
<p>public class Quack&nbsp; implements QuackBehavior{</p>
<p>&nbsp;public void quack() {<br />
&nbsp;&nbsp;System.out.println("Quack");<br />
&nbsp;}<br />
}</p>
<p>public class muteQuack implements QuackBehavior{</p>
<p>&nbsp;public void quack() {<br />
&nbsp;&nbsp;System.out.println("&lt;&lt;Silence&gt;&gt;");<br />
&nbsp;}</p>
<p>}</p>
<p>public class Squeak implements QuackBehavior{</p>
<p>&nbsp;public void quack() {<br />
&nbsp;&nbsp;System.out.println("Squeak");<br />
&nbsp;}<br />
}</p>
public class MallardDuck extends Duck{<br />
&nbsp;public MallardDuck(){<br />
&nbsp;&nbsp;quackBehavior = new Quack();<br />
&nbsp;&nbsp;flyBehavior = new FlyWithWings();<br />
&nbsp;}<br />
&nbsp;public void display() {<br />
&nbsp;&nbsp;System.out.println("I'm a real Mallard duck.");<br />
&nbsp;}<br />
}<br />
测试类:<br />
public class MiniDuckSimulator {<br />
&nbsp;public static void main(String[] args){<br />
&nbsp;&nbsp;Duck mallard = new MallardDuck();<br />
&nbsp;&nbsp;mallard.performQuack();<br />
&nbsp;&nbsp;mallard.performFly();<br />
&nbsp;}<br />
}
<img src ="http://www.blogjava.net/firtre/aggbug/191381.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/firtre/" target="_blank">笨蛋</a> 2008-04-07 23:03 <a href="http://www.blogjava.net/firtre/articles/191381.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>事件 监听 机制的自实现 (event listener)</title><link>http://www.blogjava.net/firtre/articles/183739.html</link><dc:creator>笨蛋</dc:creator><author>笨蛋</author><pubDate>Wed, 05 Mar 2008 00:20:00 GMT</pubDate><guid>http://www.blogjava.net/firtre/articles/183739.html</guid><wfw:comment>http://www.blogjava.net/firtre/comments/183739.html</wfw:comment><comments>http://www.blogjava.net/firtre/articles/183739.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/firtre/comments/commentRss/183739.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/firtre/services/trackbacks/183739.html</trackback:ping><description><![CDATA[北天JAVA技术网(<a href="http://www.java114.com/">www.java114.com</a>))<br />
<br />
<div style="font-size: 10.5pt">Event/Listener模式在Java中很常见，并且很有用，但要自己来实现这个模式是一件很费时间并且单调乏味的工作。每次你都不得不和List或Vector打交道，每次你都不得不处理Add方法、Remove方法，然后你还得遍历整个列表来通知所有的监听者，这才算完。如果能象下面这样简单就好了：<br />
Notifier notifier = new Notifier("actionPerformed");<br />
...notifier.addListener( someObject );<br />
...notifier.notify( new ActionEvent(this) );只要几行代码就能够完成一切。<br />
下面的Notifier类就达到了这个目的：<br />
package com.generationjava.lang;<br />
<br />
<p>import java.lang.reflect.Method;<br />
import java.util.ArrayList;<br />
import java.util.EventObject;<br />
import java.util.Iterator;</p>
<p>public class Notifier {<br />
&nbsp;private ArrayList listeners = new ArrayList();<br />
&nbsp;private String listenerMethod;<br />
&nbsp;public Notifier(String name) {<br />
&nbsp;&nbsp;this.listenerMethod = name;<br />
&nbsp;}<br />
&nbsp;public void addListener(Object not) {<br />
&nbsp;&nbsp;this.listeners.add(not);<br />
&nbsp;}<br />
&nbsp;public void removeListener(Object not) {<br />
&nbsp;&nbsp;this.listeners.remove(not);<br />
&nbsp;}<br />
&nbsp;public void notify(EventObject event) {<br />
&nbsp;&nbsp;Iterator itr = listeners.iterator();<br />
&nbsp;&nbsp;while(itr.hasNext()) {<br />
&nbsp;&nbsp;&nbsp;try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;Object listener = itr.next();<br />
&nbsp;&nbsp;&nbsp;&nbsp;Class clss = listener.getClass();<br />
&nbsp;&nbsp;&nbsp;&nbsp;Method method = clss.getMethod(this.listenerMethod,new Class[] { event.getClass() });<br />
&nbsp;&nbsp;&nbsp;&nbsp;method.invoke( listener, new Object[] { event } );<br />
&nbsp;&nbsp;&nbsp;} catch(Exception e) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();<br />
&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;}<br />
&nbsp;}<br />
}</p>
这个类并没有经过性能上的优化，而且它是不同步的，但在编写一组Event/Listener API的时候，可以很快掌握它并且节省时间。利用Notifier类，你就能执行这样一个常见的任务而不必每次都为之编写代码。 <br />
<br />
以下内容摘自CSDC社区: (<a href="http://topic.csdn.net/t/20020918/10/1032825.html">http://topic.csdn.net/t/20020918/10/1032825.html</a>)<br />
<br />
其实java的事件机制十分简单，你完全可以实现自己的事件驱动； &nbsp; <br />
&nbsp; 主要涉及到如下几个类（可以参考键盘事件的有关类）： &nbsp; <br />
&nbsp; 1.事件类XXXEvent，其中包含你所规定的事件的一些信息，如事件源，事件名称等等，如KeyEvent，中有eventSource，keyCode等等 &nbsp; <br />
&nbsp; 2.事件监听接口，XXXEventListener，其中包含捕获到事件的类要作的事情，如KeyListener，其中包括:keyPress,keyReleased,等等 &nbsp; <br />
&nbsp; 如： &nbsp; <br />
&nbsp; public &nbsp; interface &nbsp; XXXListener{ &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; public &nbsp; void &nbsp; doXXXEvent(xxxEvent &nbsp; e); &nbsp; <br />
&nbsp; } &nbsp; <br />
&nbsp; 3.发出事件的类：可以是任意的类，在这个类中，可以发出该事件XXXEvent，比如可以在这个类中添加一个fireXXXEvent方法，在这个方法中去手工发出事件，如： &nbsp; <br />
&nbsp; public &nbsp; void &nbsp; fireXXXEvent(){ &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; java.util.Vector &nbsp; targets; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; synchronized &nbsp; (this) &nbsp; { &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; targets &nbsp; = &nbsp; (java.util.Vector) &nbsp; xxxListeners.clone(); &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; XXXEvent &nbsp; evt &nbsp; = &nbsp; new &nbsp; XXXEvent(.....); &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for &nbsp; (int &nbsp; i &nbsp; = &nbsp; 0; &nbsp; i &nbsp; &lt; &nbsp; targets.size(); &nbsp; i++) &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; XXXListener &nbsp; target &nbsp; = &nbsp; (XXXListener) &nbsp; targets.elementAt(i); &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; target.doXXXEvent(evt); &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } &nbsp; <br />
&nbsp; } &nbsp; <br />
&nbsp; 此外在这个类里要有一个监听列表即上面的xxxlisteners，在这个类中还要实现一个addXXXListrener(XXXListener)方法，来把一个实现了XXXListenr的类作为监听者加到该类中。 <br />
</div>
<img src ="http://www.blogjava.net/firtre/aggbug/183739.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/firtre/" target="_blank">笨蛋</a> 2008-03-05 08:20 <a href="http://www.blogjava.net/firtre/articles/183739.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>XML初识篇</title><link>http://www.blogjava.net/firtre/articles/180493.html</link><dc:creator>笨蛋</dc:creator><author>笨蛋</author><pubDate>Mon, 18 Feb 2008 08:45:00 GMT</pubDate><guid>http://www.blogjava.net/firtre/articles/180493.html</guid><wfw:comment>http://www.blogjava.net/firtre/comments/180493.html</wfw:comment><comments>http://www.blogjava.net/firtre/articles/180493.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/firtre/comments/commentRss/180493.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/firtre/services/trackbacks/180493.html</trackback:ping><description><![CDATA[&nbsp;XML 是一种数据格式。<br />
<br />
读取XML文件内容，就需要解析器。<br />
最普通的 XML 处理工作是 <strong>解析</strong> XML 文档。解析包括读取 XML 文档并确定其结构和内容。<br />
XML 编程的一个好处是可以使用开放源代码的、免费的 XML 解析器读取 XML 文档。<br />
为了简化编写处理 XML 的 Java 程序，已经建立了多种编程接口。<br />
主要的四个接口：<br />
<ul>
    <li>Document Object Model （<span style="color: red">DOM</span>，文档对象模型），Level 2
    <li>Simple API for XML (<span style="color: red">SAX</span>), Version 2.0
    <li><span style="color: red">JDOM</span>, Jason Hunter 和 Brett McLaughlin 创立的一种简单 Java API
    <li>Java API for XML Processing (<span style="color: red">JAXP</span>) </li>
</ul>
<br />
<p>使用 DOM、SAX 或 JDOM 处理 XML 文档的内容。 </p>
<p>如果使用 DOM 或 SAX，则使用 JAXP 创建解析器。 </p>
<p>如果使用 JDOM，则 JDOM 库为您创建解析器。<br />
<br />
解析器的类型：<br />
</p>
<ul>
    <li>验证和非验证解析器
    <li>支持一种或多种 XML Schema 语言的解析器
    <li>支持 Document Object Model (DOM) 的解析器
    <li>支持 Simple API for XML (SAX) 的解析器 </li>
</ul>
<p>XML文件的类型：<br />
</p>
<li><strong xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">结构良好的文档：</strong>这类文档符合 XML 基本规则（属性必须放在引号中、标签必须正确嵌套等等）。
<li><strong xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">有效文档：</strong>这些结构良好的文档同时还符合文档类型定义（DTD）或 XML Schema 所定义的规则。
<li><strong xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">无效文档：</strong>所有其他文档。 </li>
<p>（如果您有一个 XML 文档符合 XML 的基本规则，那么它就是一个 <em>结构良好的</em> 文档。如果该文档还满足您的公司所定义的支出帐目文档规则，那么它也是 <em>有效的</em>。 ）</p>
<p xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">如果 XML 解析器发现 XML 文档不是结构良好的，XML Specification 要求解析器报告一个致命错误。但验证是一个不同的问题。<strong>验证解析器</strong> 在解析时验证 XML 文档，而 <strong>非验证解析器</strong> 不验证文档。换句话说，如果一个 XML 文档是结构良好的，那么非验证解析器并不关心文档是否符合 DTD 或模式中定义的规则，甚至不关心该文档是否有这样的规则（原因：验证需要大量工作）<br />
<br />
设置：<br />
</p>
<p>1首先请访问 Apache XML Project (http://xml.apache.org/xerces2-j/) 上的 <a href="http://xml.apache.org/xerces2-j/" target="blank">Xerces XML 解析器主页</a>。您也可以直接去 <a href="http://xml.apache.org/xerces2-j/download.cgi" target="_blank">下载页面</a> (http://xml.apache.org/xerces2-j/download.cgi)。 </p>
<p>2解压从 Apache 下载的文件。根据解析器版本的不同，这样将会创建名为 <code>xerces-2_5_0</code> 或者类似名称的目录。所需要的 JAR 文件（<code>xercesImpl.jar</code> 和 <code>xml-apis.jar</code>）应该出现在 Xerces 根目录下。 </p>
<p>3访问 <a href="http://jdom.org/" target="_blank">JDOM 项目站点</a> 并下载最新版本的 JDOM (http://jdom.org/)。 </p>
<p>4解压从 JDOM 下载的文件，这样将建立名为 <code>jdom-b9</code> 或者类似名称的目录。所需要的 JAR 文件（<code>jdom.jar</code>）应该在 <code>build</code> 目录中。 </p>
<p>5最后请下载本教程的示例压缩文件 <binref href="xmlprogj.zip"></binref>，并解压该文件。 </p>
<p>6把当前目录 (<code>.</code>)、<code>xercesImpl.jar</code>、<code>xml-apis.jar</code> 和 <code>jdom.jar</code> 添加到 <code>CLASSPATH</code> 变量中。<br />
<br />
使用解析器：<br />
</p>
<p>1创建一个解析器对象 </p>
<p>2使解析器指向您的 XML 文档 </p>
<p>3处理结果 <br />
<br />
<br />
SAX：<br />
Simple API for XML (SAX) API 是处理 XML 文档内容的一种替代方法。它的设计目标是更少的内存占用，但是把更多的工作交给了程序员。SAX 和 DOM 是互补的，有各自的适用环境。<br />
<font face="Verdana, Arial, Helvetica" size="2">&nbsp; </p>
<p xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">当使用 SAX 解析器解析一个 XML 文档时，解析器在读取文档的过程中会生成一系列的事件。至于如何处理这些事件则取决于您。下面列出了一小部分您在 XML 文档时可能遇到的事件：</p>
<ul>
    <li><code xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">startDocument</code> 事件。
    <li>对于每个元素，在元素开始时有 <code xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">startElement</code> 事件，元素结束时有 <code xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">endElement</code> 事件。
    <li>如果元素包含内容，对于文本将出现 <code xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">characters</code> 事件，对于子元素将出现 <code xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">startElement</code> 和 <code xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">endElement</code> 事件，依此类推。
    <li><code xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">endDocument</code> 事件。 </li>
</ul>
<p xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">和 DOM 一样，SAX 解析器也忽略了某些细节，如属性出现的顺序。</p>
<p></font>SAX 和 DOM 都过于复杂，</p>
<p xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">和 DOM 类似，JDOM 也提供一个对象树表示 XML 文档，但是这些对象工作的方式对 Java 程序员更直观。要记住，JDOM 在背后包含使用普通 SAX 或 DOM 解析器的适配器；JDOM 对所有主要的（和几个次要的） Java XML 解析器都提供了适配器，因此不必担心您的 Java XML 解析器是否支持 JDOM。JDOM 在幕后使用一个解析器不需要您的干涉。</p>
<p>DOM<br />
<br />
DOM 是处理 XML 文档结构的一种接口。作为一个 W3C 项目，DOM 的设计目标是提供一组对象和方法，使程序员的工作更轻松。<br />
</p>
<p xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">当使用 DOM 解析器解析一个 XML 文档时，您得到一个层次化的数据结构（DOM 树），它表示解析器在 XML 文档中发现的所有内容。然后您可以使用 DOM 函数操纵这棵树。您可以搜索树中的内容、移动分支、增加新的分支或者删除树的一部分。</p>
<p>DOM 解析器返回一个树状结构，这个 DOM 树包含一些 <code>Node</code>。从 Java 语言的角度看，<code>Node</code> 是一个接口。<code>Node</code> 是 DOM 的基本数据类型，DOM 树中的所有事物都是这种或那种类型的 <code>Node</code>。<br />
</p>
<p xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">DOM Level 1 还定义了 <code>Node</code> 接口的几种子接口：</p>
<ul>
    <li><code xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">Element</code>：表示源文档中的一个 XML 元素。
    <li><code xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">Attr</code>：表示 XML 元素的一个属性。
    <li><code xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">Text</code>：一个元素的内容。这意味着带有文本的元素包含文本节点孩子，元素的文本 <em xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">不是</em> 元素本身的一个属性。
    <li><code xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">Document</code>：表示整个 XML 文档。解析的每个 XML 文档中有且只有一个 <code xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">Document</code> 对象。给定一个 <code xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">Document</code> 对象就可以找到 DOM 树的根，从这个根可以使用 DOM 函数读和操纵树。 </li>
</ul>
<p xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance"><strong>注意：</strong>&#8220;元素&#8221;和&#8220;标签&#8221;这两个词有不同的含义。<strong>元素</strong> 是指起始元素、结束元素以及两者之间的一切内容，包括属性、文本、注释以及子元素。<strong>标签</strong> 是一对&lt;尖括号&gt;和两者之间的内容，包括元素名和所有属性。比如 <code>&lt;p class="blue"&gt;</code> 是一个标签，<code>&lt;/p&gt;</code> 也是；而 <code>&lt;p class="blue"&gt;The quick brown fox&lt;/p&gt;</code> 是一个元素。</p>
<p>DOM 经常要用到以下方法： </p>
<ul>
    <li><code xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">Document.getDocumentElement()</code>：返回 DOM 树的根。（该函数是 <code xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">Document</code> 接口的一个方法，没有定义其他的 <code xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">Node</code> 子类型。）
    <li><code xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">Node.getFirstChild()</code> 和 <code xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">Node.getLastChild()</code>：返回给定 <code xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">Node</code> 的第一个和最后一个孩子。
    <li><code xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">Node.getNextSibling()</code> 和 <code xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">Node.getPreviousSibling()</code>：返回给定 <code xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">Node</code> 的下一个和上一个兄弟。
    <li><code xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">Element.getAttribute(String attrName)</code>：对于给定的 <code xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">Element</code>，返回名为 <code xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">attrName</code> 的属性的值。如果需要 <code xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">"id"</code> 属性的值，可以使用 <code xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">Element.getAttribute("id")</code>。如果该属性不存在，该方法返回一个空字符串 (<code xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">""</code>)。 </li>
</ul>
<p><font face="Verdana, Arial, Helvetica" size="2">&nbsp; </p>
<p xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">第一个应用程序是 <code>DomOne.java</code>，这段简单的 Java 代码完成四件事：</p>
<ol xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">
    <li>扫描命令行得到 XML 文件名
    <li>创建一个解析器对象
    <li>告诉解析器解析命令行中给定的 XML 文件
    <li>遍历 DOM 结果树向标准输出打印各种节点的内容 </li>
</ol>
<p></font>
<table cellspacing="0" cellpadding="0" border="0">
    <tbody>
        <tr>
            <td width="90%"><font face="Verdana, Arial, Helvetica" size="4"><strong>第 1 步：扫描命令行</strong></font></td>
            <td align="right" width="200"><font face="Verdana, Arial, Helvetica" size="1"><nobr></nobr></font></td>
        </tr>
    </tbody>
</table>
<br />
<br />
<font face="Verdana, Arial, Helvetica" size="2"></p>
<p xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">扫描命令行相对而言非常简单。只需要查看一个参数，并假定该参数是一个文件名或 URI。如果命令行中没有参数，则打印一个错误消息并退出：</p>
<pre><code style="font-size: 12px; font-family: Courier New, Courier, monospace">public static void main(String argv[])
{
if (argv.length == 0 ||
(argv.length == 1 &amp;&amp; argv[0].equals("-help")))
{
System.out.println("\nUsage:  java DomOne uri");
System.out.println("   where uri is the URI of the XML " +
"document you want to print.");
System.out.println("   Sample:  java DomOne sonnet.xml");
System.out.println("\nParses an XML document, then writes " +
"the DOM tree to the console.");
System.exit(1);
}
DomOne d1 = new DomOne();
d1.parseAndPrint(argv[0]);
}
</code></font></pre>
<p xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">
<table cellspacing="0" cellpadding="0" border="0">
    <tbody>
        <tr>
            <td width="90%"><font face="Verdana, Arial, Helvetica" size="4"><strong>第 2 步：创建一个解析器对象</strong></font></td>
        </tr>
    </tbody>
</table>
<br />
下面的代码说明了先创建一个工厂对象，然后工厂对象创建解析器：</p>
<pre><code style="font-size: 12px; font-family: Courier New, Courier, monospace">public void parseAndPrint(String uri)
{
Document doc = null;
try
{
<strong xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">DocumentBuilderFactory dbf =
DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();</strong>
. . .
</code></pre>
<p><font face="Verdana, Arial, Helvetica" size="2">&nbsp; <font face="Verdana, Arial, Helvetica" size="4"><strong>第 3 步：解析 XML 文件</strong></font></p>
<p xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">现在您已经创建了解析器，告诉它解析哪个文件（或 URI）很简单：</p>
<pre><code style="font-size: 12px; font-family: Courier New, Courier, monospace">doc = db.parse(uri);</code>
</pre>
<p></font><font face="Verdana, Arial, Helvetica" size="4"><strong>&nbsp; 第 4 步：打印 DOM 树的内容<br />
</strong></font><font face="Verdana, Arial, Helvetica" size="2">&nbsp; </p>
<p xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">最后一项任务是打印 DOM 树的内容。因为 DOM 树中的一切事物都是这种或那种类型的 <code>Node</code>，您需要用递归的方法遍历并打印其中的内容。策略是调用该方法打印一个节点。该方法将打印那个节点，并对该节点的每个孩子调用自身。如果这些孩子还有孩子，该方法将对这些孩子调用自身。下面是一个例子：</p>
<pre><code style="font-size: 12px; font-family: Courier New, Courier, monospace">  if (doc != null)
<strong xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">printDomTree</strong>(doc);
. . .
}
public void printDomTree(Node node)
{
int type = node.getNodeType();
switch (type)
{
// print the document element
case Node.DOCUMENT_NODE:
{
System.out.println("&lt;?xml version=\"1.0\" ?&gt;");
<strong xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">printDomTree</strong>(((Document)node).getDocumentElement());
break;
}
</code>
</pre>
<p xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance"><code>printDomTree</code> 方法以一个 <code>Node</code> 作为参数。如果该 <code>Node</code> 是一个文档节点，就打印一个 XML 声明，然后对文档元素（包含文档其他内容的元素）调用 <code>printDomTree</code>。文档元素基本上总是有其他孩子，因此 <code>printDomTree</code> 也将对这些孩子调用自身。这种递归算法可以遍历整个 DOM 树并把内容打印到命令行中。</p>
<p xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">以下是 <code>printDomTree</code> 对元素节点的处理：</p>
<pre><code style="font-size: 12px; font-family: Courier New, Courier, monospace">    case Node.ELEMENT_NODE:
{
System.out.print("&lt;");
System.out.print(node.getNodeName());
NamedNodeMap attrs = node.getAttributes();
for (int i = 0; i &lt; attrs.getLength(); i++)
<strong xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">printDomTree</strong>(attrs.item(i));
System.out.print("&gt;");
if (node.hasChildNodes())
{
NodeList children = node.getChildNodes();
for (int i = 0; i &lt; children.getLength(); i++)
<strong xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">printDomTree</strong>(children.item(i));
}
System.out.print("&lt;/");
System.out.print(node.getNodeName());
System.out.print('&gt;');
break;
}
</code>
</pre>
<p xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">对于元素节点，您需要打印一个左尖括号和结点名称。如果该元素有属性，就对每个属性调用 <code>printDomTree</code>。（技术上讲，这里可以使用 <code>Attr.getName()</code> 和 <code>Attr.getValue()</code> 打印属性，我这样做是为了说明 DOM 树中的一切都是 <code>Node</code>。）一旦打印完所有的属性，就可以对该节点所包含的所有子元素再次调用 <code>printDomTree</code>。最后一步是在处理完所有的子元素之后打印结束元素。</p>
<p xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">处理属性节点和文本节点很简单。对于属性，需要输出一个空格、属性名、等号、开双引号、属性值和闭双引号。（这里简化了，属性值可以使用单引号和双引号，如果愿意您完全可以修正这个问题。）</p>
<p xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">处理文本节点最简单，只需要输出文本就可以了。以下是这两种节点类型的代码：</p>
<pre><code style="font-size: 12px; font-family: Courier New, Courier, monospace">    case Node.ATTRIBUTE_NODE:
{
System.out.print(" " + node.getNodeName() + "=\"" +
((Attr)node).getValue() + "\"");
break;
}
case Node.TEXT_NODE:
{
System.out.print(node.getNodeValue());
break;
}
</code>
</pre>
<p xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">尽管这里只是打印 DOM 树的内容，但多数围绕着 DOM 建立的 XML 应用程序都使用这种四个步骤的模式，第四步是递归处理例程。</font></p>
<p>
<table cellspacing="0" cellpadding="0" border="0">
    <tbody>
        <tr>
            <td width="90%"><font face="Verdana, Arial, Helvetica" size="4"><strong>运行 <code style="font-size: 18px; font-family: Courier New, Courier, monospace">DomOne</code> </strong></font></td>
        </tr>
    </tbody>
</table>
</p>
<p xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">在您解压示例文件的目录下键入：</p>
<pre><code style="font-size: 12px; font-family: Courier New, Courier, monospace">javac DomOne.java</code>
</pre>
<p xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">（记住 Java 语言是区分大小写的。）如果没有任何错误，键入：</p>
<pre><code style="font-size: 12px; font-family: Courier New, Courier, monospace">java DomOne sonnet.xml</code>
</pre>
<p xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">解析并显示文件 <code>sonnet.xml</code>。</p>
<p xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">如果一切都和预期的一样，您应该看到类似这样的内容：</p>
<pre><code style="font-size: 12px; font-family: Courier New, Courier, monospace">C:\xml-prog-java&gt;java DomOne sonnet.xml
&lt;?xml version="1.0" ?&gt;
&lt;sonnet type="Shakespearean"&gt;
&lt;author&gt;
&lt;lastName&gt;Shakespeare&lt;/lastName&gt;
&lt;firstName&gt;William&lt;/firstName&gt;
&lt;nationality&gt;British&lt;/nationality&gt;
&lt;yearOfBirth&gt;1564&lt;/yearOfBirth&gt;
&lt;yearOfDeath&gt;1616&lt;/yearOfDeath&gt;
&lt;/author&gt;
&lt;title&gt;Sonnet 130&lt;/title&gt;
&lt;lines&gt;
&lt;line&gt;My mistress' eyes are nothing like the sun,&lt;/line&gt;
&lt;line&gt;Coral is far more red than her lips red.&lt;/line&gt;
&lt;line&gt;If snow be white, why then her breasts are dun,&lt;/line&gt;
&lt;line&gt;If hairs be wires, black wires grow on her head.&lt;/line&gt;
. . .
&lt;/lines&gt;
</code></pre>
<p>待续<br />
摘自IBM在线学习<br />
</p>
<img src ="http://www.blogjava.net/firtre/aggbug/180493.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/firtre/" target="_blank">笨蛋</a> 2008-02-18 16:45 <a href="http://www.blogjava.net/firtre/articles/180493.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>synchronized 与unsynchronized (同步与异步）</title><link>http://www.blogjava.net/firtre/articles/180454.html</link><dc:creator>笨蛋</dc:creator><author>笨蛋</author><pubDate>Mon, 18 Feb 2008 05:32:00 GMT</pubDate><guid>http://www.blogjava.net/firtre/articles/180454.html</guid><wfw:comment>http://www.blogjava.net/firtre/comments/180454.html</wfw:comment><comments>http://www.blogjava.net/firtre/articles/180454.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/firtre/comments/commentRss/180454.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/firtre/services/trackbacks/180454.html</trackback:ping><description><![CDATA[<p>网络上最直白的解释：<br />
&nbsp; 同步就是你叫我去吃饭，我听到了就和你去吃饭；如果没有听到，你就不停的叫，直到我告诉你听到了，才一起去吃饭。 &nbsp; <br />
&nbsp; 异步就是你叫我，然后自己去吃饭，我得到消息后可能立即走，也可能等到下班才去吃饭。&nbsp;&nbsp; <br />
较正经的解释：<br />
&nbsp; 普通B/S模式（同步）AJAX技术（异步） &nbsp; <br />
&nbsp; 同步：提交请求-&gt;等待服务器处理-&gt;处理完毕返回 &nbsp; 这个期间客户端浏览器不能干任何事 &nbsp; <br />
&nbsp; 异步: &nbsp; 请求通过事件触发-&gt;服务器处理（这是浏览器仍然可以作其他事情）-&gt;处理完毕<br />
其它比较好的解释：<br />
1：<br />
&nbsp; 同步，就是在发出一个功能调用时，在没有得到结果之前，该调用就不返回。&nbsp;&nbsp;&nbsp;<br />
&nbsp; 异步的概念和同步相对。当一个异步过程调用发出后，调用者不能立刻得到结果。实际处理这个调用的部件在完成后，通过状态、通知和回调来通知调用者。</p>
2：<br />
&nbsp; 同步，就是在发出一个功能调用时，在没有得到结果之前，该调用就不返回。&nbsp;&nbsp;&nbsp;<br />
&nbsp; 异步的概念和同步相对。当一个异步过程调用发出后，调用者不能立刻得到结果。实际处理这个调用的部件在完成后，通过状态、通知和回调来通知调用者。
<img src ="http://www.blogjava.net/firtre/aggbug/180454.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/firtre/" target="_blank">笨蛋</a> 2008-02-18 13:32 <a href="http://www.blogjava.net/firtre/articles/180454.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>StringBuffer和StringTokenizer</title><link>http://www.blogjava.net/firtre/articles/180450.html</link><dc:creator>笨蛋</dc:creator><author>笨蛋</author><pubDate>Mon, 18 Feb 2008 05:11:00 GMT</pubDate><guid>http://www.blogjava.net/firtre/articles/180450.html</guid><wfw:comment>http://www.blogjava.net/firtre/comments/180450.html</wfw:comment><comments>http://www.blogjava.net/firtre/articles/180450.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/firtre/comments/commentRss/180450.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/firtre/services/trackbacks/180450.html</trackback:ping><description><![CDATA[&nbsp;StringBuffer类是String类的一个替代品，一般来说，字符串不管在任何时候，都需要使用字符串缓冲区。StringBuffer比String的灵活之处就在于，它可以在字符串缓冲区中修改字符串内容，而String字符串一旦创建，它的值就是固定的了。<br />
构造方法：<br />
public&nbsp;StringBuffer()<br />
public StringBuffer(int length)<br />
public StringBuffer(String string)&nbsp;<br />
StringBuffer常用的方法：<br />
public int capacity()<br />
public synchronized StringBuffer reverse()<br />
public int length()<br />
pulbic synchronized setLength(int newLength)<br />
public synchronized charAt(int index)<br />
public synchronized setCharAt(int index,char ch)<br />
<br />
StringTokenizer可以将一个字符串分成小片，以便提取和处理其中的信息。<br />
构造方法：<br />
public StringTokenizer(String s, String delim, boolean returnTokens);<br />
public StringTokenizer(String s,String delim);<br />
public StringTokenizer(String s);<br />
常用的方法：<br />
public boolean hasMoreTokens();<br />
public String nextToken();<br />
public nextToken(String delim);——重置delim中的定界符后，这个方法返回下一个命牌。<br />
public countTokens();<br />
<img src ="http://www.blogjava.net/firtre/aggbug/180450.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/firtre/" target="_blank">笨蛋</a> 2008-02-18 13:11 <a href="http://www.blogjava.net/firtre/articles/180450.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>多线程——synchronized</title><link>http://www.blogjava.net/firtre/articles/179047.html</link><dc:creator>笨蛋</dc:creator><author>笨蛋</author><pubDate>Sat, 02 Feb 2008 08:17:00 GMT</pubDate><guid>http://www.blogjava.net/firtre/articles/179047.html</guid><wfw:comment>http://www.blogjava.net/firtre/comments/179047.html</wfw:comment><comments>http://www.blogjava.net/firtre/articles/179047.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/firtre/comments/commentRss/179047.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/firtre/services/trackbacks/179047.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;Java对多线程的支持与同步机制深受大家的喜爱，似乎看起来使用了synchronized关键字就可以轻松地解决多线程共享数据同步问题。到底如何？――还得对synchronized关键字的作用进行深入了解才可定论。总的说来，synchronized关键字可以作为函数的修饰符，也可作为函数内的语句，也就是平时说的同步方法和同步语句块。如果再细的分类，synchronized可作用于...&nbsp;&nbsp;<a href='http://www.blogjava.net/firtre/articles/179047.html'>阅读全文</a><img src ="http://www.blogjava.net/firtre/aggbug/179047.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/firtre/" target="_blank">笨蛋</a> 2008-02-02 16:17 <a href="http://www.blogjava.net/firtre/articles/179047.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>印度是如何做软件开发的（转转）</title><link>http://www.blogjava.net/firtre/articles/176012.html</link><dc:creator>笨蛋</dc:creator><author>笨蛋</author><pubDate>Thu, 17 Jan 2008 09:25:00 GMT</pubDate><guid>http://www.blogjava.net/firtre/articles/176012.html</guid><wfw:comment>http://www.blogjava.net/firtre/comments/176012.html</wfw:comment><comments>http://www.blogjava.net/firtre/articles/176012.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/firtre/comments/commentRss/176012.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/firtre/services/trackbacks/176012.html</trackback:ping><description><![CDATA[<p>我在工作中，接触到印度软件公司开发出来的软件： </p>
<p>整个体系架构非常清晰，按照我们的要求实现了全部功能，而且相当稳定。但是打开具体的代码一看，拖沓冗长，水平不咋样。我们自己的一些程序员就有怪话了，说他们水平真低。但是！印度人能够把软件整体把握得很好，能够完成软件，并得到相当好的设计文档。 </p>
<p>而中国人在那里琢磨数据结构、算法，界面人员就还没编码就想着是Outlook式的还是Visual Studio式的界面。到最后就成为Code高手，对某 <br />
些特定的开发工具精通，但是就是不能保证能够把一个软件稳当、完整的开发出来。 </p>
<p>举个简单的例子： </p>
<p>软件中需要一个列表，用来表示我们处理的事务。该类表在业务繁忙的时候将变得很大。中国人就用双向链表，抱着《数据结构》书在那里写 <br />
链表的类。印度人开了一个大数组，然后就开始干。为什么印度人不用链表，他们说： </p>
<p>1.你们给出的设备（小型机），最少具备512M内存，浪费一些没有什么。 </p>
<p>2.数组方式访问方便、效率高。 </p>
<p>看出了一拿到东西就吭哧吭哧作Code，和好好进行软件分析的不同了吗？正好前几天我有几个同事从印度回来和我们交流，那家公司是CMM4级 <br />
公司。我感受的几点： </p>
<p>1.流程重于项目 </p>
<p>2.QC（就是QA）独立于研发部门，专门检查研发部门的开发流程是不是按照既定流程走。如果QC觉得流程不对，他会直接上报高层，项目肯定就此停止。 </p>
<p>3.所谓的项目经理（PC）一般也是从编码人员升上来的，并不是所谓的不懂技术，一般都至少有四年以上的经验 </p>
<p>4.PC主要就是制定开发计划，负责协调，填写各种表格。 </p>
<p>5.所有的东西（包括草稿）都有文档。 </p>
<p>6.详细文档要求达到只有这个文档就可以编码的程度，一般写文档时间占60%，编码时间极少 </p>
<p>7.有各种详细的review（同行评审），项目组内的，项目组之间的，客户的&#8230;&#8230; </p>
<p>8.计划很详细，的确能达到小时级，但是实际情况还是误差比较大，所以他们也有加班。 </p>
<p>先学习UML和Rose以及RUP，不要总是要找着证据。在中国的软件开发水平下，很难给你一个好的例子，OK？中国人总是要看到一个东西有了试 <br />
验田，而且稻子长得好，才换稻种。要知道在国外上述的软件开发模式的应用，大可以看看 Rational网页上的story。Just do it！一句话，中国的软件开发水平低得很。赶不上印度人，印度的软件公司可以让高中生编代码，它的软件工程水平可想而知。 </p>
<p>当然，你如果是个很牛的程序员。估计够呛，因为中国的气氛中，很牛的程序员都很难接受软件工程的。你可以测试一下自己，看看自己适不适合现在学习软件工程 </p>
<p>1.你是不是不能忍受一个编程序不如你的人做你的项目经理？ <br />
2.你是不是觉得你的老板对客户吹牛皮、夸大自己而感到不舒服？ <br />
3.你是不是一个拿到一个需求脑袋里第一念头就是如何实现的人？ <br />
4.你是不是很崇拜Stallman，Linus，很讨厌Microsoft？ <br />
5.你是不是曾经在深夜编码的时候，突然感觉到一种乏味，对Code的生涯感到一种无趣？我们现在处于深深的自卑当中，感到中国的软件工程水平的低下已经是牵涉到民族劣根性的问题了。 </p>
<p><br />
1.他们的软件教育水平：我们招聘印度人，给应聘者出了一份与国内差不多的试卷，有基础概念和编程题目。等到他们完成后，我们这些中国 <br />
的自认高手惊呆了！他们的编程题目简直象是抄袭的？？程序结构，注释，变量命名就不说了吧，全部都是极其类似！ </p>
<p>反观中国的牛人、高手，每个人有自己的一套。到了新的岗位，先把前任的程序贬损一通，然后自己再开发更多的问题的代码来代替。我的公 <br />
司统计，一个软件中有4个以上CSocket版本，每个人都觉得别人做得差，自己再搞一套。中国人，就是这个样子，还会辩解说&#8220;我们这样有创造 <br />
性&#8221;。其实软件发展，早就走过了求伯君那个编码英雄的年代，程序员已经是个坐办公室的蓝领了。你具备拧好一个螺丝钉的能力就可以了，Code <br />
是最低级的事情了。 </p>
<p><br />
2.他们许多公司的项目经理根本就不懂技术。中国的项目经理如果不能在技术上压服下属，那么下属将与他搞鬼，越是高手越喜欢搞鬼，根本不知道作软件的终极目的是从别人兜里掏钱，而在内部搞不团结。技术高手都会纠集一些对他技术上崇拜的菜鸟，与管理层作对。 </p>
<p>而印度的软件经理根本就不懂正在做的东西，许多甚至直接就是MBA，或者是领域专家（工业设计、地理专家等），而不是编码的专家。但是却 <br />
能够领导大群素质良好的程序员把工作做好，没有内部不团结的情况。许多印度的程序员加入一个公司很长时间，都不知道自己整天编的代码是干 <br />
什么用的。给他们的任务可能就是一个函数的声明以及该函数要实现的功能。我们呢？ </p>
<p><br />
3.他们的编程人员的流动率达到 30%！他们的编程人员流动率（包括内部项目之间的流动）高达 30%，可以想见他们的文档水平如何。他们的 <br />
产品不依赖任何一个人，谁都可以立即辞职，产品的开发还是会正常进行。而中国，是老板怕总工。技术骨干拥兵自重，抗拒管理。任何制定好的计 <br />
划，都有可能被技术人员推翻或者跟你消极怠工。 </p>
<p><br />
4.他们的开发计划能够做到小时级别。如果一个印度公司的项目经理没有上班，那么他的下属将可能不知道作什么。他们的计划一般都定到天， <br />
每个基层开发人员每天的工作量就是 8小时。而我们能够给出月度计划的公司就很少，而给出的月度计划要么不可能实现，要么就可能被取消。开发人员被初略的给个任务，他在月初，可以慢慢琢磨是做成什么样子，然后上上网，聊聊天。到了月中和月末，就开始熬夜编码。 </p>
<p>看到每年，从各大高校不尽牛人滚滚来，我们是不得不要召人，同时又是不抱希望。我公司现在有意以后将核心软件开发外包给印度公司，中 <br />
国人？做做界面吧，中国人做界面会极尽奇技淫巧，搞得花里胡哨的。BTW，大家不要误会我有什么种族歧视。但是我们现在就是对自己歧视，自卑得很。中科院那么多研究院，连个能用的操作系统 <br />
都搞不定。 </p>
<p><br />
北大开发一些东西，比如什么青鸟CASE，就是给一帮人评职称的。杨芙清院士整天搞来搞去，搞出了什么东西？B大，T大的人最难管理，牛得看不见人。中国的程序员骂微软，追 Linux是全世界最狠的，可是我们除了汉化Linux，做了什么东西出来。CDE 是瑞典人写的，Linus是芬兰的，GNome是墨西哥人写的。哎，我们曾经是多么的瞧不起印度人...... </p>
&nbsp;<br />
<br />
<p id="TBPingURL">Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=2048678</p>
再转自：http://blog.csdn.net/liukai721/archive/2008/01/17/2048678.aspx
<img src ="http://www.blogjava.net/firtre/aggbug/176012.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/firtre/" target="_blank">笨蛋</a> 2008-01-17 17:25 <a href="http://www.blogjava.net/firtre/articles/176012.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>软件工程 设计与编码</title><link>http://www.blogjava.net/firtre/articles/176003.html</link><dc:creator>笨蛋</dc:creator><author>笨蛋</author><pubDate>Thu, 17 Jan 2008 09:04:00 GMT</pubDate><guid>http://www.blogjava.net/firtre/articles/176003.html</guid><wfw:comment>http://www.blogjava.net/firtre/comments/176003.html</wfw:comment><comments>http://www.blogjava.net/firtre/articles/176003.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/firtre/comments/commentRss/176003.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/firtre/services/trackbacks/176003.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;对于软件工程中的详细设计：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;有人认为于由没有实际编码，很多细节领悟不透。做出来的详细设计也会和代码相差很大。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;另有人认为前一种说法是项目做得差的标志，因为设计文档就要引导整个软件的构架、流程、思想等，甚至包括使用的组件和实现方法。如果以文档做为基准，项目可以顺利进行。导致代码和设计文档相差太大有大体有两种可能：一是项目实现没有以设计文档为基准进行开发，二是设计文档经过评审，实现思想没有统一。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;外包时：设计应该做得足够详细而且没有歧义。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1、详细设计后，对这个系统会有一个比较系统的理解，会发现需要补充调研的需求之类的。此时补充调研后调整设计的成本是比较低的。否则，等你Coding完成了，再需求变更。。。哦。。。会很痛苦的。这种情况通过好的详细设计来减少很多的。&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2、项目特征中的渐进明细性，概括了项目团队会随着时间的推进，增加对项目的了解。详细设计就是提供了这么个需要。此时的需求变更很大部分是可以发现的。特别是需求比较粗的部分，可以补充调研。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;维护代码的时候，如果没有详细设计而只有原代码，那么维护起来会相当费时。（理解原代码的意图？理解是对的么？）<br />
<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;论坛上各种说法都有，引用认为比较有道理的flyfing（江山如此多娇）评论（摘自CSDN社区）：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;原则上是设计的时间最长，不过国内很少能做到这一点儿。这样，在编码上消耗的时间就不少，而且由于软件设计上时间欠缺造成的设计问题，会让以后的测试困难重重，最后的重头戏反而在测试上，呵呵。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;大学的时候软件工程的课没认真听，只记得老师说过编码的时间是占的比例是相当短的。只好有时间再充电找一个权威一点的说法吧。。。
 <img src ="http://www.blogjava.net/firtre/aggbug/176003.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/firtre/" target="_blank">笨蛋</a> 2008-01-17 17:04 <a href="http://www.blogjava.net/firtre/articles/176003.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>String、StringBulider和StringBuffer </title><link>http://www.blogjava.net/firtre/articles/175645.html</link><dc:creator>笨蛋</dc:creator><author>笨蛋</author><pubDate>Wed, 16 Jan 2008 03:52:00 GMT</pubDate><guid>http://www.blogjava.net/firtre/articles/175645.html</guid><wfw:comment>http://www.blogjava.net/firtre/comments/175645.html</wfw:comment><comments>http://www.blogjava.net/firtre/articles/175645.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/firtre/comments/commentRss/175645.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/firtre/services/trackbacks/175645.html</trackback:ping><description><![CDATA[<span style="font-size: 12pt; font-family: Verdana">1 String&nbsp;是不可变的（String对象具有只读特性）<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String对象实际上是不可变的。String类中每一个对String的操作其实都是新生成一个String对象。原来的String对象是没有改变而且存在在物理内存上的。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;特点：在传递参数的时候，参数是为方法提供信息而不希望本身被修改的。<br />
2 StringBuilder 对象是可变的<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在通过追加、移除、替换或插入字符而创建它后可以对它的对象本身进行修改。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;特点：可以避免频烦地修改String而导致需要耗费大量内存存储String对象（中间过程的String往往是无用的）；但是在多线程的时候使用StringBuilder则是不安全的。建议使用StringBuffer 。<br />
3 StringBuffer 线程安全的可变字符序列<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;它是一个类似于 String的字符串缓冲区，但不能修改。虽然在任意时间点上它都包含某种特定的字符序列，但通过某些方法调用可以改变该序列的长度和内容。可将字符串缓冲区安全地用于多个线程。可以在必要时对这些方法进行同步，因此任意特定实例上的所有操作就好像是以串行顺序发生的，该顺序与所涉及的每个线程进行的方法调用顺序一致。<br />
<br />
总结：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String :对象不可变。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;StringBuilder：对象可变，速度快，但多线程不安全。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;StringBuffer ：对象可变，速度较StringBuilder慢，但多线程安全。</span>
<img src ="http://www.blogjava.net/firtre/aggbug/175645.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/firtre/" target="_blank">笨蛋</a> 2008-01-16 11:52 <a href="http://www.blogjava.net/firtre/articles/175645.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JSP （IBM 中国） </title><link>http://www.blogjava.net/firtre/articles/173419.html</link><dc:creator>笨蛋</dc:creator><author>笨蛋</author><pubDate>Mon, 07 Jan 2008 10:19:00 GMT</pubDate><guid>http://www.blogjava.net/firtre/articles/173419.html</guid><wfw:comment>http://www.blogjava.net/firtre/comments/173419.html</wfw:comment><comments>http://www.blogjava.net/firtre/articles/173419.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/firtre/comments/commentRss/173419.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/firtre/services/trackbacks/173419.html</trackback:ping><description><![CDATA[在当今的环境下，绝大多数的 Web 站点希望根据用户和会话来动态显示内容。大多数内容，例如图片、文本和广告条，可由 HTML 制作人员来轻松完成制作。所以我们需要将&#8220;静态&#8221; HTML 文件内容与可存取或生成动态内容的&#8220;指引项&#8221;混合起来。
<p>&nbsp;&nbsp;&nbsp;&nbsp;JavaServer Page 技术可以满足这种需求。它提供了服务器端脚本来生成包含静态和动态内容的 Web 页面。<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
关键概念：</p>
<ul>
    <li>Servlet
    <li>JavaBean(tm) 组件
    <li>语法 </li>
</ul>
<p>
<table height="400" cellspacing="0" cellpadding="2" width="100%" bgcolor="#ffffff" border="0">
    <tbody>
        <tr>
            <td valign="top" align="left" bgcolor="#ffffff" cellspacing="0" cellpadding="0"><img alt="" src="https://www6.software.ibm.com/developerworks/cn/education/java/jsp/tutorial/images/JSP-2-2.gif" /></td>
            <td width="12" bgcolor="#ffffff">&nbsp;</td>
        </tr>
    </tbody>
</table>
</p>
<p>
<table cellspacing="0" cellpadding="0" border="0">
    <tbody>
        <tr>
            <td width="90%"><font face="Verdana, Arial, Helvetica" size="4"><strong>请求和响应</strong></font></td>
            <td align="right" width="200"><font face="Verdana, Arial, Helvetica" size="2"><nobr></nobr></font></td>
        </tr>
    </tbody>
</table>
<font face="Verdana, Arial, Helvetica" size="2">当一个用户在浏览器中输入 URL时，一个请求被创建并送到服务器上。依据请求的类型，服务器的响应可能是存放在服务器上的静态 HTML 页面，或者是从多方汇集的动态内容。</p>
<p>直到今天，生成动态内容的最普通方法是通过 Common Gateway Interface, 也称为 CGI。CGI 程序(通常用 C 或者 Perl 编写) 通过以 HTML 表单形式读入用户的输入，然后返回定制的 HTML 页面。但是，CGI 有一个缺点：对于用户的每个请求，CGI 脚本必须经过&#8220;载入&#8221;、&#8220;运行&#8221; 和&#8220;调出&#8221;。这非常低效。</p>
<p></font>
<table height="400" cellspacing="0" cellpadding="2" width="100%" bgcolor="#ffffff" border="0">
    <tbody>
        <tr>
            <td valign="top" align="left" bgcolor="#ffffff" cellspacing="0" cellpadding="0"><img alt="" src="https://www6.software.ibm.com/developerworks/cn/education/java/jsp/tutorial/images/JSP-2-3.gif" /></td>
            <td width="12" bgcolor="#ffffff">&nbsp;</td>
        </tr>
    </tbody>
</table>
<table cellspacing="0" cellpadding="0" border="0">
    <tbody>
        <tr>
            <td width="90%"><font face="Verdana, Arial, Helvetica" size="4"><strong>静态和动态响应</strong></font></td>
            <td align="right" width="200"><font face="Verdana, Arial, Helvetica" size="2"><nobr></nobr></font></td>
        </tr>
    </tbody>
</table>
<br x="7" />
<br x="7" />
<font face="Verdana, Arial, Helvetica" size="2"></p>
<p>另一种生成动态内容的方法是使用 Java servlet。servlet 是 Java 程序可以被载入到一个应用服务器中，例如WebSphere Application Server。 servlet 可以完成 CGI 脚本的功能，但是它们驻留在服务器的内存中。因此，servlet 要对用户的响应更为及时。</p>
<p>JSP 技术提供了一种混合HTML 和 Java servlet 编程的环境。JSP 页面是纯文本文件而且看起来很类似 HTML 页面。HTML 通过新的标记得以扩展，新的标记指明一个 servlet 控制动态内容的生成的程序逻辑。<br />
</p>
<p></font><font face="Verdana, Arial, Helvetica" size="2">&nbsp; </p>
<p>如果用户请求的信息被包含在驻留于 HTTP 服务器的静态页面中，响应将是驻留页面的 HTML 版本。对动态响应而言，将从 HTTP 服务器产生一个调用到 WebSphere Application Server，或其他任意一种应用服务器，它们将管理 JSP 页面和 servlet。应用服务器可以被配置成预先载入 Java servlet 来实现对用户响应速度的提高，甚至对于第一个用户的请求。</p>
<p>JSP 页面被一次编译为 servlet 并被载入到内存。如果 JSP 页面有了新版本，应用服务器将编译新的版本然后载入对应的新 servlet。</font></p>
<p>为什么要使用JSP呢？<br />
首先，Java 编程语言具有 "Write Once, Run Anywhere(tm)"(书写一次，任意运行) 的特性。<br />
<br />
&nbsp;&nbsp;</p>
<img src ="http://www.blogjava.net/firtre/aggbug/173419.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/firtre/" target="_blank">笨蛋</a> 2008-01-07 18:19 <a href="http://www.blogjava.net/firtre/articles/173419.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JDBC </title><link>http://www.blogjava.net/firtre/articles/173418.html</link><dc:creator>笨蛋</dc:creator><author>笨蛋</author><pubDate>Mon, 07 Jan 2008 10:19:00 GMT</pubDate><guid>http://www.blogjava.net/firtre/articles/173418.html</guid><wfw:comment>http://www.blogjava.net/firtre/comments/173418.html</wfw:comment><comments>http://www.blogjava.net/firtre/articles/173418.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/firtre/comments/commentRss/173418.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/firtre/services/trackbacks/173418.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: JDBC（Java Data Base Connectivity,java数据库连接）是一种用于执行SQL语句的Java API，可以为多种关系数据库提供统一访问，它由一组用Java语言编写的类和接口组成。JDBC提供了一种基准，据此可以构建更高级的工具和接口，使数据库开发人员能够编写数据库应用程序，同时，JDBC也是个商标名。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 有了...&nbsp;&nbsp;<a href='http://www.blogjava.net/firtre/articles/173418.html'>阅读全文</a><img src ="http://www.blogjava.net/firtre/aggbug/173418.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/firtre/" target="_blank">笨蛋</a> 2008-01-07 18:19 <a href="http://www.blogjava.net/firtre/articles/173418.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>编写优良的Java代码（IBM学习） </title><link>http://www.blogjava.net/firtre/articles/173417.html</link><dc:creator>笨蛋</dc:creator><author>笨蛋</author><pubDate>Mon, 07 Jan 2008 10:18:00 GMT</pubDate><guid>http://www.blogjava.net/firtre/articles/173417.html</guid><wfw:comment>http://www.blogjava.net/firtre/comments/173417.html</wfw:comment><comments>http://www.blogjava.net/firtre/articles/173417.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/firtre/comments/commentRss/173417.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/firtre/services/trackbacks/173417.html</trackback:ping><description><![CDATA[<p>1：保持类最小。<br />
2：保持方法最小。运行时效率不是要具有小方法的原因，可读性才是真正的目标。这将使得代码更加容易维护，并且在需要添加功能时更加容易更改。<br />
3：给方法取好名称。揭示意图的方法名。<br />
4：保持类的数量最少。如果需要，就可以添加一类；不要为了加类而加类。</p>
5：保持注释的数量最少。注释使代码维护变困难，如果想更改代码，就必需要先修改注释，否则注释会可怕地过期，这样会使维护的时间加倍；如何解决？如果代码太难阅读和理解而需要注释，我就需要使它足够清晰，从而不需要注释；如果代码太长，或者做太多的事情。我就简化它；如果代码太隐晦，就添加助手方法，使之清晰。保持代码清晰！如果您需要系统或者某个特定组件的全景描述，就编写一个简短的注释来描述。
<p>罗嗦的注释一般比较难维护，通常不及一个小的、编写良好的方法那么好地表达意图，并且很快就会过期。根本不要过分依赖注释。</p>
6：使用一致的风格。惟一绝对的风格规则是<em>一致性</em>。如果一个项目上的每个人都用不同的风格，那么阅读代码将变得很困难。挑选一种风格并且不要改变。<br />
7：避免switch。
<p>8：使方法是 <code>public</code> 的，变量是 <code>protected</code> 的，直到您有一个很好的理由限制访问。如果您对代码中您设想其他人不应该访问的东西限制访问，您就是在设想自己无所不知。这在大多数时候是一个危险的假设。不要以&#8220;这段代码不应该被调用&#8221;、或者&#8220;没有人会用这段代码&#8221;为理由气绝将代码设为public。</p>
<img src ="http://www.blogjava.net/firtre/aggbug/173417.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/firtre/" target="_blank">笨蛋</a> 2008-01-07 18:18 <a href="http://www.blogjava.net/firtre/articles/173417.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>主题：java垃圾收集算法(摘自javaeye) </title><link>http://www.blogjava.net/firtre/articles/173415.html</link><dc:creator>笨蛋</dc:creator><author>笨蛋</author><pubDate>Mon, 07 Jan 2008 10:17:00 GMT</pubDate><guid>http://www.blogjava.net/firtre/articles/173415.html</guid><wfw:comment>http://www.blogjava.net/firtre/comments/173415.html</wfw:comment><comments>http://www.blogjava.net/firtre/articles/173415.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/firtre/comments/commentRss/173415.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/firtre/services/trackbacks/173415.html</trackback:ping><description><![CDATA[<p><font face="Arial" color="#0000ff"><strong>http://www.javaeye.com/topic/144859<br />
</strong></font></p>
<font face="Arial">
<p><font face="Arial" color="#0000ff"><strong>1.垃圾收集算法的核心思想</strong></font></p>
<p><font face="Arial">　　Java语言建立了垃圾收集机制，用以跟踪正在使用的对象和发现并回收不再使用(引用)的对象。该机制可以有效防范动态内存分配中可能发生的两个危险：因内存垃圾过多而引发的内存耗尽，以及不恰当的内存释放所造成的内存非法引用。</font></p>
<p><font face="Arial">　　垃圾收集算法的核心思想是：对虚拟机可用内存空间，即堆空间中的对象进行识别，如果对象正在被引用，那么称其为存活对象，反之，如果对象不再被引用，则为垃圾对象，可以回收其占据的空间，用于再分配。垃圾收集算法的选择和垃圾收集系统参数的合理调节直接影响着系统性能，因此需要开发人员做比较深入的了解。</font></p>
<p><font face="Arial"><font color="#0000ff"><strong>2.触发主GC(Garbage Collector)的条件</strong></font></font></p>
<p><font face="Arial">　　JVM进行次GC的频率很高,但因为这种GC占用时间极短,所以对系统产生的影响不大。更值得关注的是主GC的触发条件,因为它对系统影响很明显。总的来说,有两个条件会触发主GC:<br />
&nbsp; </font></p>
<p><font face="Arial">　　①当应用程序空闲时,即没有应用线程在运行时,GC会被调用。因为GC在优先级最低的线程中进行,所以当应用忙时,GC线程就不会被调用,但以下条件除外。</font></p>
<p><font face="Arial">　　②Java堆内存不足时,GC会被调用。当应用线程在运行,并在运行过程中创建新对象,若这时内存空间不足,JVM就会强制地调用GC线程,以便回收内存用于新的分配。若GC一次之后仍不能满足内存分配的要求,JVM会再进行两次GC作进一步的尝试,若仍无法满足要求,则 JVM将报&#8220;out of memory&#8221;的错误,Java应用将停止。</font></p>
<p><font face="Arial">　　由于是否进行主GC由JVM根据系统环境决定,而系统环境在不断的变化当中,所以主GC的运行具有不确定性,无法预计它何时必然出现,但可以确定的是对一个长期运行的应用来说,其主GC是反复进行的。</font></p>
<p><font face="Arial"><font color="#0000ff"><strong>3.减少GC开销的措施</strong></font></font></p>
<p><font face="Arial">　　根据上述GC的机制,程序的运行会直接影响系统环境的变化,从而影响GC的触发。若不针对GC的特点进行设计和编码,就会出现内存驻留等一系列负面影响。为了避免这些影响,基本的原则就是尽可能地减少垃圾和减少GC过程中的开销。具体措施包括以下几个方面:</font></p>
<p><font face="Arial">　　(1)不要显式调用System.gc()</font></p>
<p><font face="Arial">　　此函数建议JVM进行主GC,虽然只是建议而非一定,但很多情况下它会触发主GC,从而增加主GC的频率,也即增加了间歇性停顿的次数。</font></p>
<p><font face="Arial">　　(2)尽量减少临时对象的使用</font></p>
<p><font face="Arial">　　临时对象在跳出函数调用后,会成为垃圾,少用临时变量就相当于减少了垃圾的产生,从而延长了出现上述第二个触发条件出现的时间,减少了主GC的机会。</font></p>
<p><font face="Arial">　　(3)对象不用时最好显式置为Null</font></p>
<p><font face="Arial">　　一般而言,为Null的对象都会被作为垃圾处理,所以将不用的对象显式地设为Null,有利于GC收集器判定垃圾,从而提高了GC的效率。</font></p>
<p><font face="Arial">　　(4)尽量使用StringBuffer,而不用String来累加字符串(详见blog另一篇文章JAVA中String与StringBuffer)</font></p>
<p><font face="Arial">　　由于String是固定长的字符串对象,累加String对象时,并非在一个String对象中扩增,而是重新创建新的String对象,如Str5=Str1+Str2+Str3+Str4,这条语句执行过程中会产生多个垃圾对象,因为对次作&#8220;+&#8221;操作时都必须创建新的String对象,但这些过渡对象对系统来说是没有实际意义的,只会增加更多的垃圾。避免这种情况可以改用StringBuffer来累加字符串,因StringBuffer是可变长的,它在原有基础上进行扩增,不会产生中间对象。</font></p>
<p><font face="Arial">　　(5)能用基本类型如Int,Long,就不用Integer,Long对象</font></p>
<p><font face="Arial">　　基本类型变量占用的内存资源比相应对象占用的少得多,如果没有必要,最好使用基本变量。</font></p>
<p><font face="Arial">　　(6)尽量少用静态对象变量</font></p>
<p><font face="Arial">　　静态变量属于全局变量,不会被GC回收,它们会一直占用内存。</font></p>
<p><font face="Arial">　　(7)分散对象创建或删除的时间</font></p>
<p><font face="Arial">　　集中在短时间内大量创建新对象,特别是大对象,会导致突然需要大量内存,JVM在面临这种情况时,只能进行主GC,以回收内存或整合内存碎片,从而增加主GC的频率。集中删除对象,道理也是一样的。它使得突然出现了大量的垃圾对象,空闲空间必然减少,从而大大增加了下一次创建新对象时强制主GC的机会。</font></p>
<p><font face="Arial"><font color="#0000ff"><strong>4.gc与finalize方法</strong></font></font></p>
<p><font face="Arial">　　⑴gc方法请求垃圾回收</font></p>
<p><font face="Arial">　　使用System.gc()可以不管JVM使用的是哪一种垃圾回收的算法，都可以请求Java的垃圾回收。需要注意的是，调用System.gc()也仅仅是一个请求。JVM接受这个消息后，并不是立即做垃圾回收，而只是对几个垃圾回收算法做了加权，使垃圾回收操作容易发生，或提早发生，或回收较多而已。</font></p>
<p><font face="Arial">　　⑵finalize方法透视垃圾收集器的运行</font></p>
<p><font face="Arial">　　在JVM垃圾收集器收集一个对象之前 ，一般要求程序调用适当的方法释放资源，但在没有明确释放资源的情况下，Java提供了缺省机制来终止化该对象释放资源，这个方法就是finalize()。它的原型为：</font></p>
<p><font face="Arial">　　protected void finalize() throws Throwable</font></p>
<p><font face="Arial">　　在finalize()方法返回之后，对象消失，垃圾收集开始执行。原型中的throws Throwable表示它可以抛出任何类型的异常。</font></p>
<p><font face="Arial">　　因此，当对象即将被销毁时，有时需要做一些善后工作。可以把这些操作写在finalize()方法里。</font></p>
<p><font face="Arial"></font>&nbsp;</p>
<div class="code_title">java 代码</div>
<div class="dp-highlighter">
<div class="bar"></div>
<ol class="dp-j">
    <li class="alt"><span><span class="keyword">protected</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;finalize()&nbsp; &nbsp;&nbsp;</span></span>
    <li class=""><span>　　&nbsp;{&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;</span><span class="comment">//&nbsp;finalization&nbsp;code&nbsp;here&nbsp; </span><span>&nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;}&nbsp;&nbsp;</span> </li>
</ol>
</div>
<p>&nbsp;</p>
<p>⑶代码示例<br />
</p>
<div class="code_title">java 代码</div>
<div class="dp-highlighter">
<div class="bar"></div>
<ol class="dp-j">
    <li class="alt"><span><span class="keyword">class</span><span>&nbsp;Garbage{&nbsp; &nbsp;&nbsp;</span></span>
    <li class=""><span>　　&nbsp;</span><span class="keyword">int</span><span>&nbsp;index;&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;</span><span class="keyword">static</span><span>&nbsp;</span><span class="keyword">int</span><span>&nbsp;count;&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>&nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;Garbage()&nbsp;{&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;count++;&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;System.out.println(</span><span class="string">"object&nbsp;"</span><span>+count+</span><span class="string">"&nbsp;construct"</span><span>);&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;setID(count);&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;}&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>&nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;</span><span class="keyword">void</span><span>&nbsp;setID(</span><span class="keyword">int</span><span>&nbsp;id)&nbsp;{&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;index=id;&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;}&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>&nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;</span><span class="keyword">protected</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;finalize()&nbsp;</span><span class="comment">//重写finalize方法&nbsp; </span><span>&nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;{&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;System.out.println(</span><span class="string">"object&nbsp;"</span><span>+index+</span><span class="string">"&nbsp;is&nbsp;reclaimed"</span><span>);&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;}&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>&nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">static</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;main(String[]&nbsp;args)&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;{&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;</span><span class="keyword">new</span><span>&nbsp;Garbage();&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;</span><span class="keyword">new</span><span>&nbsp;Garbage();&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;</span><span class="keyword">new</span><span>&nbsp;Garbage();&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;</span><span class="keyword">new</span><span>&nbsp;Garbage();&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;System.gc();&nbsp;</span><span class="comment">//请求运行垃圾收集器&nbsp; </span><span>&nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;}&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>&nbsp;&nbsp;</span>
    <li class="alt"><span>　}&nbsp;&nbsp;</span> </li>
</ol>
</div>
<p><font face="Arial"><font color="#0000ff"><strong>5.Java 内存泄漏 <br />
</strong></font>　　由于采用了垃圾回收机制，任何不可达对象(对象不再被引用)都可以由垃圾收集线程回收。因此通常说的Java 内存泄漏其实是指无意识的、非故意的对象引用，或者无意识的对象保持。无意识的对象引用是指代码的开发人员本来已经对对象使用完毕，却因为编码的错误而意外地保存了对该对象的引用(这个引用的存在并不是编码人员的主观意愿)，从而使得该对象一直无法被垃圾回收器回收掉，这种本来以为可以释放掉的却最终未能被释放的空间可以认为是被&#8220;泄漏了&#8221;。</font></p>
<p><font face="Arial">　　考虑下面的程序,在ObjStack类中,使用push和pop方法来管理堆栈中的对象。两个方法中的索引(index)用于指示堆栈中下一个可用位置。push方法存储对新对象的引用并增加索引值,而pop方法减小索引值并返回堆栈最上面的元素。在main方法中,创建了容量为64的栈,并64次调用push方法向它添加对象,此时index的值为64,随后又32次调用pop方法,则index的值变为32,出栈意味着在堆栈中的空间应该被收集。但事实上,pop方法只是减小了索引值,堆栈仍然保持着对那些对象的引用。故32个无用对象不会被GC回收,造成了内存渗漏。</font></p>
<p><font face="Arial"></font>&nbsp;</p>
<div class="code_title">java 代码</div>
<div class="dp-highlighter">
<div class="bar"></div>
<ol class="dp-j">
    <li class="alt"><span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;ObjStack&nbsp;{&nbsp; &nbsp;&nbsp;</span></span>
    <li class=""><span>　　&nbsp;</span><span class="keyword">private</span><span>&nbsp;Object[]&nbsp;stack;&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;</span><span class="keyword">private</span><span>&nbsp;</span><span class="keyword">int</span><span>&nbsp;index;&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;ObjStack(</span><span class="keyword">int</span><span>&nbsp;indexcount)&nbsp;{&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;stack&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;Object[indexcount];&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;index&nbsp;=&nbsp;</span><span class="number">0</span><span>;&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;}&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;push(Object&nbsp;obj)&nbsp;{&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;stack[index]&nbsp;=&nbsp;obj;&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;index++;&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;}&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;</span><span class="keyword">public</span><span>&nbsp;Object&nbsp;pop()&nbsp;{&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;index--;&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;</span><span class="keyword">return</span><span>&nbsp;stack[index];&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;}&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;}&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;Pushpop&nbsp;{&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">static</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;main(String[]&nbsp;args)&nbsp;{&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;</span><span class="keyword">int</span><span>&nbsp;i&nbsp;=&nbsp;</span><span class="number">0</span><span>;&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;Object&nbsp;tempobj;&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>&nbsp;&nbsp;</span>
    <li class=""><span class="comment">//new一个ObjStack对象，并调用有参构造函数。分配stack&nbsp;Obj数组的空间大小为64，可以存64个对象，从0开始存储 </span><span>&nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;ObjStack&nbsp;stack1&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;ObjStack(</span><span class="number">64</span><span>); &nbsp;&nbsp;</span>
    <li class=""><span>&nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;</span><span class="keyword">while</span><span>&nbsp;(i&nbsp;&lt;&nbsp;</span><span class="number">64</span><span>)&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;{&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;tempobj&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;Object();</span><span class="comment">//循环new&nbsp;Obj对象，把每次循环的对象一一存放在stack&nbsp;Obj数组中。&nbsp; </span><span>&nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;stack1.push(tempobj);&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;i++;&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;System.out.println(</span><span class="string">"第"</span><span>&nbsp;+&nbsp;i&nbsp;+&nbsp;</span><span class="string">"次进栈"</span><span>&nbsp;+&nbsp;</span><span class="string">"\t"</span><span>);&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;}&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>&nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;</span><span class="keyword">while</span><span>&nbsp;(i&nbsp;&gt;&nbsp;</span><span class="number">32</span><span>)&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;{&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;tempobj&nbsp;=&nbsp;stack1.pop();</span><span class="comment">//这里造成了空间的浪费。&nbsp; </span><span>&nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;</span><span class="comment">//正确的pop方法可改成如下所指示,当引用被返回后,堆栈删除对他们的引用,因此垃圾收集器在以后可以回收他们。&nbsp; </span><span>&nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;</span><span class="comment">/*&nbsp; </span>&nbsp;
    <li class=""><span><span class="comment">　　&nbsp;*&nbsp;public&nbsp;Object&nbsp;pop()&nbsp;{index&nbsp;-&nbsp;-;Object&nbsp;temp&nbsp;=&nbsp;stack&nbsp;[index];stack&nbsp;[index]=null;return&nbsp;temp;}&nbsp; </span>&nbsp;</span>
    <li class="alt"><span><span class="comment">　　&nbsp;*/</span><span>&nbsp; &nbsp;&nbsp;</span></span>
    <li class=""><span>　　&nbsp;i--;&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;System.out.println(</span><span class="string">"第"</span><span>&nbsp;+&nbsp;(</span><span class="number">64</span><span>&nbsp;-&nbsp;i)&nbsp;+&nbsp;</span><span class="string">"次出栈"</span><span>&nbsp;+&nbsp;</span><span class="string">"\t"</span><span>);&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;}&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>　　&nbsp;}&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>　　&nbsp;}&nbsp;&nbsp;</span> </li>
</ol>
</div>
<p>&nbsp;</p>
<p><font face="Arial" color="#0000ff"><strong>6.如何消除内存泄漏</strong></font></p>
<p><font face="Arial">　　虽然Java虚拟机(JVM)及其垃圾收集器(garbage collector，GC)负责管理大多数的内存任务，Java软件程序中还是有可能出现内存泄漏。实际上，这在大型项目中是一个常见的问题。避免内存泄漏的第一步是要弄清楚它是如何发生的。本文介绍了编写Java代码的一些常见的内存泄漏陷阱，以及编写不泄漏代码的一些最佳实践。一旦发生了内存泄漏，要指出造成泄漏的代码是非常困难的。因此本文还介绍了一种新工具，用来诊断泄漏并指出根本原因。该工具的开销非常小，因此可以使用它来寻找处于生产中的系统的内存泄漏。</font></p>
<p><font face="Arial">　　垃圾收集器的作用</font></p>
<p><font face="Arial">　　虽然垃圾收集器处理了大多数内存管理问题，从而使编程人员的生活变得更轻松了，但是编程人员还是可能犯错而导致出现内存问题。简单地说，GC循环地跟踪所有来自&#8220;根&#8221;对象(堆栈对象、静态对象、JNI句柄指向的对象，诸如此类)的引用，并将所有它所能到达的对象标记为活动的。程序只可以操纵这些对象;其他的对象都被删除了。因为GC使程序不可能到达已被删除的对象，这么做就是安全的。</font></p>
<p><font face="Arial">　　虽然内存管理可以说是自动化的，但是这并不能使编程人员免受思考内存管理问题之苦。例如，分配(以及释放)内存总会有开销，虽然这种开销对编程人员来说是不可见的。创建了太多对象的程序将会比完成同样的功能而创建的对象却比较少的程序更慢一些(在其他条件相同的情况下)。</font></p>
<p><font face="Arial">　　而且，与本文更为密切相关的是，如果忘记&#8220;释放&#8221;先前分配的内存，就可能造成内存泄漏。如果程序保留对永远不再使用的对象的引用，这些对象将会占用并耗尽内存，这是因为自动化的垃圾收集器无法证明这些对象将不再使用。正如我们先前所说的，如果存在一个对对象的引用，对象就被定义为活动的，因此不能删除。为了确保能回收对象占用的内存，编程人员必须确保该对象不能到达。这通常是通过将对象字段设置为null或者从集合(collection)中移除对象而完成的。但是，注意，当局部变量不再使用时，没有必要将其显式地设置为null。对这些变量的引用将随着方法的退出而自动清除。</font></p>
<p><font face="Arial">　　概括地说，这就是内存托管语言中的内存泄漏产生的主要原因：保留下来却永远不再使用的对象引用。</font></p>
<p><font face="Arial">　　典型泄漏</font></p>
<p><font face="Arial">　　既然我们知道了在Java中确实有可能发生内存泄漏，就让我们来看一些典型的内存泄漏及其原因。</font></p>
<p><font face="Arial">　　全局集合</font></p>
<p><font face="Arial">　　在大的应用程序中有某种全局的数据储存库是很常见的，例如一个JNDI树或一个会话表。在这些情况下，必须注意管理储存库的大小。必须有某种机制从储存库中移除不再需要的数据。</font></p>
<p><font face="Arial">　　这可能有多种方法，但是最常见的一种是周期性运行的某种清除任务。该任务将验证储存库中的数据，并移除任何不再需要的数据。</font></p>
<p><font face="Arial">　　另一种管理储存库的方法是使用反向链接(referrer)计数。然后集合负责统计集合中每个入口的反向链接的数目。这要求反向链接告诉集合何时会退出入口。当反向链接数目为零时，该元素就可以从集合中移除了。</font></p>
<p><font face="Arial">　　缓存</font></p>
<p><font face="Arial">　　缓存是一种数据结构，用于快速查找已经执行的操作的结果。因此，如果一个操作执行起来很慢，对于常用的输入数据，就可以将操作的结果缓存，并在下次调用该操作时使用缓存的数据。</font></p>
<p><font face="Arial">　　缓存通常都是以动态方式实现的，其中新的结果是在执行时添加到缓存中的。典型的算法是：</font></p>
<p><font face="Arial">　　检查结果是否在缓存中，如果在，就返回结果。</font></p>
<p><font face="Arial">　　如果结果不在缓存中，就进行计算。</font></p>
<p><font face="Arial">　　将计算出来的结果添加到缓存中，以便以后对该操作的调用可以使用。</font></p>
<p><font face="Arial">　　该算法的问题(或者说是潜在的内存泄漏)出在最后一步。如果调用该操作时有相当多的不同输入，就将有相当多的结果存储在缓存中。很明显这不是正确的方法。</font></p>
<p><font face="Arial">　　为了预防这种具有潜在破坏性的设计，程序必须确保对于缓存所使用的内存容量有一个上限。因此，更好的算法是：</font></p>
<p><font face="Arial">　　检查结果是否在缓存中，如果在，就返回结果。</font></p>
<p><font face="Arial">　　如果结果不在缓存中，就进行计算。</font></p>
<p><font face="Arial">　　如果缓存所占的空间过大，就移除缓存最久的结果。</font></p>
<p><font face="Arial">　　将计算出来的结果添加到缓存中，以便以后对该操作的调用可以使用。</font></p>
<p><font face="Arial">　　通过始终移除缓存最久的结果，我们实际上进行了这样的假设：在将来，比起缓存最久的数据，最近输入的数据更有可能用到。这通常是一个不错的假设。</font></p>
<p><font face="Arial">　　新算法将确保缓存的容量处于预定义的内存范围之内。确切的范围可能很难计算，因为缓存中的对象在不断变化，而且它们的引用包罗万象。为缓存设置正确的大小是一项非常复杂的任务，需要将所使用的内存容量与检索数据的速度加以平衡。</font></p>
<p><font face="Arial">　　解决这个问题的另一种方法是使用java.lang.ref.SoftReference类跟踪缓存中的对象。这种方法保证这些引用能够被移除，如果虚拟机的内存用尽而需要更多堆的话。</font></p>
<p><font face="Arial">　　ClassLoader</font></p>
<p><font face="Arial">　　Java ClassLoader结构的使用为内存泄漏提供了许多可乘之机。正是该结构本身的复杂性使ClassLoader在内存泄漏方面存在如此多的问题。ClassLoader的特别之处在于它不仅涉及&#8220;常规&#8221;的对象引用，还涉及元对象引用，比如：字段、方法和类。这意味着只要有对字段、方法、类或ClassLoader的对象的引用，ClassLoader就会驻留在JVM中。因为ClassLoader本身可以关联许多类及其静态字段，所以就有许多内存被泄漏了。</font></p>
<p><font face="Arial">　　确定泄漏的位置</font></p>
<p><font face="Arial">　　通常发生内存泄漏的第一个迹象是：在应用程序中出现了OutOfMemoryError。这通常发生在您最不愿意它发生的生产环境中，此时几乎不能进行调试。有可能是因为测试环境运行应用程序的方式与生产系统不完全相同，因而导致泄漏只出现在生产中。在这种情况下，需要使用一些开销较低的工具来监控和查找内存泄漏。还需要能够无需重启系统或修改代码就可以将这些工具连接到正在运行的系统上。可能最重要的是，当进行分析时，需要能够断开工具而保持系统不受干扰。</font></p>
<p><font face="Arial">　　虽然OutOfMemoryError通常都是内存泄漏的信号，但是也有可能应用程序确实正在使用这么多的内存;对于后者，或者必须增加JVM可用的堆的数量，或者对应用程序进行某种更改，使它使用较少的内存。但是，在许多情况下，OutOfMemoryError都是内存泄漏的信号。一种查明方法是不间断地监控GC的活动，确定内存使用量是否随着时间增加。如果确实如此，就可能发生了内存泄漏。</font></p>
<p><font face="Arial"></font>&nbsp;</font></p>
<img src ="http://www.blogjava.net/firtre/aggbug/173415.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/firtre/" target="_blank">笨蛋</a> 2008-01-07 18:17 <a href="http://www.blogjava.net/firtre/articles/173415.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>句柄和ID </title><link>http://www.blogjava.net/firtre/articles/173413.html</link><dc:creator>笨蛋</dc:creator><author>笨蛋</author><pubDate>Mon, 07 Jan 2008 10:16:00 GMT</pubDate><guid>http://www.blogjava.net/firtre/articles/173413.html</guid><wfw:comment>http://www.blogjava.net/firtre/comments/173413.html</wfw:comment><comments>http://www.blogjava.net/firtre/articles/173413.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/firtre/comments/commentRss/173413.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/firtre/services/trackbacks/173413.html</trackback:ping><description><![CDATA[在Windows程序设计中，句柄是无法精确定义的术语。随便找一个高手，让他给你讲讲句柄是什么，恐怕他都很难给你一个具体的定义来。<br />
<br />
在Windows程序设计中，句柄无所不在，窗口有窗口的句柄HWND，线程和进程也有句柄HANDLE，甚至有人把套接字也称为句柄（我就是这样的）。<br />
<br />
句柄在英文中是handle，作为动词讲是处理的意思。简而言之，句柄是处理对象的一个接口，对于程序中所涉及的对象，你可以通过句柄去操作他。你不应该试图去回答句柄是什么，而应该从务虚的角度去理解他，知道他干什么即可。<br />
<br />
有人说，因为handle的定义是void *，因此他是一个指针。有些熟悉内核的人说这是一个索引。这些说法都是不准确的。需要注意的是，微软并没有精确定义句柄的含义，也许在某个特殊的操作系统中，他使用了一种内部含义，但是在其他版本中，就不保证这样了。任何对句柄的内在假设都可能导致灾难性的后果。<br />
<br />
API是接口，句柄是接口，两者有什么区别？API是一个通用的函数族，他处理所有的对象，而句柄是和某个具体对象相关联的数据结构。只有借助句柄，API才知道处理哪个对象。<br />
<br />
有些对象有ID。句柄表示特殊的对象，ID也表示某个对象，为什么要两个东西来表示？<br />
<br />
首先，句柄不能唯一表示对象。一个对象可以有多个句柄。例如：假设我们用CreateProcess创建一个进程，该进程的第一个线程的句柄会返回给调用CreateProcess的进程。同时，在新创建的进程中，该线程也会有一个句柄。这样，这个线程就有两个句柄。我们也可以用DuplicateHandle复制一个句柄，这个句柄和原来句柄是不一样的，但是他们都表示同一个对象。而每个有ID的对象，在系统范围内，ID肯定是唯一的。<br />
<br />
其次，句柄所能实现的功能ID不能实现。毕竟ID只是一个数字，他不能记录很多信息。而句柄可能在其内部结构中记录了很多信息（如权限、有无信号等）。<br />
<br />
总之，如果试图解释他到底是什么，学习句柄就会误入歧途。从虚的角度去理解，对于新手是难一点，但是这也许是唯一正确的办法。 <br />
<br />
<br />
句柄一般是操作系统避免你直接对某个对象数据结构进行操作而引入的，可以通过句柄来使用某个对象，而不用知道句柄的内容。<br />
<br />
句柄是一种指向指针的指针。我们知&nbsp;道，所谓指针是一种内存地址。应用程序启动后，组成这&nbsp; <br />
个程序的各对象是住留在内存的。如果简单地理解，似乎我们只要获知这个内存的首地址，那么就可以随时用这个地址&nbsp;访问对象。但是，如果您真的这样认为，那么您就大错特错了。我们知道，Windows是一&nbsp;个以虚拟内存为基础的操作系统。在这种系统环境下，Windows内存管理器经常在内存中来回移动对象，依此来满足各种应用程序的内存需要。对象被移动意味着它的地址变化&nbsp;了。如果地址总是如此变化，我们该到哪里去找该对象呢?为了解决这个问题，Windows操作系统为各应用程序腾出一些内存储地址，用来专门&nbsp;登记各应用对象在内存中的地址变化，而这个地址(存储单元的位置)本身是不变的。Windows内存管理器在移动对象在内存中的位置后，把对象新的地址告知这个句柄地址来保存。这样我们只需记住这个句柄地址就可以间接地知道对象具体在内存中的哪个位置。这个地址是在对象装载(Load)时由系统分配给的，当系统卸载时(Unload)又释放给系统。句柄地址(稳定)&#8594;记载着对象在内存中的地址&#8594;对象在内存中的地址(不稳定)&#8594;实际对象。但是，必须注意的是程序每次从新启动，系统不能保证分配给这个程序的句柄还是原来的那个句柄，而且绝大多数情况的确不一样的。假如我们把进入电影院看电影看成&nbsp;是一个应用程序的启动运行，那么系统给应用程序分配的句柄总是不一样，这和每次电&nbsp;影院售给我们的门票总是不同的一个座位是一样的道理。<br />
<img src ="http://www.blogjava.net/firtre/aggbug/173413.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/firtre/" target="_blank">笨蛋</a> 2008-01-07 18:16 <a href="http://www.blogjava.net/firtre/articles/173413.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>哈希表 ——简单说明 </title><link>http://www.blogjava.net/firtre/articles/126875.html</link><dc:creator>笨蛋</dc:creator><author>笨蛋</author><pubDate>Thu, 28 Jun 2007 09:41:00 GMT</pubDate><guid>http://www.blogjava.net/firtre/articles/126875.html</guid><wfw:comment>http://www.blogjava.net/firtre/comments/126875.html</wfw:comment><comments>http://www.blogjava.net/firtre/articles/126875.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/firtre/comments/commentRss/126875.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/firtre/services/trackbacks/126875.html</trackback:ping><description><![CDATA[摘自：编程中国<br><a href="http://www.bc-cn.net/Article/kfyy/sjjg/200411/260.html">http://www.bc-cn.net/Article/kfyy/sjjg/200411/260.html</a><br><br><br><br>哈希表（一）<br>
<p><strong><em>教学目的：</em></strong> 掌握哈希表的概念作用及意义，哈希表的构造方法</p>
<p><strong><em>教学重点：</em></strong> 哈希表的构造方法</p>
<p><strong><em>教学难点：</em></strong> 哈希表的构造方法</p>
<p><strong><em>授课内容：</em></strong></p>
<p>一、哈希表的概念及作用</p>
<blockquote>
<p>一般的线性表，树中，记录在结构中的相对位置是随机的，即和记录的关键字之间不存在确定的关系，因此，在结构中查找记录时需进行一系列和关键字的比较。这一类查找方法建立在&#8220;比较&#8220;的基础上，查找的效率依赖于查找过程中所进行的比较次数。 </p>
<p>理想的情况是能直接找到需要的记录，因此必须在记录的存储位置和它的关键字之间建立一个确定的对应关系f，使每个关键字和结构中一个唯一的存储位置相对应。</p>
<p>哈希表最常见的例子是<font color=#ff00cc>以学生学号为关键字</font>的成绩表，１号学生的记录位置在第一条，１０号学生的记录位置在第１０条...</p>
<p>如果我们以学生姓名为关键字，如何建立查找表，使得根据姓名可以直接找到相应记录呢？</p>
<table cellSpacing=0 width="75%" border=1>
    <tbody>
        <tr>
            <td>a</td>
            <td>b</td>
            <td>c</td>
            <td>d</td>
            <td>e</td>
            <td>f</td>
            <td>g</td>
            <td>h</td>
            <td>i</td>
            <td>j</td>
            <td>k</td>
            <td>l</td>
            <td>m</td>
            <td>n</td>
            <td>o</td>
            <td>p</td>
            <td>q</td>
            <td>r</td>
            <td>s</td>
            <td>t</td>
            <td>u</td>
            <td>v</td>
            <td>w</td>
            <td>x</td>
            <td>y</td>
            <td>z</td>
        </tr>
        <tr>
            <td>1</td>
            <td>2</td>
            <td>3</td>
            <td>4</td>
            <td>5</td>
            <td>6</td>
            <td>7</td>
            <td>8</td>
            <td>9</td>
            <td>10</td>
            <td>11</td>
            <td>12</td>
            <td>13</td>
            <td>14</td>
            <td>15</td>
            <td>16</td>
            <td>17</td>
            <td>18</td>
            <td>19</td>
            <td>20</td>
            <td>21</td>
            <td>22</td>
            <td>23</td>
            <td>24</td>
            <td>25</td>
            <td>26</td>
        </tr>
    </tbody>
</table>
<br>
<table cellSpacing=0 width="90%" border=1>
    <tbody>
        <tr>
            <td width="31%" height=21>&nbsp;</td>
            <td width="11%" height=21>刘丽</td>
            <td width="13%" height=21>刘宏英</td>
            <td width="12%" height=21>吴军</td>
            <td width="11%" height=21>吴小艳</td>
            <td width="12%" height=21>李秋梅</td>
            <td width="10%" height=21>陈伟</td>
            <td width="10%" height=21>...</td>
        </tr>
        <tr>
            <td width="31%">姓名中各字拼音首字母</td>
            <td width="11%">ll</td>
            <td width="13%">lhy</td>
            <td width="12%">wj</td>
            <td width="11%">wxy</td>
            <td width="12%">lqm</td>
            <td width="10%">cw</td>
            <td width="10%">...</td>
        </tr>
        <tr>
            <td width="31%">用所有首字母编号值相加求和</td>
            <td width="11%">24</td>
            <td width="13%">46</td>
            <td width="12%">33</td>
            <td width="11%">72</td>
            <td width="12%">42</td>
            <td width="10%">26</td>
            <td width="10%">...</td>
        </tr>
        <tr>
            <td colSpan=8>
            <p>最小值可能为3 最大值可能为78 可放75个学生</p>
            </td>
        </tr>
    </tbody>
</table>
<p>用上述得到的数值作为对应记录在表中的位置，得到下表：<br></p>
<table cellSpacing=0 width="75%" border=1>
    <tbody>
        <tr bgColor=#ffffff>
            <td width="8%">&nbsp;</td>
            <td width="15%">&nbsp;</td>
            <td width="13%">成绩一</td>
            <td width="64%">成绩二...</td>
        </tr>
        <tr bgColor=#ccffcc>
            <td width="8%">3</td>
            <td width="15%">...</td>
            <td width="13%">&nbsp;</td>
            <td width="64%">&nbsp;</td>
        </tr>
        <tr bgColor=#ccffcc>
            <td width="8%"><font color=#ffccff>...</font></td>
            <td width="15%"><font color=#ffccff>...</font></td>
            <td width="13%">&nbsp;</td>
            <td width="64%"><font color=#ffccff></font></td>
        </tr>
        <tr>
            <td width="8%" bgColor=#ffcccc>24</td>
            <td width="15%">刘丽</td>
            <td width="13%">82</td>
            <td width="64%">95</td>
        </tr>
        <tr bgColor=#ccffcc>
            <td width="8%">25</td>
            <td width="15%">...</td>
            <td width="13%">&nbsp;</td>
            <td width="64%">&nbsp;</td>
        </tr>
        <tr>
            <td width="8%" bgColor=#ffcccc>26</td>
            <td width="15%">陈伟</td>
            <td width="13%">&nbsp;</td>
            <td width="64%">&nbsp;</td>
        </tr>
        <tr bgColor=#ccffcc>
            <td width="8%">...</td>
            <td width="15%">...</td>
            <td width="13%">&nbsp;</td>
            <td width="64%">&nbsp;</td>
        </tr>
        <tr>
            <td width="8%" bgColor=#ffcccc>33</td>
            <td width="15%">吴军</td>
            <td width="13%">&nbsp;</td>
            <td width="64%">&nbsp;</td>
        </tr>
        <tr bgColor=#ccffcc>
            <td width="8%">...</td>
            <td width="15%">...</td>
            <td width="13%">&nbsp;</td>
            <td width="64%">&nbsp;</td>
        </tr>
        <tr>
            <td width="8%" bgColor=#ffcccc>42</td>
            <td width="15%">李秋梅</td>
            <td width="13%">&nbsp;</td>
            <td width="64%">&nbsp;</td>
        </tr>
        <tr bgColor=#ccffcc>
            <td width="8%">...</td>
            <td width="15%">...</td>
            <td width="13%">&nbsp;</td>
            <td width="64%">&nbsp;</td>
        </tr>
        <tr>
            <td width="8%" bgColor=#ffcccc>46</td>
            <td width="15%">刘宏英</td>
            <td width="13%">&nbsp;</td>
            <td width="64%">&nbsp;</td>
        </tr>
        <tr bgColor=#ccffcc>
            <td width="8%">...</td>
            <td width="15%">...</td>
            <td width="13%">&nbsp;</td>
            <td width="64%">&nbsp;</td>
        </tr>
        <tr>
            <td width="8%" bgColor=#ffcccc>72</td>
            <td width="15%">吴小艳</td>
            <td width="13%">&nbsp;</td>
            <td width="64%">&nbsp;</td>
        </tr>
        <tr bgColor=#ccffcc>
            <td width="8%">...</td>
            <td width="15%">...</td>
            <td width="13%">&nbsp;</td>
            <td width="64%">&nbsp;</td>
        </tr>
        <tr bgColor=#ccffcc>
            <td width="8%">78</td>
            <td width="15%">...</td>
            <td width="13%">&nbsp;</td>
            <td width="64%">&nbsp;</td>
        </tr>
    </tbody>
</table>
<p>上面这张表即<font color=#ff3333>哈希表</font>。</p>
<p>如果将来要查李秋梅的成绩，可以用上述方法求出该记录所在位置：</p>
<p>李秋梅:lqm 12+17+13=42 取表中第42条记录即可。</p>
<p>问题：如果两个同学分别叫 刘丽 刘兰 该如何处理这两条记录？</p>
<p>这个问题是哈希表不可避免的，即<font color=#ff0033>冲突</font>现象：对不同的关键字可能得到同一哈希地址。</p>
</blockquote>
<p>二、哈希表的构造方法</p>
<blockquote>
<p>１、直接定址法</p>
<blockquote>
<p>例如：有一个从1到100岁的人口数字统计表，其中，年龄作为关键字，哈希<a class=channel_keylink href="http://www.bc-cn.net/Article/Search.asp?Field=Title&amp;ClassID=&amp;keyword=%BA%AF%CA%FD">函数</a>取关键字自身。</p>
<table cellSpacing=0 width="75%" border=1>
    <tbody>
        <tr>
            <td>地址</td>
            <td>01</td>
            <td>02</td>
            <td>...</td>
            <td>25</td>
            <td>26</td>
            <td>27</td>
            <td>...</td>
            <td>100</td>
        </tr>
        <tr>
            <td>年龄</td>
            <td>1</td>
            <td>2</td>
            <td>...</td>
            <td>25</td>
            <td>26</td>
            <td>27</td>
            <td>...</td>
            <td>...</td>
        </tr>
        <tr>
            <td>人数</td>
            <td>3000</td>
            <td>2000</td>
            <td>...</td>
            <td>1050</td>
            <td>...</td>
            <td>...</td>
            <td>...</td>
            <td>...</td>
        </tr>
        <tr>
            <td>...</td>
            <td>&nbsp;</td>
            <td>&nbsp;</td>
            <td>&nbsp;</td>
            <td>&nbsp;</td>
            <td>&nbsp;</td>
            <td>&nbsp;</td>
            <td>&nbsp;</td>
            <td>&nbsp;</td>
        </tr>
    </tbody>
</table>
</blockquote>
<p>２、数字分析法</p>
<blockquote>
<p>有学生的生日数据如下：</p>
<p>年.月.日</p>
<p>75.10.03<br>75.11.23<br>76.03.02<br>76.07.12<br>75.04.21<br>76.02.15<br>...</p>
<p>经分析,第一位，第二位，第三位重复的可能性大，取这三位造成冲突的机会增加，所以尽量不取前三位，取后三位比较好。</p>
</blockquote>
<p>３、平方取中法</p>
<blockquote>
<p>取关键字平方后的中间几位为哈希地址。</p>
</blockquote>
<p>４、折叠法</p>
<blockquote>
<p>将关键字分割成位数相同的几部分（最后一部分的位数可以不同），然后取这几部分的叠加和（舍去进位）作为哈希地址，这方法称为折叠法。</p>
<p>例如：每一种西文图书都有一个国际标准图书编号，它是一个10位的十进制数字，若要以它作关键字建立一个哈希表，当馆藏书种类不到10,000时，可采用此法构造一个四位数的哈希<a class=channel_keylink href="http://www.bc-cn.net/Article/Search.asp?Field=Title&amp;ClassID=&amp;keyword=%BA%AF%CA%FD">函数</a>。如果一本书的编号为0-442-20586-4,则：</p>
<table cellSpacing=0 width="75%" border=0>
    <tbody>
        <tr>
            <td width="18%">
            <div align=right></div>
            </td>
            <td width="26%">
            <div align=right>5864</div>
            </td>
            <td width="27%">
            <div align=right></div>
            </td>
            <td width="29%">
            <div align=right>5864</div>
            </td>
        </tr>
        <tr>
            <td width="18%">
            <div align=right></div>
            </td>
            <td width="26%">
            <div align=right>4220</div>
            </td>
            <td width="27%">
            <div align=right></div>
            </td>
            <td width="29%">
            <div align=right>0224</div>
            </td>
        </tr>
        <tr>
            <td width="18%">
            <div align=right>+)</div>
            </td>
            <td width="26%">
            <div align=right>04</div>
            </td>
            <td width="27%">
            <div align=right>+)</div>
            </td>
            <td width="29%">
            <div align=right>04</div>
            </td>
        </tr>
        <tr>
            <td width="18%">
            <div align=right></div>
            </td>
            <td width="26%">
            <div align=right>-----------</div>
            </td>
            <td width="27%">
            <div align=right></div>
            </td>
            <td width="29%">
            <div align=right>-----------</div>
            </td>
        </tr>
        <tr>
            <td width="18%">
            <div align=right></div>
            </td>
            <td width="26%">
            <div align=right>10088</div>
            </td>
            <td width="27%">
            <div align=right></div>
            </td>
            <td width="29%">
            <div align=right>6092</div>
            </td>
        </tr>
        <tr>
            <td width="18%">
            <div align=right></div>
            </td>
            <td width="26%">
            <div align=right>H(key)=0088</div>
            </td>
            <td width="27%">
            <div align=right></div>
            </td>
            <td width="29%">
            <div align=right>H(key)=6092</div>
            </td>
        </tr>
        <tr>
            <td width="18%">&nbsp;</td>
            <td width="26%">&nbsp;</td>
            <td width="27%">&nbsp;</td>
            <td width="29%">&nbsp;</td>
        </tr>
        <tr>
            <td width="18%">
            <div align=right></div>
            </td>
            <td width="26%">
            <div align=right>(a)移位叠加</div>
            </td>
            <td width="27%">
            <div align=right></div>
            </td>
            <td width="29%">
            <div align=right>(b)间界叠加</div>
            </td>
        </tr>
    </tbody>
</table>
</blockquote>
<p>５、除留余数法</p>
<blockquote>
<p>取关键字被某个不大于哈希表表长m的数p除后所得余数为哈希地址。</p>
<p>H(key)=key MOD p (p&lt;=m)</p>
</blockquote>
<p>６、随机数法</p>
<blockquote>
<p>选择一个随机函数，取关键字的随机<a class=channel_keylink href="http://www.bc-cn.net/Article/Search.asp?Field=Title&amp;ClassID=&amp;keyword=%BA%AF%CA%FD">函数</a>值为它的哈希地址，即</p>
<p>H(key)=random(key) ,其中random为随机<a class=channel_keylink href="http://www.bc-cn.net/Article/Search.asp?Field=Title&amp;ClassID=&amp;keyword=%BA%AF%CA%FD">函数</a>。通常用于关键字长度不等时采用此法。</p>
</blockquote></blockquote>
<p>三、总结</p>
<blockquote>
<p>哈希表的优缺点</p>
</blockquote>
<p>四、作业</p>
<blockquote>
<p>&nbsp;</p>
<p>预习如何处理冲突及哈希表的查找。</p>
</blockquote>
<p>&nbsp;<a href="http://www.bc-cn.net/Article/kfyy/sjjg/200411/261.html">http://www.bc-cn.net/Article/kfyy/sjjg/200411/261.html</a></p>
&nbsp;哈希表（二）<br>
<p><strong><em>教学目的：</em></strong> 掌握哈希表处理冲突的方法及哈希表的查找算法</p>
<p><strong><em>教学重点：</em></strong> 哈希表处理冲突的方法</p>
<p><strong><em>教学难点：</em></strong> 开放定址法</p>
<p><strong><em>授课内容：</em></strong></p>
<p>一、复习上次课内容</p>
<blockquote>
<p>什么是哈希表？如何构造哈希表？</p>
<p>提出问题：如何处理冲突？</p>
</blockquote>
<p>二、处理冲突的方法</p>
<blockquote>
<table cellSpacing=0 width="75%" border=1>
    <tbody>
        <tr bgColor=#ffffff>
            <td width="8%">&nbsp;</td>
            <td width="15%">&nbsp;</td>
            <td width="13%">成绩一</td>
            <td width="64%">成绩二...</td>
        </tr>
        <tr bgColor=#ccffcc>
            <td width="8%">3</td>
            <td width="15%">...</td>
            <td width="13%">&nbsp;</td>
            <td width="64%">&nbsp;</td>
        </tr>
        <tr bgColor=#ccffcc>
            <td width="8%"><font color=#ffccff>...</font></td>
            <td width="15%"><font color=#ffccff>...</font></td>
            <td width="13%">&nbsp;</td>
            <td width="64%"><font color=#ffccff></font></td>
        </tr>
        <tr>
            <td width="8%" bgColor=#ffcccc>24</td>
            <td width="15%">刘丽</td>
            <td width="13%">82</td>
            <td width="64%">95</td>
        </tr>
        <tr bgColor=#ccffcc>
            <td width="8%">25</td>
            <td width="15%">...</td>
            <td width="13%">&nbsp;</td>
            <td width="64%">&nbsp;</td>
        </tr>
        <tr>
            <td width="8%" bgColor=#ffcccc>26</td>
            <td width="15%">陈伟</td>
            <td width="13%">&nbsp;</td>
            <td width="64%">&nbsp;</td>
        </tr>
        <tr bgColor=#ccffcc>
            <td width="8%">...</td>
            <td width="15%">...</td>
            <td width="13%">&nbsp;</td>
            <td width="64%">&nbsp;</td>
        </tr>
        <tr>
            <td width="8%" bgColor=#ffcccc>33</td>
            <td width="15%">吴军</td>
            <td width="13%">&nbsp;</td>
            <td width="64%">&nbsp;</td>
        </tr>
        <tr bgColor=#ccffcc>
            <td width="8%">...</td>
            <td width="15%">...</td>
            <td width="13%">&nbsp;</td>
            <td width="64%">&nbsp;</td>
        </tr>
        <tr>
            <td width="8%" bgColor=#ffcccc>42</td>
            <td width="15%">李秋梅</td>
            <td width="13%">&nbsp;</td>
            <td width="64%">&nbsp;</td>
        </tr>
        <tr bgColor=#ccffcc>
            <td width="8%">...</td>
            <td width="15%">...</td>
            <td width="13%">&nbsp;</td>
            <td width="64%">&nbsp;</td>
        </tr>
        <tr>
            <td width="8%" bgColor=#ffcccc>46</td>
            <td width="15%">刘宏英</td>
            <td width="13%">&nbsp;</td>
            <td width="64%">&nbsp;</td>
        </tr>
        <tr bgColor=#ccffcc>
            <td width="8%">...</td>
            <td width="15%">...</td>
            <td width="13%">&nbsp;</td>
            <td width="64%">&nbsp;</td>
        </tr>
        <tr>
            <td width="8%" bgColor=#ffcccc>72</td>
            <td width="15%">吴小艳</td>
            <td width="13%">&nbsp;</td>
            <td width="64%">&nbsp;</td>
        </tr>
        <tr bgColor=#ccffcc>
            <td width="8%">...</td>
            <td width="15%">...</td>
            <td width="13%">&nbsp;</td>
            <td width="64%">&nbsp;</td>
        </tr>
        <tr bgColor=#ccffcc>
            <td width="8%">78</td>
            <td width="15%">...</td>
            <td width="13%">&nbsp;</td>
            <td width="64%">&nbsp;</td>
        </tr>
    </tbody>
</table>
<p>如果两个同学分别叫 刘丽 刘兰，当加入刘兰时，地址24发生了冲突，我们可以以某种规律使用其它的存储位置，如果选择的一个其它位置仍有冲突，则再选下一个，直到找到没有冲突的位置。选择其它位置的方法有：</p>
<p>１、开放定址法</p>
<blockquote>
<p>Hi=(H(key)+di) MOD m i=1,2,...,k(k&lt;=m-1)</p>
<p>其中m为表长，di为增量序列</p>
<p>如果di值可能为1,2,3,...m-1，称<font color=#ff0033>线性探测再散列</font>。</p>
<p>如果di取值可能为1,-1,2,-2,4,-4,9,-9,16,-16,...k*k,-k*k(k&lt;=m/2)</p>
<p>称<font color=#ff0033>二次探测再散列</font>。</p>
<p>如果di取值可能为<font color=#ff0033>伪随机数列</font>。称<font color=#ff0033>伪随机探测再散列</font>。</p>
<p>例：在长度为11的哈希表中已填有关键字分别为17,60,29的记录，现有第四个记录，其关键字为38，由哈希<a class=channel_keylink href="http://www.bc-cn.net/Article/Search.asp?Field=Title&amp;ClassID=&amp;keyword=%BA%AF%CA%FD">函数</a>得到地址为5，若用线性探测再散列，如下：</p>
<div align=center>
<table cellSpacing=0 width="75%" border=1>
    <tbody>
        <tr>
            <td>0</td>
            <td>1</td>
            <td>2</td>
            <td>3</td>
            <td>4</td>
            <td>5</td>
            <td>6</td>
            <td>7</td>
            <td>8</td>
            <td>9</td>
            <td>10</td>
        </tr>
        <tr bgColor=#ffcccc>
            <td>&nbsp;</td>
            <td>&nbsp;</td>
            <td>&nbsp;</td>
            <td>&nbsp;</td>
            <td>&nbsp;</td>
            <td>60</td>
            <td>17</td>
            <td>29</td>
            <td>&nbsp;</td>
            <td>&nbsp;</td>
            <td>&nbsp;</td>
        </tr>
    </tbody>
</table>
</div>
<p align=center>(a)插入前</p>
<div align=center>
<table cellSpacing=0 width="75%" border=1>
    <tbody>
        <tr>
            <td>0</td>
            <td>1</td>
            <td>2</td>
            <td>3</td>
            <td>4</td>
            <td>5</td>
            <td>6</td>
            <td>7</td>
            <td>8</td>
            <td>9</td>
            <td>10</td>
        </tr>
        <tr bgColor=#ffcccc>
            <td>&nbsp;</td>
            <td>&nbsp;</td>
            <td>&nbsp;</td>
            <td>&nbsp;</td>
            <td>&nbsp;</td>
            <td>60</td>
            <td>17</td>
            <td>29</td>
            <td>38</td>
            <td>&nbsp;</td>
            <td>&nbsp;</td>
        </tr>
    </tbody>
</table>
</div>
<p align=center>(b)线性探测再散列</p>
<div align=center>
<table cellSpacing=0 width="75%" border=1>
    <tbody>
        <tr>
            <td>0</td>
            <td>1</td>
            <td>2</td>
            <td>3</td>
            <td>4</td>
            <td>5</td>
            <td>6</td>
            <td>7</td>
            <td>8</td>
            <td>9</td>
            <td>10</td>
        </tr>
        <tr bgColor=#ffcccc>
            <td>&nbsp;</td>
            <td>&nbsp;</td>
            <td>&nbsp;</td>
            <td>&nbsp;</td>
            <td>&nbsp;</td>
            <td>60</td>
            <td>17</td>
            <td>29</td>
            <td>&nbsp;</td>
            <td>&nbsp;</td>
            <td>&nbsp;</td>
        </tr>
    </tbody>
</table>
</div>
<p align=center>(c)二次探测再散列</p>
<div align=center>
<table cellSpacing=0 width="75%" border=1>
    <tbody>
        <tr>
            <td>0</td>
            <td>1</td>
            <td>2</td>
            <td>3</td>
            <td>4</td>
            <td>5</td>
            <td>6</td>
            <td>7</td>
            <td>8</td>
            <td>9</td>
            <td>10</td>
        </tr>
        <tr bgColor=#ffcccc>
            <td>&nbsp;</td>
            <td>&nbsp;</td>
            <td>&nbsp;</td>
            <td>38</td>
            <td>&nbsp;</td>
            <td>60</td>
            <td>17</td>
            <td>29</td>
            <td>&nbsp;</td>
            <td>&nbsp;</td>
            <td>&nbsp;</td>
        </tr>
    </tbody>
</table>
</div>
<p align=center>(d)伪随机探测再散列</p>
<p align=center>伪随机数列为9,5,3,8,1...</p>
</blockquote>
<p>２、再哈希法</p>
<blockquote>
<p>当发生冲突时，使用第二个、第三个、哈希<a class=channel_keylink href="http://www.bc-cn.net/Article/Search.asp?Field=Title&amp;ClassID=&amp;keyword=%BA%AF%CA%FD">函数</a>计算地址，直到无冲突时。缺点：计算时间增加。</p>
</blockquote>
<p>３、链地址法</p>
<blockquote>
<p>将所有关键字为同义词的记录存储在同一线性链表中。</p>
<p><img height=294 src="http://www.bc-cn.net/Article/UploadFDL05/200411/20041112073744336.jpg" width=314></p>
</blockquote>
<p>４、建立一个公共溢出区</p>
<blockquote>
<p>假设哈希<a class=channel_keylink href="http://www.bc-cn.net/Article/Search.asp?Field=Title&amp;ClassID=&amp;keyword=%BA%AF%CA%FD">函数</a>的值域为[0,m-1],则设向量HashTable[0..m-1]为基本表，另外设立存储空间向量OverTable[0..v]用以存储发生冲突的记录。</p>
</blockquote></blockquote>
<p>三、哈希表的查找</p>
<blockquote>
<p>//开放定址哈希表的存储结构</p>
<p>int hashsize[]={997,...};</p>
<p>typedef struct{</p>
<blockquote>
<p>ElemType *elem;</p>
<p>int count;</p>
<p>int sizeindex;</p>
</blockquote>
<p>}HashTable;</p>
<p>#define SUCCESS 1</p>
<p>#define UNSUCCESS 0</p>
<p>#define DUPLICATE -1</p>
<p>Status SearchHash(HashTable H,KeyType K,int &amp;p,int &amp;c){</p>
<blockquote>
<p>p=Hash(K);</p>
<p>while(H.elem[p].key!=NULLKEY &amp;&amp; !EQ(K,H.elem[p].key))</p>
<blockquote>
<p>collision(p,++c);</p>
</blockquote>
<p>if(EQ(K,H.elem[p].key)</p>
<blockquote>
<p>return SUCCESS;</p>
</blockquote>
<p>else return UNSUCCESS;</p>
</blockquote>
<p>}</p>
<p>Status InsertHash(HashTable &amp;H,EleType e){</p>
<blockquote>
<p>c=0;</p>
<p>if(SearchHash(H,e.key,p,c))</p>
<blockquote>
<p>return DUPLICATE;</p>
</blockquote>
<p>else if(c&lt;hashsize[H.sizeindex]/2){</p>
<blockquote>
<p>H.elem[p]=e; ++H.count; return OK;</p>
<p>}</p>
</blockquote>
<p>else RecreateHashTable(H);</p>
</blockquote>
<p>}</p>
</blockquote>
<p>四、总结</p>
<blockquote>
<p>处理冲突的要求是什么？</p>
</blockquote>
<img src ="http://www.blogjava.net/firtre/aggbug/126875.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/firtre/" target="_blank">笨蛋</a> 2007-06-28 17:41 <a href="http://www.blogjava.net/firtre/articles/126875.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>类图 ——介绍了类图基本知识以及对应的UML图画法</title><link>http://www.blogjava.net/firtre/articles/126806.html</link><dc:creator>笨蛋</dc:creator><author>笨蛋</author><pubDate>Thu, 28 Jun 2007 05:29:00 GMT</pubDate><guid>http://www.blogjava.net/firtre/articles/126806.html</guid><wfw:comment>http://www.blogjava.net/firtre/comments/126806.html</wfw:comment><comments>http://www.blogjava.net/firtre/articles/126806.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/firtre/comments/commentRss/126806.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/firtre/services/trackbacks/126806.html</trackback:ping><description><![CDATA[<p>摘自：<br><a href="http://www.itisedu.com/phrase/200603071659325.html">http://www.itisedu.com/phrase/200603071659325.html</a><br><font face=Verdana>&nbsp;</font><a href="http://www.itisedu.com/phrase/200603071659325.html" target=_new><u><font face=Verdana color=#800080>类图</font></u></a><font face=Verdana>(</font><a href="http://www.itisedu.com/phrase/200604241343565.html" target=_new><u><font face=Verdana color=#0000ff>Class diagram</font></u></a><font face=Verdana>)是显示了模型的静态结构，特别是模型中存在的</font><a href="http://www.itisedu.com/phrase/200603090857555.html" target=_new><u><font face=Verdana color=#0000ff>类</font></u></a><font face=Verdana>、类的内部结构以及它们与其他类的关系等。类图不显示暂时性信息。</font></p>
<p><font face=Verdana>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 类图(</font><a href="http://www.itisedu.com/phrase/200604231359565.html" target=_new><font face=Verdana color=#0000ff><u>Class</u></font></a><font face=Verdana> diagram)由许多（静态）说明性的模型元素（例如类、包和它们之间的关系，这些元素和它们的内容互相连接）组成。类图可以组织在（并且属于）包中，仅显示特定包中的相关内容。</font></p>
<p><font face=Verdana>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 类图(Class diagram)是最常用的<a href="http://www.itisedu.com/phrase/200602271429302.html" target=_new><u><font color=#0000ff>UML</font></u></a>图，显示出类、接口以及它们之间的静态结构和关系；它用于描述系统的结构化设计。</font></p>
<p><font face=Verdana>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 类图(Class diagram)最基本的元素是类或者接口。</font></p>
<p><font face=Verdana><strong>类图通常包含如下的内容</strong></font></p>
<p><font face=Verdana>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 类<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 接口<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 协作<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 关系</font></p>
<p><font face=Verdana>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 同其他的图一样，类图也可以包含注解和限制。</font></p>
<p><font face=Verdana>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 类图中也可以包含包和<a href="http://www.itisedu.com/phrase/200604161433025.html" target=_new><u><font color=#0000ff>子系统</font></u></a>，这两者用来将元素分组。有时后你也可以将类的实例放到类图中。</font></p>
<p><font face=Verdana>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 注：<a href="http://www.itisedu.com/phrase/200604161810285.html" target=_new><u><font color=#0000ff>组件图</font></u></a>和分布图和类图类似，虽然他们不包含类而是分别包含<a href="http://www.itisedu.com/phrase/200603302222545.html" target=_new><u><font color=#0000ff>组件</font></u></a>和节点。</font></p>
<font face=Verdana>
<p><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 你通常通过下面三种方式使用类图：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1，为系统词汇建模型<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 为系统的词汇建模实际上是从词汇表中发现类，发现它的责任。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2，模型化简单的协作<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 协作是指一些类、接口和其他的元素一起工作提供一些合作的行为，这些行为不是简单地将元素加能得到的。例如：当你为一个分布式的系统中的事务处理过程建模型时，你不可能只通过一个类来明白事务是怎样进行的，事实上这个过程的执行涉及到一系列的类的协同工作。使用类图来可视化这些类和他们的关系。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3，模型化一个逻辑<a href="http://www.itisedu.com/phrase/200602271218062.html" target=_new><u><font color=#0000ff>数据库</font></u></a><a href="http://www.itisedu.com/phrase/200603061709535.html" target=_new><u><font color=#0000ff>模式</font></u></a><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 想象模式是概念上设计数据库的蓝图。在很多领域，你将想保存持久性数据到关系数据库活<a href="http://www.itisedu.com/phrase/200603101726185.html" target=_new><u><font color=#0000ff>面向对象</font></u></a>的数据库。你可以用类图为这些数据库模式建立模型。</p>
<p><br><strong>1. 类（Class）</strong> </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一般包含3个组成部分。第一个是类名；第二个是属性（attributes）；第三个是该类提供的方法（ 类的性质可以放在第四部分；如果类中含有内部类，则会出现第五个组成部分）。类名部分是不能省略的，其他组成部分可以省略。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 类名书写规范：正体字说明类是可被实例化的，斜体字说明类为抽象类。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 属性和方法书写规范：修饰符 [描述信息] 属性、方法名称 [参数] [：返回<a href="http://www.itisedu.com/phrase/200603051002565.html" target=_new><u><font color=#0000ff>类型</font></u></a>|类型]</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 属性和方法之前可附加的可见性修饰符：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 加号（+）表示public；减号（-）表示private；#号表示protected；省略这些修饰符表示具有package（包）级别的可见性。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果属性或方法具有下划线，则说明它是静态的。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 描述信息使用 &lt;&lt; 开头和使用 &gt;&gt; 结尾。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 类的性质是由一个属性、一个赋值方法和一个取值方法组成。书写方式和方法类似。</p>
<p><strong>2. 包（Package）</strong> </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 包是一种常规用途的组合机制。UML中的一个包直接对应于Java中的一个包。在Java中，一个包可能含有其他包、类或者同时含有这两者。进行建模时，通常使用逻辑性的包，用于对模型进行组织；使用物理性的包，用于转换成系统中的Java包。每个包的名称对这个包进行了惟一性的标识。</p>
<p><br><strong>3. 接口（Interface）</strong></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 接口是一系列操作的集合，它指定了一个类所提供的服务。它直接对应于Java中的一个接口类型。接口的表示有大概两种方式。具体画法见下例：</p>
<p><br><strong>4. 关系</strong></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 常见的关系有：一般化关系（Generalization），关联关系（Association），聚合关系（Aggregation），合成关系（Composition），依赖关系（Dependency）。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 其中，聚合关系（Aggregation），合成关系（Composition）属于关联关系（Association）。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一般关系表现为继承或实现关系(is a)，关联关系表现为变量(has a )，依赖关系表现为函数中的参数(use a)。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一般化关系：表示为类与类之间的继承关系，接口与接口之间的继承，类对接口的实现关系。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 表示方法： 用一个空心箭头＋实线，箭头指向父类。或空心箭头＋虚线，如果父类是接口。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 关联关系：类与类之间的联接，它使一个类知道另一个类的属性和方法。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 表示方法：用 实线＋箭头， 箭头指向被使用的类。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 聚合关系：是关联关系的一种，是强的关联关系。聚合关系是整体和个体的关系。关联关系的两个类处于同一层次上，啊聚合关系两个类处于不同的层次，一个是整体，一个是部分。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 表示方法：空心菱形＋实线＋箭头，箭头指向部分。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 合成关系：是关联关系的一种，是比聚合关系强的关系。它要求普通的聚合关系中代表整体的<a href="http://www.itisedu.com/phrase/200603090845215.html" target=_new><u><font color=#0000ff>对象</font></u></a>负责代表部分的对象的生命周期，合成关系不能共享。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 表示方法：实心菱形＋实线＋箭头，</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 依赖关系：是类与类之间的连接，表示一个类依赖于另一个类的定义。例如如果A依赖于B，则B体现为局部变量，方法的参数、或静态方法的调用。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 表示方法：虚线＋箭头</p>
<p><strong>通用建模技术</strong></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 没有类是单独存在的，他们通常和别的类协作，创造比单独工作更大的语义。因此，除了捕获系统的词汇以外，还要将注意力集中到这些类是如何在一起工作的。使用类图来表达这种协作。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; l 确定你建模的机制。机制代表了部分你建模的系统的一些功能和行为，这些功能和行为是一组类、接口和其他事物相互作用的结果。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; l 对于每个机制，确定类、接口和其他的参与这个协作的协作。同时确定这些事物之间的关系。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; l 用场景来预排这些事物，沿着这条路你将发现模型中忽略的部分和定义错误的部分。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; l 确定用这些事物的内容来填充它们。对于类，开始于获得一个责任（类的职责），然后，将它转化为具体的属性和方法。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 图7-1是一个自治<a href="http://www.itisedu.com/phrase/200603021227495.html" target=_new><u><font color=#0000ff>机器人</font></u></a>的类图。这张的图焦点聚集那些让机器人在路上行走的机制对应的类上。你可以发现一个虚类Motor和两个从它派生出来的类：SteeringMotor和MainMotor。这两个类都从它的父亲Motor继承了五个方法。这两个类又是另一个类Driver的一部分。类PathAgent和Driver有一个1对1的关系，和CollisionSensor有1对n的关系。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在这个系统中其实还有很多其他的类，但这张图的重点是放在那些将机器人移动的类上的。在其他的图中你可能也会看到这些类。通过将焦点放在不通的功能上，可以获得从不通的角度对整个系统的认识，最终达到认识整个系统。　</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 很多系统都是有持久性数据的，也就是说要将这些数据保存到数据库中以便下一次使用。通常你会使用关系型数据库或面向对象的数据库，或其它类型的数据库来保存数据。UML很适合为逻辑数据库模式建模。</p>
<p><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UML的类图是E-R图（为逻辑数据库建模的通用工具）的超集，尽管E-R图的重点是数据，类图的扩展允许模型化行为。在物理数据库中这些逻辑操作一半转化为触发器或存储过程。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; l 确定那些状态比其生命周期要长的类。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; l 创建一张包含这些类的图，标记它们为持久性的。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; l 详细定义它们的属性。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; l 对于使得物理<a href="http://www.itisedu.com/phrase/200603011123415.html" target=_new><u><font color=#0000ff>数据库设计</font></u></a>复杂的模式如：循环关系、1对1关系、N元关系，考虑创建中间抽象来使得逻辑结构复杂。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; l 详细定义这些类的操作，特别是那些访问数据和涉及数据完整性的方法。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; l 如果可能的话使用工具来将你的逻辑设计转化为物理设计。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 建模是重要的，但要记住的是对于开发组来说<a href="http://www.itisedu.com/phrase/200604232134205.html" target=_new><u><font color=#0000ff>软件</font></u></a>才是主要的产品，而不是图。当然，画图的主要目的是为了更好地理解系统，预测什么时候可以提供什么样的软件来满足用户的需要。基于这个理由，让你画的图对开发有指导意义是很重要的。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 某些时候，使用UML。你的模型并不能直接映射成为代码。例如，如果你在使用<a href="http://www.itisedu.com/phrase/200603101530375.html" target=_new><u><font color=#0000ff>活动图</font></u></a>为一个商业过程建模，很多活动实际上涉及人而不是<a href="http://www.itisedu.com/phrase/200603021438435.html" target=_new><u><font color=#0000ff>计算机</font></u></a>。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 很多时候，你创建的图形可以被映射成为代码。UML并不是专门为面向对象的语言设计的，它支持多种语言，但使用面向对象的语言会更直观些，特别是类图的映射，它的内容可以直接映射成为<a href="http://www.itisedu.com/phrase/200603010948085.html" target=_new><u><font color=#0000ff>面向对象语言</font></u></a>的内容。如：C＋＋，SMALLTALK、ADA、ObjectPascal、Eiffel和Forte。UML还支持如Visual Basic这样的面向对象的语言。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 正向工程：是从图到代码的过程。通过对某中特定语言的映射可以从UML的图得到该语言的代码。正向工程会丢失信息，这是因为UML比任何一种<a href="http://www.itisedu.com/phrase/200604232224305.html" target=_new><u><font color=#0000ff>程序</font></u></a>语言的语义都丰富。这也正是为什么你需要UML模型的原因。结构特性、协作、交互等可以通过UML直观地表达出来，使用代码就不是那么明显了。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 对类图的正向工程：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; l 选择将图形映射到哪一种程序语言。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; l 根据你选择的语言的语义，你可能要对使用某写UML的特性加以限制。例如：UML允许你使用多重继承，而SmallTalk只允许一重继承。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; l 使用标记值来指定比的目的语言。你可以在类级进行也可以在协作或包的层次上进行。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; l 使用工具来对你的模型进行正向工程。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 反向工程：反向工程是从代码到模型的过程。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 进行反向工程：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; l 确定将你的程序语言的代码反向成模型的规则。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; l 使用工具（Rose C++ Analyzer）进行反向工程。</p>
<p><strong>提示和技巧</strong></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一个结构化好的类图：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; l 焦点放在系统静态<a href="http://www.itisedu.com/phrase/200604241330575.html" target=_new><u><font color=#0000ff>设计视图</font></u></a>的一个方面。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; l 只包含为了理解该方面而应该存在的元素。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; l 提供足够的信息来理解该图。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; l 不让读者产生错误的信息。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当你画类图的时候：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; l 给它起一个名字，这个名字能表达类图的用途。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; l 用最少的交叉线来组织它的元素。 <br></p>
</font>
<img src ="http://www.blogjava.net/firtre/aggbug/126806.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/firtre/" target="_blank">笨蛋</a> 2007-06-28 13:29 <a href="http://www.blogjava.net/firtre/articles/126806.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java多线程编程_基础</title><link>http://www.blogjava.net/firtre/articles/126622.html</link><dc:creator>笨蛋</dc:creator><author>笨蛋</author><pubDate>Wed, 27 Jun 2007 08:30:00 GMT</pubDate><guid>http://www.blogjava.net/firtre/articles/126622.html</guid><wfw:comment>http://www.blogjava.net/firtre/comments/126622.html</wfw:comment><comments>http://www.blogjava.net/firtre/articles/126622.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/firtre/comments/commentRss/126622.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/firtre/services/trackbacks/126622.html</trackback:ping><description><![CDATA[run(),start(),wait(),notify(),notifyAll(),sleep(),yield(),join() <br><br>start() 用于自动调用run();这是JAVA 的内在机制规定的。并且run() <br>的访问控制符必须是public，返回值必须是void（这种说法不准确，run()没有返回值），run() <br>不带参数。<br>join() :跟在start()方法后面可以保证调用start()方法的线程运行结束才继续执行join()以下的代码。<br>yield()方法与sleep()方法相似，只是它不能由用户指定线程暂停多长时间。按照SUN 的<br>说法：sleep 方法可以使低优先级的线程得到执行的机会，当然也可以让同优先级和高优先级的线程有执行的机会。而yield()方法只能使同优先级的线程有执行的机会。<br><br>wait()方法（无参数）：线程等待到notify()通知后才继续执行以后的代码；若有参数而其它线程在参数限定时间内就完成了，可以提前唤醒本线程。<br><br>以下部分摘自：<a href="http://www.blogjava.net/cheneyfree/archive/2007/05/24/119625.html">http://www.blogjava.net/cheneyfree/archive/2007/05/24/119625.html</a><br>编写具有多线程能力的程序经常会用到的方法有： <br>run(),start(),wait(),notify(),notifyAll(),sleep(),yield(),join() <br>还有一个重要的关键字：synchronized <br>本文将对以上内容进行讲解。
<p><br>一：run()和start() <br>示例1： <br>public class ThreadTest extends Thread <br>{ <br>public void run() <br>{ <br>for(int i=0;i&lt;10;i++) <br>{ <br>System.out.print(" " + i); <br>} <br>} <br>public static void main(String[] args) <br>{ <br>new ThreadTest().start(); <br>new ThreadTest().start(); <br>} <br>} <br>这是个简单的多线程程序。run()和start()是大家都很熟悉的两个方法。把希望并行处理的<br>代码都放在run()中；stat()用于自动调用run()，这是JAVA 的内在机制规定的。并且run() <br>的访问控制符必须是public，返回值必须是void（这种说法不准确，run()没有返回值），run() <br>不带参数。<br>这些规定想必大家都早已知道了，但你是否清楚为什么run 方法必须声明成这样的形式？这涉<br>及到JAVA 的方法覆盖和重载的规定。这些内容很重要，请读者参考相关资料。</p>
<p><br>二：关键字synchronized <br>有了synchronized 关键字，多线程程序的运行结果将变得可以控制。synchronized 关键<br>字用于保护共享数据。请大家注意"共享数据"，你一定要分清哪些数据是共享数据，JAVA 是面向<br>对象的程序设计语言，所以初学者在编写多线程程序时，容易分不清哪些数据是共享数据。请看下<br>面的例子： <br>示例2： <br>public class ThreadTest implements Runnable <br>{ public synchronized void run() <br>{ <br>for(int i=0;i&lt;10;i++) <br>{ <br>System.out.print(" " + i); <br>} <br>} <br>public static void main(String[] args) <br>{ <br>Runnable r1 = new ThreadTest(); <br>Runnable r2 = new ThreadTest(); <br>Thread t1 = new Thread(r1); <br>Thread t2 = new Thread(r2); <br>t1.start(); <br>t2.start(); <br>} <br>} <br>在这个程序中，run()被加上了synchronized 关键字。在main 方法中创建了两个线程。你<br>可能会认为此程序的运行结果一定为：0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9。但你<br>错了！这个程序中synchronized 关键字保护的不是共享数据（其实在这个程序中synchronized <br>关键字没有起到任何作用，此程序的运行结果是不可预先确定的）。这个程序中的t1,t2 是两个&nbsp;&nbsp; 对象（r1,r2）的线程。JAVA <br>是面向对象的程序设计语言，不同的对象的数据是不同的，r1,r2 有<br>各自的run()方法，而synchronized 使同一个对象的多个线程，在某个时刻只有其中的一个线程<br>可以访问这个对象的synchronized 数据。每个对象都有一个"锁标志"，当这个对象的一个线程<br>访问这个对象的某个synchronized 数据时，这个对象的所有被synchronized 修饰的数据将被<br>上锁（因为"锁标志"被当前线程拿走了），只有当前线程访问完它要访问的synchronized 数据<br>时，当前线程才会释放"锁标志"，这样同一个对象的其它线程才有机会访问synchronized 数据。<br>示例3： <br>public class ThreadTest implements Runnable <br>{ <br>public synchronized void run() <br>{ <br>for(int i=0;i&lt;10;i++) <br>{ <br>System.out.print(" " + i); <br>} <br>} <br>public static void main(String[] args) <br>{ <br>Runnable r = new ThreadTest(); <br>Thread t1 = new Thread(r); <br>Thread t2 = new Thread(r); <br>t1.start(); t2.start(); <br>} <br>} <br>如果你运行1000 次这个程序，它的输出结果也一定每次都是：0 1 2 3 4 5 6 7 8 9 0 1 <br>2 3 4 5 6 7 8 9。因为这里的synchronized 保护的是共享数据。t1,t2 是同一个对象（r） <br>的两个线程，当其中的一个线程（例如：t1）开始执行run()方法时，由于run()受synchronized <br>保护，所以同一个对象的其他线程（t2）无法访问synchronized 方法（run 方法）。只有当t1 <br>执行完后t2 才有机会执行。<br>示例4： <br>public class ThreadTest implements Runnable <br>{ <br>public void run() <br>{ <br>synchronized(this) <br>{ <br>for(int i=0;i&lt;10;i++) <br>{ <br>System.out.print(" " + i); <br>} <br>} <br>} <br>public static void main(String[] args) <br>{ <br>Runnable r = new ThreadTest(); <br>Thread t1 = new Thread(r); <br>Thread t2 = new Thread(r); <br>t1.start(); <br>t2.start(); <br>} <br>} <br>这个程序与示例3 的运行结果一样。在可能的情况下，应该把保护范围缩到最小，可以用示例<br>4 的形式，this 代表"这个对象"。没有必要把整个run()保护起来，run()中的代码只有一个for 循环，所以只要保护for 循环就可以了。<br>示例5： <br>public class ThreadTest implements Runnable <br>{ <br>public void run() <br>{ <br>for(int k=0;k&lt;5;k++) <br>{ <br>System.out.println(Thread.currentThread().getName() <br>+ " : for loop : " + k); } <br>synchronized(this) <br>{ <br>for(int k=0;k&lt;5;k++) <br>{ <br>System.out.println(Thread.currentThread().getName() <br>+ " : synchronized for loop : " + k); <br>} <br>} <br>} <br>public static void main(String[] args) <br>{ <br>Runnable r = new ThreadTest(); <br>Thread t1 = new Thread(r,"t1_name"); <br>Thread t2 = new Thread(r,"t2_name"); <br>t1.start(); <br>t2.start(); <br>} <br>} <br>运行结果： <br>t1_name : for loop : 0 <br>t1_name : for loop : 1 <br>t1_name : for loop : 2 <br>t2_name : for loop : 0 <br>t1_name : for loop : 3 <br>t2_name : for loop : 1 <br>t1_name : for loop : 4 <br>t2_name : for loop : 2 <br>t1_name : synchronized for loop : 0 <br>t2_name : for loop : 3 <br>t1_name : synchronized for loop : 1 <br>t2_name : for loop : 4 <br>t1_name : synchronized for loop : 2 <br>t1_name : synchronized for loop : 3 <br>t1_name : synchronized for loop : 4 <br>t2_name : synchronized for loop : 0 <br>t2_name : synchronized for loop : 1 <br>t2_name : synchronized for loop : 2 <br>t2_name : synchronized for loop : 3 <br>t2_name : synchronized for loop : 4 <br>第一个for 循环没有受synchronized 保护。对于第一个for 循环，t1,t2 可以同时访问。<br>运行结果表明t1 执行到了k=2 时，t2 开始执行了。t1 首先执行完了第一个for 循环，此时t2<br>还没有执行完第一个for 循环（t2 刚执行到k=2）。t1 开始执行第二个for 循环，当t1 的第二<br>个for 循环执行到k=1 时，t2 的第一个for 循环执行完了。t2 想开始执行第二个for 循环，但<br>由于t1 首先执行了第二个for 循环，这个对象的锁标志自然在t1 手中（synchronized 方法的<br>执行权也就落到了t1 手中），在t1 没执行完第二个for 循环的时候，它是不会释放锁标志的。所<br>以t2 必须等到t1 执行完第二个for 循环后，它才可以执行第二个for 循环。</p>
<p><br>三：sleep() <br>示例6： <br>public class ThreadTest implements Runnable <br>{ <br>public void run() <br>{ <br>for(int k=0;k&lt;5;k++) <br>{ <br>if(k == 2) <br>{ <br>try <br>{ <br>Thread.currentThread().sleep(5000); <br>} <br>catch(Exception e) <br>{} <br>} <br>System.out.print(" " + k); <br>} <br>} <br>public static void main(String[] args) <br>{ <br>Runnable r = new ThreadTest(); <br>Thread t = new Thread(r); <br>t.start(); <br>} <br>} <br>sleep 方法会使当前的线程暂停执行一定时间（给其它线程运行机会）。读者可以运行示例6， <br>看看结果就明白了。sleep 方法会抛出异常，必须提供捕获代码。<br>示例7： <br>public class ThreadTest implements Runnable <br>{ <br>public void run() <br>{ for(int k=0;k&lt;5;k++) <br>{ <br>if(k == 2) <br>{ <br>try <br>{ <br>Thread.currentThread().sleep(5000); <br>} <br>catch(Exception e) <br>{} <br>} <br>System.out.println(Thread.currentThread().getName() <br>+ " : " + k); <br>} <br>} <br>public static void main(String[] args) <br>{ <br>Runnable r = new ThreadTest(); <br>Thread t1 = new Thread(r,"t1_name"); <br>Thread t2 = new Thread(r,"t2_name"); <br>t1.setPriority(Thread.MAX_PRIORITY); <br>t2.setPriority(Thread.MIN_PRIORITY); <br>t1.start(); <br>t2.start(); <br>} <br>} <br>t1 被设置了最高的优先级，t2 被设置了最低的优先级。t1 不执行完，t2 就没有机会执行。<br>但由于t1 在执行的中途休息了5 秒中，这使得t2 就有机会执行了。读者可以运行这个程序试试看。<br>示例8： <br>public class ThreadTest implements Runnable <br>{ <br>public synchronized void run() <br>{ <br>for(int k=0;k&lt;5;k++) <br>{ <br>if(k == 2) <br>{ <br>try <br>{ <br>Thread.currentThread().sleep(5000); <br>} <br>catch(Exception e) <br>{} } <br>System.out.println(Thread.currentThread().getName() <br>+ " : " + k); <br>} <br>} <br>public static void main(String[] args) <br>{ <br>Runnable r = new ThreadTest(); <br>Thread t1 = new Thread(r,"t1_name"); <br>Thread t2 = new Thread(r,"t2_name"); <br>t1.start(); <br>t2.start(); <br>} <br>} <br>请读者首先运行示例8 程序，从运行结果上看：一个线程在sleep 的时候，并不会释放这个对<br>象的锁标志。</p>
<p><br>四：join() <br>示例9： <br>public class ThreadTest implements Runnable <br>{ <br>public static int a = 0; <br>public void run() <br>{ <br>for(int k=0;k&lt;5;k++) <br>{ <br>a = a + 1; <br>} <br>} <br>public static void main(String[] args) <br>{ <br>Runnable r = new ThreadTest(); <br>Thread t = new Thread(r); <br>t.start(); <br>System.out.println(a); <br>} <br>} <br>请问程序的输出结果是5 吗？答案是：有可能。其实你很难遇到输出5 的时候，通常情况下都<br>不是5。这里不讲解为什么输出结果不是5，我要讲的是：怎样才能让输出结果为5！其实很简单， <br>join()方法提供了这种功能。join()方法，它能够使调用该方法的线程在此之前执行完毕。<br>把示例9 的main()方法该成如下这样： public static void main(String[] args) throws Exception <br>{ <br>Runnable r = new ThreadTest(); <br>Thread t = new Thread(r); <br>t.start(); <br>t.join(); <br>System.out.println(a); <br>} <br>这时，输出结果肯定是5！join()方法会抛出异常，应该提供捕获代码。或留给JDK 捕获。<br>示例10： <br>public class ThreadTest implements Runnable <br>{ <br>public void run() <br>{ <br>for(int k=0;k&lt;10;k++) <br>{ <br>System.out.print(" " + k); <br>} <br>} <br>public static void main(String[] args) throws Exception <br>{ <br>Runnable r = new ThreadTest(); <br>Thread t1 = new Thread(r); <br>Thread t2 = new Thread(r); <br>t1.start(); <br>t1.join(); <br>t2.start(); <br>} <br>} <br>运行这个程序，看看结果是否与示例3 一样？ </p>
<p><br>五：yield() <br>yield()方法与sleep()方法相似，只是它不能由用户指定线程暂停多长时间。按照SUN 的<br>说法：sleep <br>方法可以使低优先级的线程得到执行的机会，当然也可以让同优先级和高优先级的线程有执行的机会。而yield()方法只能使同优先级的线程有执行的机会。<br>示例11： <br>public class ThreadTest implements Runnable <br>{ <br>public void run() <br>{ for(int k=0;k&lt;10;k++) <br>{ <br>if(k == 5 &amp;&amp; Thread.currentThread().getName().equals("t1")) <br>{ <br>Thread.yield(); <br>} <br>System.out.println(Thread.currentThread().getName() <br>+ " : " + k); <br>} <br>} <br>public static void main(String[] args) <br>{ <br>Runnable r = new ThreadTest(); <br>Thread t1 = new Thread(r,"t1"); <br>Thread t2 = new Thread(r,"t2"); <br>t1.setPriority(Thread.MAX_PRIORITY); <br>t2.setPriority(Thread.MIN_PRIORITY); <br>t1.start(); <br>t2.start(); <br>} <br>} <br>输出结果： <br>t1 : 0 <br>t1 : 1 <br>t1 : 2 <br>t1 : 3 <br>t1 : 4 <br>t1 : 5 <br>t1 : 6 <br>t1 : 7 <br>t1 : 8 <br>t1 : 9 <br>t2 : 0 <br>t2 : 1 <br>t2 : 2 <br>t2 : 3 <br>t2 : 4 <br>t2 : 5 <br>t2 : 6 <br>t2 : 7 <br>t2 : 8 <br>t2 : 9 <br>多次运行这个程序，输出也是一样。这说明：yield()方法不会使不同优先级的线程有执行的<br>机会。</p>
<p><br>六：wait(),notify(),notifyAll() <br>首先说明：wait(),notify(),notifyAll()这些方法由java.lang.Object 类提供，而上面<br>讲到的方法都是由java.lang.Thread 类提供（Thread 类实现了Runnable 接口）。<br>wait(),notify(),notifyAll()这三个方法用于协调多个线程对共享数据的存取，所以必<br>须在synchronized 语句块内使用这三个方法。先看下面了例子： <br>示例12： <br>public class ThreadTest implements Runnable <br>{ <br>public static int shareVar = 0; <br>public synchronized void run() <br>{ <br>if(shareVar == 0) <br>{ <br>for(int i=0;i&lt;10;i++) <br>{ <br>shareVar++ ; <br>if(shareVar == 5) <br>{ <br>try <br>{ <br>this.wait(); <br>} <br>catch(Exception e) <br>{} <br>} <br>} <br>} <br>if(shareVar != 0) <br>{ <br>System.out.print(Thread.currentThread().getName()); <br>System.out.println(" shareVar = " + shareVar); <br>this.notify(); <br>} <br>} <br>public static void main(String[] args) <br>{ <br>Runnable r = new ThreadTest(); <br>Thread t1 = new Thread(r,"t1"); Thread t2 = new Thread(r,"t2"); <br>t1.start(); <br>t2.start(); <br>} <br>} <br>运行结果： <br>t2 shareVar = 5 <br>t1 shareVar = 10 <br>t1线程最先执行。由于初始状态下shareVar 为0，t1 将使shareVar 连续加1，当shareVar <br>的值为5 时，t1 调用wait()方法，t1 将处于休息状态，同时释放锁标志。这时t2 得到了锁标志<br>开始执行，shareVar 的值已经变为5，所以t2 直接输出shareVar 的值，然后再调用notify() <br>方法唤醒t1。t1 接着上次休息前的进度继续执行，把shareVar 的值一直加到10，由于此刻<br>shareVar 的值不为0，所以t1 将输出此刻shareVar 的值，然后再调用notify()方法，由于<br>此刻已经没有等待锁标志的线程，所以此调用语句不起任何作用。<br>这个程序简单的示范了wait(),notify()的用法，读者还需要在实践中继续摸索。</p>
<p><br>七：关于线程的补充<br>编写一个具有多线程能力的程序可以继承Thread 类，也可以实现Runnable 接口。在这两个<br>方法中如何选择呢？从面向对象的角度考虑，作者建议你实现Runnable 接口。有时你也必须实现<br>Runnable 接口，例如当你编写具有多线程能力的小应用程序的时候。<br>线程的调度： <br>一个Thread 对象在它的生命周期中会处于各种不同的状态，上图形象地说明了这点。wa in<br>调用start()方法使线程处于可运行状态，这意味着它可以由JVM 调度并执行。这并不意味<br>着线程就会立即运行。<br>实际上，程序中的多个线程并不是同时执行的。除非线程正在真正的多CPU 计算机系统上执行， <br>否则线程使用单CPU 必须轮流执行。但是，由于这发生的很快，我们常常认为这些线程是同时执行<br>的。<br>JAVA 运行时系统的计划调度程序是抢占性的。如果计划调度程序正在运行一个线程并且来了另<br>一个优先级更高的线程，那么当前正在执行的线程就被暂时终止而让更高优先级的线程执行。<br>JAVA 计划调度程序不会为与当前线程具有同样优先级的另一个线程去抢占当前的线程。但是， <br>尽管计划调度程序本身没有时间片（即它没有给相同优先级的线程以执行用的时间片），但以<br>Thread 类为基础的线程的系统实现可能会支持时间片分配。这依赖具体的*作系统，Windows 与<br>UNIX 在这个问题上的支持不会完全一样。<br>由于你不能肯定小应用程序将运行在什么*作系统上，因此你不应该编写出依赖时间片分配的<br>程序。就是说，应该使用yield 方法以允许相同优先级的线程有机会执行而不是希望每一个线程都自动得到一段CPU 时间片。<br>Thread 类提供给你与系统无关的处理线程的机制。但是，线程的实际实现取决于JAVA 运行<br>所在的*作系统。因此，线程化的程序确实是利用了支持线程的*作系统。<br>当创建线程时，可以赋予它优先级。它的优先级越高，它就越能影响运行系统。JAVA 运行系统<br>使用一个负责在所有执行JAVA 程序内运行所有存在的计划调度程序。该计划调度程序实际上使用<br>一个固定优先级的算法来保证每个程序中的最高优先级的线程得到CPU――允许最高优先级的线程<br>在其它线程之前执行。<br>对于在一个程序中有几个相同优先级的线程等待执行的情况，该计划调度程序循环地选择它们， <br>当进行下一次选择时选择前面没有执行的线程，具有相同优先级的所有的线程都受到平等的对待。<br>较低优先级的线程在较高优先级的线程已经死亡或者进入不可执行状态之后才能执行。<br>继续讨论wait(),notify(),notifyAll()： <br>当线程执行了对一个特定对象的wait()调用时，那个线程被放到与那个对象相关的等待池中。<br>此外，调用wait()的线程自动释放对象的锁标志。<br>可以调用不同的wait()：wait() 或wait(long timeout) <br>对一个特定对象执行notify()调用时，将从对象的等待池中移走一个任意的线程，并放到锁<br>标志等待池中，那里的线程一直在等待，直到可以获得对象的锁标志。notifyAll()方法将从对象<br>等待池中移走所有等待那个对象的线程并放到锁标志等待池中。只有锁标志等待池中的线程能获取<br>对象的锁标志，锁标志允许线程从上次因调用wait()而中断的地方开始继续运行。<br>在许多实现了wait()/notify()机制的系统中，醒来的线程必定是那个等待时间最长的线程。<br>然而，在Java 技术中，并不保证这点。<br>注意，不管是否有线程在等待，都可以调用notify()。如果对一个对象调用notify()方法， <br>而在这个对象的锁标志等待池中并没有线程，那么notify()调用将不起任何作用。<br>在JAVA 中，多线程是一个神奇的主题。之所以说它"神奇"，是因为多线程程序的运行结果不<br>可预测，但我们又可以通过某些方法控制多线程程序的执行。要想灵活使用多线程，读者还需要大<br>量实践。<br>另外，从JDK 1.2 开始，SUN 就不建议使用resume(),stop(),suspend()了。</p>
<p><br>转<a href="http://vegetable318.bokee.com/" mce_href="http://vegetable318.bokee.com/"><u><font color=#638f27>http://vegetable318.bokee.com</font></u></a></p>
 <img src ="http://www.blogjava.net/firtre/aggbug/126622.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/firtre/" target="_blank">笨蛋</a> 2007-06-27 16:30 <a href="http://www.blogjava.net/firtre/articles/126622.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>UML类图 </title><link>http://www.blogjava.net/firtre/articles/126320.html</link><dc:creator>笨蛋</dc:creator><author>笨蛋</author><pubDate>Tue, 26 Jun 2007 05:43:00 GMT</pubDate><guid>http://www.blogjava.net/firtre/articles/126320.html</guid><wfw:comment>http://www.blogjava.net/firtre/comments/126320.html</wfw:comment><comments>http://www.blogjava.net/firtre/articles/126320.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/firtre/comments/commentRss/126320.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/firtre/services/trackbacks/126320.html</trackback:ping><description><![CDATA[<p><font face=Arial>类与类之间的关系对于理解面向对象具有很重要的作用，以前在面试的时候也经常被问到这个问题，在这里我就介绍一下。<br>类与类之间存在以下关系:</font></p>
<font face=Arial>
<p><br><strong><font color=#ff6600>(1)泛化(Generalization)<br>(2)关联(Association)<br>(3)依赖(Dependency)<br>(4)聚合(Aggregation)</font></strong></p>
<p mce_keep="true">&nbsp;</p>
</font>
<p><font face=Arial><strong>UML图与应用代码例子:</strong></font></p>
<font face=Arial><br><strong><font size=+0><font color=#ff6600 size=1>1.泛化(Generalization)</font></font></strong></font><font face=Arial><strong><font color=#ff9900 size=4><br><font color=#ff6600 size=1>表示类与类之间的继承关系，接口与接口之间的继承关系，或类对接口的实现关系。一般化的关系是从子类指向父类的，与继承或实现的方法相反。</font></font></strong></font><font face=Arial>
<p><br><font color=#339966 size=3><strong><font color=#808080 size=1>[具体表现]</font><br></strong></font><span style="COLOR: #000000"><font color=#ff0000>父类</font> 父类实例＝new <font color=#ff0000>子类</font>()</span></p>
<p><br><strong><font color=#339966 size=3><font color=#808080><font size=1>[</font><font size=1>UML图](图1.1)</font></font><font color=#808080><br></font></font><img height=144 alt="" src="http://seagar.javaeye.com/upload/picture/pic/1320/10bfdb9d-ed2d-4226-bab2-f814d2e10a82.jpg" width=229 mce_src="http://seagar.javaeye.com/upload/picture/pic/1320/10bfdb9d-ed2d-4226-bab2-f814d2e10a82.jpg"><br></strong><font face=Arial><font color=#808080><strong>图1.1</strong></font> <strong>Animal类与Tiger类,Dog类的泛化关系<br></strong></font><br><strong><font color=#808080 size=1>[代码表现]</font></strong></p>
</font>
<div class=dp-highlighter>
<ol class=dp-j>
    <li class=alt><span><span class=keyword>class</span><span><strong>&nbsp;Animal{} &nbsp;&nbsp;</strong></span></span><strong> </strong>
    <li><span class=keyword>class</span><strong><span>&nbsp;Tiger&nbsp;</span><span class=keyword>extends</span><span>&nbsp;Animal{} &nbsp;&nbsp;</span> </strong>
    <li class=alt><span class=keyword>public</span><strong><span>&nbsp;</span><span class=keyword>class</span><span>&nbsp;Test &nbsp;&nbsp;</span> </strong>
    <li><strong><span>{ &nbsp;&nbsp;</span> </strong>
    <li class=alt><strong><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=keyword>public</span><span>&nbsp;</span><span class=keyword>void</span><span>&nbsp;test() &nbsp;&nbsp;</span> </strong>
    <li><strong><span>&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;</span> </strong>
    <li class=alt><strong><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Animal&nbsp;a=</span><span class=keyword>new</span><span>&nbsp;Tiger(); &nbsp;&nbsp;</span> </strong>
    <li><strong><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span> </strong>
    <li class=alt><strong><span>}&nbsp;&nbsp;</span> </strong></li>
</ol>
</div>
<br><font face=Arial><strong><font color=#ff6600 size=1>2.依赖(Dependency)</font></strong></font><font face=Arial><strong><font size=3><strong><br></strong></font><font color=#ff6600>对于两个相对独立的对象，当一个对象负责构造另一个对象的实例，或者依赖另一个对象的服务时，这两个对象之间主要体现为依赖关系。</font></strong></font><font face=Arial>
<p><br><font size=3><strong><font color=#808080><font size=1>[具体表现]</font><br></font></strong></font>依赖关系表现在<font color=#ff0000>局部变量</font>，<font color=#ff0000>方法的参数</font>，以及对<font color=#ff0000>静态方法的调用</font></p>
<p><br><font color=#339966 size=3><strong><font color=#808080 size=1>[现实例子]</font><br></strong></font>比如说你要去拧螺丝，你是不是要借助(也就是依赖)螺丝刀(Screwdriver)来帮助你完成拧螺丝(screw)的工作</p>
<p><br><font color=#808080 size=1><strong>[UML表现](图1.2)</strong></font></p>
<p align=left><strong><img height=82 alt="" src="http://seagar.javaeye.com/upload/picture/pic/1319/ec7bca6c-c01a-4772-a91b-3a695773ddfb.jpg" width=272 mce_src="http://seagar.javaeye.com/upload/picture/pic/1319/ec7bca6c-c01a-4772-a91b-3a695773ddfb.jpg"></strong></p>
<p align=left><br><font face=Arial><strong><font color=#339966><font color=#808080>图1.2</font> </font>Person类与Screwdriver类的依赖关系</strong><br><font face=Arial><font color=#339966 size=3><strong><br><font color=#808080 size=1>[代码表现]</font> </strong></font></font></font></p>
<div class=dp-highlighter>
<ol class=dp-j>
    <li class=alt><span><span class=keyword>public</span><strong><span>&nbsp;</span><span class=keyword>class</span><span>&nbsp;Person{ &nbsp;&nbsp;</span></strong></span><strong> </strong>
    <li><strong><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=comment>/**&nbsp;拧螺丝&nbsp;*/</span><span>&nbsp;&nbsp;</span> </strong>
    <li class=alt><strong><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=keyword>public</span><span>&nbsp;</span><span class=keyword>void</span><span>&nbsp;screw(Screwdriver&nbsp;screwdriver){ &nbsp;&nbsp;</span> </strong>
    <li><strong><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;screwdriver.screw(); &nbsp;&nbsp;</span> </strong>
    <li class=alt><strong><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span> </strong>
    <li><strong><span>}&nbsp;&nbsp;</span> </strong></li>
</ol>
</div>
<br><font face=Arial><strong><font color=#ff6600 size=1>3.关联(Association)</font></strong></font><font face=Arial><strong><font size=3><strong><br></strong></font><font color=#ff6600>对于两个相对独立的对象，当一个对象的实例与另一个对象的一些特定实例存在固定的对应关系时，这两个对象之间为关联关系。</font></strong></font><font face=Arial>
<p><br><font color=#339966 size=3><strong><font color=#808080 size=1>[具体表现]</font><br></strong></font>关联关系是使用<font color=#ff0000>实例变量</font>来实现</p>
<p><br><font size=3><strong><font color=#808080><font size=1>[现实例子]</font><br></font></strong></font>比如客户和订单，每个订单对应特定的客户，每个客户对应一些特定的订单；再例如公司和员工，每个公司对应一些特定的员工，每个员工对应一特定的公司</p>
<br><strong><font color=#339966 size=1><font color=#808080>[UML图] (图1.3)</font><br></font><img height=57 alt="" src="http://seagar.javaeye.com/upload/picture/pic/1318/d4b10677-364d-4c34-beb7-416f8e835d8c.jpg" width=291 mce_src="http://seagar.javaeye.com/upload/picture/pic/1318/d4b10677-364d-4c34-beb7-416f8e835d8c.jpg"><br><font face=Arial><strong><font color=#339966><font color=#808080>图1.3</font> </font></strong>公司和员工的关联关系</font></strong></font><br><font face=Arial><strong><br><font color=#808080 size=1>[代码表现]</font></strong> </font></font><font face=Arial>
<div class=dp-highlighter>
<ol class=dp-j>
    <li class=alt><span><span class=keyword>public</span><strong><span>&nbsp;</span><span class=keyword>class</span><span>&nbsp;Company{ &nbsp;&nbsp;</span></strong></span><strong> </strong>
    <li><strong><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=keyword>private</span><span>&nbsp;Employee&nbsp;employee; &nbsp;&nbsp;</span> </strong>
    <li class=alt><strong><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=keyword>public</span><span>&nbsp;Employee&nbsp;getEmployee(){ &nbsp;&nbsp;</span> </strong>
    <li><strong><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=keyword>return</span><span>&nbsp;employee; &nbsp;&nbsp;</span> </strong>
    <li class=alt><strong><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span> </strong>
    <li><strong><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=keyword>public</span><span>&nbsp;</span><span class=keyword>void</span><span>&nbsp;setEmployee(Employee&nbsp;employee){ &nbsp;&nbsp;</span> </strong>
    <li class=alt><strong><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=keyword>this</span><span>.employee=employee; &nbsp;&nbsp;</span> </strong>
    <li><strong><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span> </strong>
    <li class=alt><strong><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=comment>//公司运作 </span><span>&nbsp;&nbsp;</span> </strong>
    <li><strong><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=keyword>public</span><span>&nbsp;</span><span class=keyword>void</span><span>&nbsp;run(){ &nbsp;&nbsp;</span> </strong>
    <li class=alt><strong><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;employee.startWorking(); &nbsp;&nbsp;</span> </strong>
    <li><strong><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span> </strong>
    <li class=alt><strong><span>}&nbsp;&nbsp;</span> </strong></li>
</ol>
</div>
<font face=Arial><strong><font color=#ff6600 size=1>(4)聚合（Aggregation）</font></strong></font></font><font face=Arial><strong><font size=1><br></font><font color=#ff6600>当对象A被加入到对象B中，成为对象B的组成部分时，对象B和对象A之间为聚集关系。聚合是关联关系的一种，是较强的关联关系，强调的是<font size=+0>整体</font>与<font size=+0>部分</font>之间的关系。</font></strong></font><font face=Arial>
<p><br><font color=#339966 size=3><strong><font color=#808080 size=1>[具体表现]</font><br></strong></font>与关联关系一样，聚合关系也是通过<font color=#ff0000>实例变量</font>来实现这样关系的。关联关系和聚合关系来语法上是没办法区分的，从<font color=#ff0000>语义</font>上才能<font color=#ff0000>更好的区分</font>两者的区别。</p>
<p><br><font color=#808080 size=1><strong>[关联与聚合的区别]</strong></font><br>(1)<span style="COLOR: #ff6600">关联关系所涉及的两个对象是处在同一个层次上的</span>。比如人和自行车就是一种关联关系，而不是聚合关系，因为人不是由自行车组成的。<br><span style="COLOR: #ff6600">聚合关系涉及的两个对象处于不平等的层次上，一个代表整体，一个代表部分</span>。比如电脑和它的显示器、键盘、主板以及内存就是聚集关系，因为主板是电脑的组成部分。<br>(2)对于具有聚集关系（尤其是强聚集关系）的两个对象，整体对象会制约它的组成对象的生命周期。部分类的对象不能单独存在，它的生命周期依赖于整体类的对象的生命周期，当整体消失，部分也就随之消失。比如张三的电脑被偷了，那么电脑的所有组件也不存在了，除非张三事先把一些电脑的组件（比如硬盘和内存）拆了下来。</p>
<p><br><font color=#808080 size=1><strong>[UML图](图1.4)</strong></font><br><strong><img height=178 alt="" src="http://seagar.javaeye.com/upload/picture/pic/1326/7032798b-36ca-4b89-a462-97ba056cbe48.jpg" width=298 mce_src="http://seagar.javaeye.com/upload/picture/pic/1326/7032798b-36ca-4b89-a462-97ba056cbe48.jpg"><br><font face=Arial><strong><font color=#339966><font color=#808080>图1.3</font> </font><font color=#000000>电脑和组件的聚合关系</font></strong></font><br><br><font face=Arial><font color=#808080 size=1><strong>[代码表现]</strong></font></font></strong> </p>
<div class=dp-highlighter>
<ol class=dp-j>
    <li class=alt><span><span class=keyword>public</span><strong><span>&nbsp;</span><span class=keyword>class</span><span>&nbsp;Computer{ &nbsp;&nbsp;</span></strong></span><strong> </strong>
    <li><strong><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=keyword>private</span><span>&nbsp;CPU&nbsp;cpu; &nbsp;&nbsp;</span> </strong>
    <li class=alt><strong><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=keyword>public</span><span>&nbsp;CPU&nbsp;getCPU(){ &nbsp;&nbsp;</span> </strong>
    <li><strong><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=keyword>return</span><span>&nbsp;cpu; &nbsp;&nbsp;</span> </strong>
    <li class=alt><strong><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span> </strong>
    <li><strong><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=keyword>public</span><span>&nbsp;</span><span class=keyword>void</span><span>&nbsp;setCPU(CPU&nbsp;cpu){ &nbsp;&nbsp;</span> </strong>
    <li class=alt><strong><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=keyword>this</span><span>.cpu=cpu; &nbsp;&nbsp;</span> </strong>
    <li><strong><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span> </strong>
    <li class=alt><strong><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=comment>//开启电脑 </span><span>&nbsp;&nbsp;</span> </strong>
    <li><strong><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=keyword>public</span><span>&nbsp;</span><span class=keyword>void</span><span>&nbsp;start(){ &nbsp;&nbsp;</span> </strong>
    <li class=alt><strong><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=comment>//cpu运作 </span><span>&nbsp;&nbsp;</span> </strong>
    <li><strong><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cpu.run(); &nbsp;&nbsp;</span> </strong>
    <li class=alt><strong><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span> </strong>
    <li><strong><span>}&nbsp;&nbsp;</span> </strong></li>
</ol>
转CSDN<br><br><br>转自<a href="http://www.blogjava.net/cheneyfree/archive/2007/05/24/119670.html">http://www.blogjava.net/cheneyfree/archive/2007/05/24/119670.html</a><a href="http://www.blogjava.net/alex/archive/2006/08/29/66524.html"></a><br></div>
</font>
<img src ="http://www.blogjava.net/firtre/aggbug/126320.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/firtre/" target="_blank">笨蛋</a> 2007-06-26 13:43 <a href="http://www.blogjava.net/firtre/articles/126320.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>