﻿<?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-Duffblog-文章分类-技术文摘</title><link>http://www.blogjava.net/Duffblog/category/12286.html</link><description>前进一步，看看，需要前进更大一步才可以。</description><language>zh-cn</language><lastBuildDate>Tue, 27 Feb 2007 08:40:23 GMT</lastBuildDate><pubDate>Tue, 27 Feb 2007 08:40:23 GMT</pubDate><ttl>60</ttl><item><title>“中文问题没商量”之Dom4j中的编码问题 (转)</title><link>http://www.blogjava.net/Duffblog/articles/79712.html</link><dc:creator>追球者</dc:creator><author>追球者</author><pubDate>Tue, 07 Nov 2006 14:39:00 GMT</pubDate><guid>http://www.blogjava.net/Duffblog/articles/79712.html</guid><wfw:comment>http://www.blogjava.net/Duffblog/comments/79712.html</wfw:comment><comments>http://www.blogjava.net/Duffblog/articles/79712.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Duffblog/comments/commentRss/79712.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Duffblog/services/trackbacks/79712.html</trackback:ping><description><![CDATA[
		<span class="content">本文主要讲述的是Dom4j在把Document保存到文件过程中出现的一个中文问题，本文跟<a class="l2" href="http://www.easyjf.com/html/20060529/1924796210483044.htm" target="_blank"><font color="#666666">《80前》</font></a>一文一样，以Spring项目无关，请“<a class="l2" href="http://blog.csdn.net/easyjf/archive/2006/07/12/910060.aspx" target="_blank"><font color="#666666">春迷</font></a>”们自重、没事勿扰，文中不足之处欢迎大家批评指教。<br />　　Dom4j是一个比较优秀的java开源xml解析项目，支持DOM, SAX and JAXP.，并提供对XPath查询语言的强大支持。因此，在 EasyJF团队的很多开源项目中，如EasyJWeb、EasyDBO等都是使用Dom4j来处理xml文件相关操作。<br /> <br />1、从一个xml文件中载入一个Dom到内存：<br />　　FileInputStream in = new FileInputStream(new File(fileName));<br />　　SAXReader reader = new SAXReader();<br />　　doc = reader.read(in);<br />2、把Dom中的数据写入到xml文件中<br />　　使用Dom4j，要把一个Dom中的数据写入到文件非常简单，API如下：<br />　　 public void write(Writer writer) throws IOException；<br />　　因此，假如我们要把一个Document写入到c:\test.xml文件中，可以简单的使用下面的代码即可：<br />java.io.Writer wr= new java.io.FileWrite(filename);<br />　　doc.write(wr);<br /> wr.close();//注意，必须要执行close()方法，才会实现真正的写入<br />　　<br />　　这种用法也是Dom4j所推荐我们使用的非常简单的方法。然而，当我们的dom中包含有中文字符数据的时候，这种方法写入的xml文档却无法使直觉打开。会提示类似如下的错误：<br />　　 org.dom4j.DocumentException: invalid byte 1 of 1-byte UTF-8 sequence (0xb2) Nested exception: invalid byte 1 of 1-byte UTF-8 sequence (0xb2)<br /> at org.dom4j.io.SAXReader.read(SAXReader.java:484)<br /> at org.dom4j.io.SAXReader.read(SAXReader.java:343)<br /> at <br />　　我们可以看生成的xml文件编码，内容是utf-8的，但文件格式确是ANSI的，如下图所示：<br /><img src="http://www.easyjf.com/upfile/20060819/11559975301791157793070.JPG" /><br /> <br />原因分析：<br />　　由于FileWriter默认的输出编码是ANSI编码，而Dom4j中的wirte方法提供的内容实际是以UTF-8保存的，因此造成了包括中文字符的XML文件无法正常阅读。<br /> <br />解决方法：<br /> 　　不能使用简单的FileWriter，而应该是使用一个能指定具体输出编码的Writer，在JDK的io包中， OutputStreamWriter可以指定输出编码。<br />　　正确的代码如下：<br />java.io.OutputStream out=new java.io.FileOutputStream(fileName);<br />   java.io.Writer wr=new java.io.OutputStreamWriter(out,"UTF-8");   <br />   doc.write(wr);   <br />   wr.close();<br />   out.close();<br />　　简化一下可以写成下面的样式：<br />　　 java.io.Writer wr=new java.io.OutputStreamWriter(new java.io.FileOutputStream(fileName),"UTF-8");   <br />   doc.write(wr);   <br />   wr.close();<br /><br />小结：<br />　　由于大多数优秀的基础性开源项目都是老外开发，他们不大可能在中文平台下进行测试，用例数据也很少会使用中文平台，因此，我们即使按照这些开源项目的通用说明文档及用户指南去操作，也会出现很多不可预知的错误。这也是为什么本人要参与组建开源团队EasyJF，提倡搞国产开源，并开发一些基础性的开源框架如EasyJWeb、EasyDBO的一个初衷。<br />　　当然，这里提出的中文问题，算是一个还“没来得及商量”以及要通过一些罕见的处理才能正确运行的中文问题。因此，同样归并到了“中文问题没商量”系列中。<br /><br /><a href="http://blog.lupaworld.com/blog/htm/do_showone/tid_2261.html">http://blog.lupaworld.com/blog/htm/do_showone/tid_2261.html</a></span>
<img src ="http://www.blogjava.net/Duffblog/aggbug/79712.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Duffblog/" target="_blank">追球者</a> 2006-11-07 22:39 <a href="http://www.blogjava.net/Duffblog/articles/79712.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>管理 Eclipse 环境(Eclipse 维护的神秘艺术)</title><link>http://www.blogjava.net/Duffblog/articles/77560.html</link><dc:creator>追球者</dc:creator><author>追球者</author><pubDate>Fri, 27 Oct 2006 02:46:00 GMT</pubDate><guid>http://www.blogjava.net/Duffblog/articles/77560.html</guid><wfw:comment>http://www.blogjava.net/Duffblog/comments/77560.html</wfw:comment><comments>http://www.blogjava.net/Duffblog/articles/77560.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Duffblog/comments/commentRss/77560.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Duffblog/services/trackbacks/77560.html</trackback:ping><description><![CDATA[Eclipse 的持续发展意味着需要管理的项目和插件的数量一直在增长。为了跟上最新的 Eclipse 版本，这个管理过程会使开发人员感到灰心。对于新用户来说，项目、插件、工作区和安装的概念首先就可能使之感到畏缩。本文将介绍管理 Eclipse 环境的最佳实践。<br /><br /><p><a name="N1006D"><span class="atitle">管理插件</span></a></p><p><a name="N10073"><span class="smalltitle">什么是插件？为什么我需要关心插件？</span></a></p><p><i>插件</i>（plug-in，也称为 <i>bundle</i>）是 Eclipse 的功能块。在 Eclipse 中，所有的一切都有其相应的插件，这包括：</p><ul><li>透视图和视图</li><li>编辑器</li><li>建模工具</li><li>登录和其他核心功能</li></ul><p>事实上，整个 Eclipse IDE 就是被构建为一个大的插件集合。其他基于 Eclipse 的产品，例如 IBM Rational® Software Architect，通过添加新插件增强了基本的 Eclipse。</p><p>一组相关的插件组成<i>特性</i>。特性和它们的插件存在于 Eclipse 程序目录中（在这个例子中，Eclipse 被安装在 /opt/eclipse 目录中）。下面是目录布局的一个示例：</p><br /><a name="eclipseDirStructure"><b>清单 1. Eclipse 特性和插件目录结构</b></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section">

/opt/eclipse/ 
   features/ 
      org.eclipse.jdt_3.1.1/
         feature.xml 
         ... 
   plugins/
      org.eclipse.jdt.ui_3.1.1.jar
      ...
      </code></pre></td></tr></tbody></table><br /><p>Eclipse 可以有许多相同的插件，针对每个不同的版本有一个这样的插件。它知道如何解决插件依赖性、避免版本冲突，因此您永远不必担心同时安装两个 Subclipse 插件。</p><p>在长期使用 Eclipse 的过程中，您总是会通过下载第三方插件或是创建您自己的插件来增加新的功能。跨不同的 Eclipse 版本管理这些插件可能是个麻烦。因为插件存在于 Eclipse 程序目录中，所以如果您安装 Eclipse 的新版本，它们就会丢失。这意味着如果您有多个 Eclipse 安装，就必须保存大量插件的多个副本；甚至，在每次想要升级 Eclipse 时，您只能很麻烦地全部重新安装。</p><p>如果将插件存储于 Eclipse 程序目录以外的独立位置，当升级到 Eclipse 的新版本时，就不需要重新安装它们，而且，可以跨多个 Eclipse 版本共享插件。</p><p><a name="method1"><span class="smalltitle">实施控制：方法 1 —— 手动的文件系统扩展</span></a></p><p>有三种方法对插件实施控制。第一种方法是手动创建一个可以保存插件的目录（称之为<i>产品扩展</i>），将插件移到该目录，然后告诉 Eclipse 在这里寻找特性和插件。</p><p>在我们的例子中，我们会创建一个名为 /opt/eclipse-plugins 的位置用来存储插件。为了让 Eclipse 在这里存储插件，您必须首先创建如下的目录结构和文件：</p><br /><a name="N100C1"><b>清单 2. Eclipse 产品扩展目录结构</b></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section">

/opt/eclipse-plugins/ 
   eclipse/ 
      .eclipseextension
      features/ 
      plugins/
      </code></pre></td></tr></tbody></table><br /><p>注意，除了创建这些目录以外，您还必须在 eclipse 目录（在我们的例子中，是指 /opt/eclipse-plugins/eclipse）中创建一个名为 .eclipseextension 的文件。这个文件让 Eclipse 知道在这里可以找到扩展。它应该有如下内容：</p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section">
id=org.eclipse.platform name=Eclipse Platform
version=3.1.1
</code></pre></td></tr></tbody></table><br /><p>.eclipseextension 文件中的 <code>version</code> 属性应该设置为使用这个产品扩展的 Eclipse 的版本。该属性可以是特定的（3.1.1）、比较一般的（3.0.0）或者非常一般的（1.0.0）。在撰写本文时，版本号似乎对产品扩展的功能并没有任何影响。</p><p>注意，如果您使用的是 Windows®，则无法通过 Explorer shell 创建 .eclipseextension 文件。通过打开 NotePad，输入文件的内容，并将其保存为 .eclipseextension（确保文件类型选中为 “所有文件”，否则 Notepad 将会在文件名后添加 .txt），可以创建这样的文件。</p><p>下一件事是将这个插件位置告诉 Eclipse，以便它知道以后在这里寻找插件。选择 <b>Help &gt; Software Updates &gt; Manager Configuration</b> 得到 Product Configuration Manager，在这里完成这项工作。</p><p>使用 Product Configuration Manager，您可以添加新的 Eclipse 扩展。为了启用上面创建的扩展（/opt/eclipse-plugins），我们需要将它作为一个扩展位置添加。每一个人都已经有一个扩展位置，那就是 Eclipse 安装中的插件文件夹。在 Eclipse Platform 上右击，选择 <b>Add &gt; Extension Location</b> 就可以添加另一个扩展。</p><br /><a name="N100E9"><b>图 1. 添加扩展位置</b></a><br /><img height="371" alt="添加扩展位置" src="http://www-128.ibm.com/developerworks/cn/opensource/os-ecl-manage/productConfiguration1.jpg" width="419" /><br /><p>一旦您已经选中了插件所在的目录，插件就会显示在产品扩展的列表中。在这里，您可以检验插件是否已找到。</p><br /><a name="N100FB"><b>图 2. 查看一个扩展位置中的插件</b></a><br /><img height="326" alt="查看一个扩展位置中的插件" src="http://www-128.ibm.com/developerworks/cn/opensource/os-ecl-manage/productConfiguration2.jpg" width="571" /><br /><p>Product Configuration 屏幕好的方面是，您可以很容易地禁用整个插件位置 —— 这在进行插件开发和测试不同配置时很有用。</p><p><a name="N1010B"><span class="smalltitle">实施控制：方法 2 —— 通过 Configuration Manager 添加产品扩展</span></a></p><p>不必在文件系统中创建文件夹和 .eclipseextension 文件，您可以让 Eclipse 为您创建产品扩展。</p><p>您可以在 Update Manager（<b>Help &gt; Software Updates &gt; Find and Install</b>）中创建新的产品扩展。在安装新的插件时，Eclipse 最终会提示您所要安装的位置。在这里，您可以单击 Change Location 以选择一个产品扩展。</p><br /><a name="N1011C"><b>图 3. 选择插件的安装位置</b></a><br /><img height="385" alt="选择插件的安装位置" src="http://www-128.ibm.com/developerworks/cn/opensource/os-ecl-manage/updateManager1.jpg" width="446" /><br /><p>选择 Add Location。当您选定一个目录时，Eclipse 将在那里为您创建一个产品扩展。</p><br /><a name="N1012E"><b>图 4. 通过 Update Manager 创建一个新的产品扩展</b></a><br /><img height="300" alt="通过 Update Manager 创建一个新的产品扩展" src="http://www-128.ibm.com/developerworks/cn/opensource/os-ecl-manage/updateManager2.jpg" width="399" /><br /><p>当您以后安装插件时，确保它们是被安装到您所想要的插件扩展地点（参见图 3 中的 Install Location 区域）</p><p><a name="control3"><span class="smalltitle">实施控制：方法 3 —— 创建管理产品扩展的 links 文件夹</span></a></p><p>如果在您的文件系统中已经有了产品扩展，例如我们在 <a href="http://www-128.ibm.com/developerworks/cn/opensource/os-ecl-manage/#method1">方法 1</a> 中创建的那个，那么您可以在 Eclipse 程序目录中创建一些简单的文件，告知 Eclipse 需要检查这些目录以寻找插件。</p><p>首先，在 Eclipse 安装文件夹（例如 /opt/eclipse）中创建一个名为 links 的目录。在这个目录中，您可以创建 *.link 文件（例如 emfPlugins.link）。每一个链接文件指向一个产品扩展位置。Eclipse 会在启动时扫描这个 links 文件夹，并在每个链接文件中所指向的产品扩展中寻找插件。下面是一个使用 links 文件夹的 Eclipse 安装布局的例子：</p><br /><a name="N10152"><b>清单 3. 使用 links 文件夹的 Eclipse 安装布局</b></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section">

/opt/eclipse/
     links/
          emfPlugins.link
          webtools.link
          updateManager.link
          ...
     ...
     </code></pre></td></tr></tbody></table><br /><p>链接文件的内容看上去应该像下面这样：</p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section">
path=/opt/plugins/emf/
</code></pre></td></tr></tbody></table><br /><table cellspacing="0" cellpadding="0" width="40%" align="right" border="0"><tbody><tr><td width="10"><img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="10" /></td><td><table cellspacing="0" cellpadding="5" width="100%" border="1"><tbody><tr><td bgcolor="#eeeeee"><a name="N10163"><b>Windows</b></a><br />在本文中，我们着重介绍 Eclipse 的 Linux® 安装。所有提供的示例清单对于 Windows 都是有效的。您仅仅需要将路径替换为相应的 windows 路径。另外请注意，在 Windows 中，路径中需要使用双反斜杠（例如 path=c:\\plugins\\emf）。 </td></tr></tbody></table></td></tr></tbody></table><p>/opt/plugins/emf/ 有一个 Eclipse 产品扩展的目录结构，如 <a href="http://www-128.ibm.com/developerworks/cn/opensource/os-ecl-manage/#eclipseDirStructure">清单 1</a> 所示。</p><p>这个方法的优势在于，所有的插件位置被作为一个文件夹中的文本文件来存储。这意味着您可以通过简单地将 links 文件夹复制到新的 Eclipse 安装中，来升级 Eclipse 并使其指向您的产品扩展文件夹。您也可以通过从每个 Eclipse 安装建立一个到 links 文件夹的符号链接，获得一个针对所有 Eclipse 安装的公用 links 文件夹（如果您的文件系统支持符号链接）。</p><br /><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br /><img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td></tr></tbody></table><table class="no-print" cellspacing="0" cellpadding="0" align="right"><tbody><tr align="right"><td><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br /><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td valign="center"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br /></td><td valign="top" align="right"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/opensource/os-ecl-manage/#main"><b>回页首</b></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="workspaces"><span class="atitle">管理 Eclipse 工作区</span></a></p><p>在 Eclipse 中，工作区的概念被简单地描述成可以通过插件访问的资源的容器。工作区是终端用户和 Eclipse 平台之间交互的枢纽。终端用户能够在工作区中创建项目并处理其中的内容。工作区本身作为一个目录存在于文件系统中，并且只局限于每个 Eclipse 实例使用一个。工作区还包含一个 .metadata 目录，用来持久存储诸如插件状态这样的私有信息。</p><p><a name="N1017E"><span class="smalltitle">为什么我需要多个 Eclipse 工作区？</span></a></p><p>简单的答案是为了性能。工作区中的项目越多，达到开发系统所能处理项目的临界点的机会就越大。为了解决这个问题，您可以通过 <code>-data</code> 参数划分 Eclipse 工作区，这个参数被传递给 Eclipse 可执行文件（例如 /opt/eclipse/eclipse）：</p><br /><a name="N1018F"><b>清单 4. 指定不同的工作区</b></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section">

/opt/eclipse-3.1/eclipse -data /opt/workspaces/web
/opt/eclipse-3.2M2/eclipse -data /opt/workspaces/web
/opt/eclipse-3.2M2/eclipse -data /opt/workspaces/dev -vmargs -Xmx512m
</code></pre></td></tr></tbody></table><br /><table cellspacing="0" cellpadding="0" width="40%" align="right" border="0"><tbody><tr><td width="10"><img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="10" /></td><td><table cellspacing="0" cellpadding="5" width="100%" border="1"><tbody><tr><td bgcolor="#eeeeee"><a name="N10199"><b>工作区提示</b></a><br />您可以通过向 Eclipse 可执行文件传递 <code>-showlocation</code> 参数来显示工作区位置。此外，您还可以通过 <code>-vmargs -Xms</code> 和 <code>Xmx</code> 参数为不同的工作区指定不同的性能特征。 </td></tr></tbody></table></td></tr></tbody></table><p>您也可以通过从 Eclipse 中选择 <b>File &gt; Switch Workspace</b> 切换工作区，而不必重新启动 Eclipse。</p><p>还有一种可能的情况是，您有一个 “研究” 工作区。在这个工作区中，您需要使用 Open Type（<b>Ctrl+Shift+T</b>）等由 Eclipse 对载入的大代码库的代码仔细搜寻一遍。如果您试图学习一些例子，或者您曾经想知道一个开放源码项目是如何处理特定问题的，那么这种方法是极其有用的。</p><p>有多个工作区的不利方面在于需要在它们之间共享开发首选项。因为首选项被持久存储在 Eclipse 中的一个工作区中，所以您必须导出工作区的首选项并将它们导入您所要求的工作区中（<b>File &gt; Export &gt; Preferences</b>）。</p><br /><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br /><img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td></tr></tbody></table><table class="no-print" cellspacing="0" cellpadding="0" align="right"><tbody><tr align="right"><td><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br /><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td valign="center"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br /></td><td valign="top" align="right"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/opensource/os-ecl-manage/#main"><b>回页首</b></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="N101BD"><span class="atitle">管理 Eclipse 安装</span></a></p><p><a name="N101C3"><span class="smalltitle">为什么我需要多个 Eclipse 安装？</span></a></p><p>如果您使用多个基于 Eclipse 的产品，就必然需要多个 Eclipse 安装。例如，如果您使用基本的 Eclipse V3.1 来完成日常的 Java™ 语言编程，并使用带有 WebTool 的 Eclipse 来编写 IBM WebSphere® 应用程序，那么您就有两个完全独立的 Eclipse 安装。在这些基于 Eclipse 的产品之间共享插件和工作区可以节约时间，并避免一些升级带来的麻烦。</p><p>您在开发 Eclipse 的插件时也需要多个 Eclipse 安装。当有了多个 Eclipse 安装时，您可以跨不同的 Eclipse 版本测试您的插件的功能。您也可以将一组不同的插件对应不同的 Eclipse 安装，以便跨多个环境配置测试您的插件。</p><p>注意，通过在 Eclipse 中选择 <b>Help &gt; Software Updates &gt; Manage Configuration</b>，来考察 Eclipse IDE（它启用和禁用属于这些特性的插件）中的特性，可以管理哪些插件由 Eclipse 使用。在开发自己的插件时，您也可以通过 Run Configuration Manager 来管理运行 Eclipse 测试实例时哪些插件被启用。我们通常的经验是，使用多个 Eclipse 安装是管理多个 Eclipse 版本和配置最方便且最便于重用的方法，对于测试目的尤其如此。</p><p><a name="N101D9"><span class="smalltitle">多个 Eclipse 安装</span></a></p><p>Eclipse 安装独立存在于它们自己的文件夹中。要使得多个安装并存，只要下载您所要的 Eclipse 产品和版本并将其解压到它们自己的目录中即可。下面是一个用来跨不同 Eclipse 版本测试插件的示例布局：</p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section">
/opt/eclipse-3.0
/opt/eclipse-3.1
/opt/eclipse-3.2-m1
</code></pre></td></tr></tbody></table><br /><p>对于节约所有当前安装的插件安装时间和避免工作区重复，尽可能地跨 Eclipse 安装进行共享是一个好主意。正如我们前面所讲述的，您可以共享以下内容：</p><ul><li><b>插件</b> —— 有一个（或多个）供所有安装共同使用的公用的插件文件夹。最好的方法是按照 <a href="http://www-128.ibm.com/developerworks/cn/opensource/os-ecl-manage/#control3">实施控制：方法 3</a> 中所讲述的那样创建一个 links 文件夹。</li><li><b>工作区</b> —— 参见 <a href="http://www-128.ibm.com/developerworks/cn/opensource/os-ecl-manage/#workspaces">管理 Eclipse 工作区</a></li><li><b>工作区首选项</b> —— 与工作区绑定的首选项。从 Eclipse 中选择 <b>File &gt; Export &gt; Preferences</b>。</li></ul><p>注意，跨 Eclipse 安装共享工作区和首选项可能会有问题，尤其是当 Eclipse 版本的主编号不同时（例如 3.1 和 3.2）。</p><br /><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br /><img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td></tr></tbody></table><table class="no-print" cellspacing="0" cellpadding="0" align="right"><tbody><tr align="right"><td><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br /><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td valign="center"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br /></td><td valign="top" align="right"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/opensource/os-ecl-manage/#main"><b>回页首</b></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="N10209"><span class="atitle">结束语</span></a></p><p>我们的目的有两个：初步介绍 Eclipse 的基本工作要素，比如插件、项目和工作区；告诉您管理多个 Eclipse 环境的好处以及一些不利方面。我们希望您能够接受这些知识并将其应用到您的实践中以节约 Eclipse 维护的时间。<br /><br />转自：<a href="http://www-128.ibm.com/developerworks/cn/opensource/os-ecl-manage/">http://www-128.ibm.com/developerworks/cn/opensource/os-ecl-manage/</a></p><img src ="http://www.blogjava.net/Duffblog/aggbug/77560.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Duffblog/" target="_blank">追球者</a> 2006-10-27 10:46 <a href="http://www.blogjava.net/Duffblog/articles/77560.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Oracle数据库字符集问题解析</title><link>http://www.blogjava.net/Duffblog/articles/77550.html</link><dc:creator>追球者</dc:creator><author>追球者</author><pubDate>Fri, 27 Oct 2006 02:13:00 GMT</pubDate><guid>http://www.blogjava.net/Duffblog/articles/77550.html</guid><wfw:comment>http://www.blogjava.net/Duffblog/comments/77550.html</wfw:comment><comments>http://www.blogjava.net/Duffblog/articles/77550.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Duffblog/comments/commentRss/77550.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Duffblog/services/trackbacks/77550.html</trackback:ping><description><![CDATA[
		<span class="javascript" id="text1874350" style="FONT-SIZE: 12px">
				<font face="Verdana">经常看到一些朋友问ORACLE字符集方面的问题，我想以迭代的方式来介绍一下。<br /><br /><b>第一次迭代：掌握字符集方面的基本概念。</b><br />有些朋友可能会认为这是多此一举，但实际上正是由于对相关基本概念把握不清，才导致了诸多问题和疑问。<br />首先是字符集的概念。<br />我们知道，电子计算机最初是用来进行科学计算的（所以叫做“计算机”），但随着技术的发展，还需要计算机进行其它方面的应用处理。这就要求计算机不仅能处理数值，还能处理诸如文字、特殊符号等其它信息，而计算机本身能直接处理的只有数值信息，所以就要求对这些文字、符号信息进行数值编码，最初的字符集是我们都非常熟悉的ASCII，它是用7个二进制位来表示128个字符，而后来随着不同国家、组织的需要，出现了许许多多的字符集，如表示西欧字符的 ISO8859系列的字符集，表示汉字的GB2312-80、GBK等字符集。<br /><b>字符集</b>的实质就是对一组特定的符号，分别赋予不同的数值编码，以便于计算机的处理。<br /><b>字符集之间的转换。</b>字符集多了，就会带来一个问题，比如一个字符，在某一字符集中被编码为一个数值，而在另一个字符集中被编码为另一个数值，比如我来创造两个字符集demo_charset1与demo_charset2，在demo_charset1中，我规定了三个符号的编码为：A （0001），B（0010），？（1111）；而在demo_charset2中，我也规定了三个符号的编码为：A（1001），C（1011），？（1111），这时我接到一个任务，要编写一个程序，负责在demo_charset1与demo_charset2之间进行转换。由于知道两个字符集的编码规则，对于demo_charset1中的0001，在转换为demo_charset2时，要将其编码改为1001；对于 demo_charset1中的1111，转换为demo_charset2时，其数值不变；而对于demo_charset1中的0010，其对应的字符为B，但在demo_charset2没有对应的字符，所以从理论上无法转换，对于所有这类无法转换的情况，我们可以将它们统一转换为目标字符集中的一个特殊字符（称为“替换字符”），比如在这里我们可以将？作为替换字符，所以B就转换为了？，出现了信息的丢失；同样道理，将demo_charset2 的C字符转换到demo_charset1时，也会出现信息丢失。<br />所以说，在字符集转换过程中，如果源字符集中的某个字符在目标字符集中没有定义，将会出现信息丢失。<br /><b>数据库字符集的选择。</b><br />我们在创建数据库时，需要考虑的一个问题就是选择什么字符集与国家字符集（通过create database中的CHARACTER SET与NATIONAL CHARACTER SET子句指定）。考虑这个问题，我们必须要清楚数据库中都需要存储什么数据，如果只需要存储英文信息，那么选择US7ASCII作为字符集就可以；但是如果要存储中文，那么我们就需要选择能够支持中文的字符集（如ZHS16GBK）；如果需要存储多国语言文字，那就要选择UTF8了。<br />数据库字符集的确定，实际上说明这个数据库所能处理的字符的集合及其编码方式，由于字符集选定后再进行更改会有诸多的限制，所以在数据库创建时一定要考虑清楚后再选择。<br />而我们许多朋友在创建数据库时，不考虑清楚，往往选择一个默认的字符集，如WE8ISO8859P1或US7ASCII，而这两个字符集都没有汉字编码，所以<b>用这种字符集存储汉字信息从原则上说就是错误的。</b>虽然在有些时候选用这种字符集好象也能正常使用，但它会给数据库的使用与维护带来一系列的麻烦，在后面的迭代过程中我们将深入分析。<br /><b>客户端的字符集。</b><br />有过一些Oracle使用经验的朋友，大多会知道通过NLS_LANG来设置客户端的情况，NLS_LANG由以下部分组成：NLS_LANG=&lt; Language&gt;_&lt;Territory&gt;.&lt;Clients Characterset&gt;，其中第三部分&lt;Clients Characterset&gt;的本意就是用来指明客户端操作系统缺省使用的字符集。所以按正规的用法，NLS_LANG应该按照客户端机器的实际情况进行配置，尤其对于字符集一项更是如此，这样Oracle就能够在最大程度上实现数据库字符集与客户端字符集的自动转换（当然是如果需要转换的话）。<br /><b>总结一下第一次迭代的重点：</b><br /><b>字符集：</b>将特定的符号集编码为计算机能够处理的数值；<br /><b>字符集间的转换：</b>对于在源字符集与目标字符集都存在的符号，理论上转换将不会产生信息丢失；而对于在源字符集中存在而在目标字符集中不存在的符号，理论上转换将会产生信息丢失；<br /><b>数据库字符集：</b>选择能够包含所有将要存储的信息符号的字符集；<br /><b>客户端字符集设置：</b>指明客户端操作系统缺省使用的字符集。<br /><br />具体看：<a href="http://www.itpub.net/276524,1.html">http://www.itpub.net/276524,1.html</a></font>
		</span>
<img src ="http://www.blogjava.net/Duffblog/aggbug/77550.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Duffblog/" target="_blank">追球者</a> 2006-10-27 10:13 <a href="http://www.blogjava.net/Duffblog/articles/77550.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ORACLE汉字显示的字符集问题(转)</title><link>http://www.blogjava.net/Duffblog/articles/77539.html</link><dc:creator>追球者</dc:creator><author>追球者</author><pubDate>Fri, 27 Oct 2006 01:36:00 GMT</pubDate><guid>http://www.blogjava.net/Duffblog/articles/77539.html</guid><wfw:comment>http://www.blogjava.net/Duffblog/comments/77539.html</wfw:comment><comments>http://www.blogjava.net/Duffblog/articles/77539.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Duffblog/comments/commentRss/77539.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Duffblog/services/trackbacks/77539.html</trackback:ping><description><![CDATA[
		<span class="style6">
				<font color="#6f0003">在国内外大中型数据库管理系统中，把ORACLE作为数据库管理平台的用户比较多。ORACLE 不论是数据库管理能力还是安全性都是无可非议的，但是，它在汉字信息的显示方面着实给中国用户带来不少麻烦，笔者多年从事ORACLE数据库管理，经常收到周围用户和外地用户反映有关ORACLE数据库汉字显示问题的求援信，主要现象是把汉字显示为不可识别的乱码，造成原来大量信息无法使用。本文将就这一问题产生的原因和解决办法进行一些探讨，供存在这方面问题的用户朋友参考。 <br /><br /><strong>1、原因分析</strong><br /><br />通过对用户反映情况的分析，发现字符集的设置不当是影响ORACLE数据库汉字显示的关键问题。那么字符集是怎么一会事呢？字符集是ORACLE 为适应不同语言文字显示而设定的。用于汉字显示的字符集主要有ZHS16CGB231280，US7ASCII，WE8ISO8859P1等。字符集不仅需在服务器端存在，而且客户端也必须有字符集注册。服务器端，字符集是在安装ORACLE时指定的，字符集登记信息存储在ORACLE数据库字典的V$ NLS_PARAMETERS表中；客户端，字符集分两种情况，一种情况是sql*net 2.0以下版本，字符集是在windows的系统目录下的oracle.ini文件中登记的；另一种情况是sql*net 2.0以上（即32位）版本，字符集是在windows的系统注册表中登记的。要在客户端正确显示ORACLE 数据库汉字信息，首先必须使服务器端的字符集与客户端的字符集一致；其次是加载到ORACLE数据库的数据字符集必须与服务器指定字符集一致。因此，把用户存在的问题归纳分类，产生汉字显示异常的原因大致有以下几种： <br /><br />1. 1服务器指定字符集与客户字符集不同，而与加载数据字符集一致。 <br /><br />这种情况是最常见的，只要把客户端的字符集设置正确即可，解决办法见2.1。 <br /><br />1. 2服务器指定字符集与客户字符集相同,与加载数据字符集不一致。 <br /><br />这类问题一般发生在ORACLE版本升级或重新安装系统时选择了与原来服务器端不同的字符集，而恢复加载的备份数据仍是按原字符集卸出的场合,以及加载从其它使用不同字符集的ORACLE数据库卸出的数据的情况。这两种情况中，不管服务器端和客户端字符集是否一致都无法显示汉字。解决办法见2.2。 <br /><br />1.3服务器指定字符集与客户字符集不同,与输入数据字符集不一致。 <br /><br />这种情况是在客户端与服务器端字符集不一致时，从客户端输入了汉字信息。输入的这些信息即便是把客户端字符集更改正确，也无法显示汉字。解决办法见2.3。 <br /><br /><strong>2．解决办法</strong><br /><br />下面将分别对上述三种情况给出解决办法。为了叙述方便，假设客户端使用WINDOWS95/98环境，并已成功地配置了TCP/IP协议，安装了ORACLE的sql*net，sql*pluse产品。 <br /><br />2.1 设置客户端字符集与服务器端字符集一致 <br /><br />假设当前服务器端使用US7ASCII字符集。 <br /><br />（1）查看服务器端字符集 <br /><br />通过客户端或服务器端的sql*plus登录ORACLE的一个合法用户，执行下列SQL语句： <br /><br />SQL &gt; select * from V$NLS_PARAMETERS <br />parameter value <br />NLS_LANGUAGE AMERICAN <br />NLS_TERRITORY AMERICA <br />…. …. <br />NLS_CHARACTERSET US7ASCII <br />NLS_SORT BINARY <br />NLS_NCHAR_CHARACTERSET US7ASCII <br />从上述列表信息中可看出服务器端ORACLE数据库的字符集为'US7ASCII'。 <br /><br />（2）按照服务器端字符集对客户端进行配置 <br /><br />配置方法有两种： <br /><br />安装ORACLE的客户端软件时指定 <br />在安装ORACLE的客户端产品软件时，选择与ORACLE服务端一致的字符集（本例为US7ASCII）即可。 <br /><br />修改注册信息的方法 <br />根据ORACLE 客户端所选sql*net 的版本分为下列两种情况： <br /><br />a. 客户端为 sql*net 2.0 以下版本 <br /><br />进入Windows的系统目录，编辑oracle.ini文件，用US7ASCII替换原字符集，重新启动计算机，设置生效。 <br /><br />b. 客户端为 sql*net 2.0 以上版本 <br /><br />在WIN98 下 运 行REGEDIT,第一步选HKEY_LOCAL_MACHINE,第二步选择SOFTWARE， 第三步选择 ORACLE， 第四步选择 NLS_LANG， 键 入 与服 务 器 端 相 同 的 字 符 集（本例为：AMERICAN_AMERICAN.US7ASCII）。 <br /><br />2.2 强制加载数据字符集与服务器端字符集一致 <br /><br />假设要加载数据从原ORACLE数据库卸出时的字符集为US7ASCII，当前ORACLE服务器字符集为WE8ISO8859P1。 <br /><br /><span class="javascript" id="text1874350" style="FONT-SIZE: 12px"><font face="Verdana" color="#000000"> 有过一些Oracle使用经验的朋友，大多会知道通过NLS_LANG来设置客户端的情况，NLS_LANG由以下部分组成：NLS_LANG=&lt; Language&gt;_&lt;Territory&gt;.&lt;Clients Characterset&gt;，其中第三部分&lt;Clients Characterset&gt;的本意就是用来指明客户端操作系统缺省使用的字符集。所以按正规的用法，NLS_LANG应该按照客户端机器的实际情况进行配置，尤其对于字符集一项更是如此，这样Oracle就能够在最大程度上实现数据库字符集与客户端字符集的自动转换（当然是如果需要转换的话）。</font></span><br /><br />下面提供三种解决方法： <br /><br />（1） 服务器端重新安装ORACLE <br /><br />在重新安装ORACLE 时选择与原卸出数据一致的字符集（本例为US7ASCII）。 <br /><br />加载原卸出的数据。 <br /><br />这种情况仅仅使用于空库和具有同一种字符集的数据。 <br /><br />（2）强行修改服务器端ORACLE当前字符集 <br /><br />在用imp命令加载数据前，先在客户端用sql*plus登录system DBA用户，执行下列SQL语句进行当前ORACLE数据库字符集修改： <br /><br />SQL &gt; create database character set US7ASCII <br />* create database character set US7ASCII <br />ERROR at line 1: <br />ORA-01031: insufficient privileges <br />你会发现语句执行过程中，出现上述错误提示信息，此时不用理会，实际上ORACLE数据库的字符集已被强行修改为US7ASCII，接着用imp命令装载数据。等数据装载完成以后，shutdown 数据库，再startup 数据库，用合法用户登录ORACLE数据库，在sql&gt;命令提示符下，运行select * from V$NLS_PARAMETERS，可以看到ORACLE数据库字符集已复原，这时再查看有汉字字符数据的表时，汉字已能被正确显示。 <br /><br />（3）利用数据格式转储，避开字符集限制 <br /><br />这种方法主要用于加载外来ORACLE数据库的不同字符集数据。其方法如下： <br /><br />先将数据加载到具有相同字符集的服务器上，然后用转换工具卸出为foxbase 格式或access格式数据库，再用转换工具转入到不同字符集的ORACLE数据库中，这样就避免了ORACLE字符集的困扰。目前数据库格式转换的工具很多,象power builder5.0以上版本提供的pipeline，Microsoft Access数据库提供的数据导入/导出功能等。转换方法参见有关资料说明。. <br /><br />2.3匹配字符集替换汉字 <br /><br />对于1.3提到的情况，没有很好的办法，只能先把客户端与服务器端字符集匹配一致后，根据原输入汉字的特征码替换汉字字符部分。</font>
		</span>
<img src ="http://www.blogjava.net/Duffblog/aggbug/77539.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Duffblog/" target="_blank">追球者</a> 2006-10-27 09:36 <a href="http://www.blogjava.net/Duffblog/articles/77539.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Windows中查看端口占用的简单用法。</title><link>http://www.blogjava.net/Duffblog/articles/75703.html</link><dc:creator>追球者</dc:creator><author>追球者</author><pubDate>Tue, 17 Oct 2006 09:41:00 GMT</pubDate><guid>http://www.blogjava.net/Duffblog/articles/75703.html</guid><wfw:comment>http://www.blogjava.net/Duffblog/comments/75703.html</wfw:comment><comments>http://www.blogjava.net/Duffblog/articles/75703.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Duffblog/comments/commentRss/75703.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Duffblog/services/trackbacks/75703.html</trackback:ping><description><![CDATA[ 用这个命令，在DOS窗口执行：netstat -ano<br /><br />看看占用0.0.0:80端口的PID是多少<br /><br />然后在“任务管理器”中查到与该PID对应的程序。<br /><br />如果任务管理器的进程页中看不到PID栏，则在任务管理器的菜单〖查看〗〖选择列〗中选择一下<br />-----------------------------------------------------------------------------------------------------<br />好东西呀。。。。<br />netstat 这个命令太有用了。<img src ="http://www.blogjava.net/Duffblog/aggbug/75703.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Duffblog/" target="_blank">追球者</a> 2006-10-17 17:41 <a href="http://www.blogjava.net/Duffblog/articles/75703.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JVM的内存管理机制 java.lang.OutOfMemoryError: PermGen space </title><link>http://www.blogjava.net/Duffblog/articles/71676.html</link><dc:creator>追球者</dc:creator><author>追球者</author><pubDate>Mon, 25 Sep 2006 03:06:00 GMT</pubDate><guid>http://www.blogjava.net/Duffblog/articles/71676.html</guid><wfw:comment>http://www.blogjava.net/Duffblog/comments/71676.html</wfw:comment><comments>http://www.blogjava.net/Duffblog/articles/71676.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Duffblog/comments/commentRss/71676.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Duffblog/services/trackbacks/71676.html</trackback:ping><description><![CDATA[
		<p>PermGen space的全称是Permanent Generation space,是指内存的永久保存区域OutOfMemoryError: PermGen space从表面上看就是内存益出，解决方法也一定是加大内存。说说为什么会内存益出：这一部分用于存放Class和Meta的信息,Class在被Load的时候被放入PermGen space区域，它和和存放Instance的Heap区域不同,GC(Garbage Collection)不会在主程序运行期对PermGen space进行清理，所以如果你的APP会LOAD很多CLASS的话,就很可能出现PermGen space错误。这种错误常见在web服务器对JSP进行pre compile的时候。</p>
		<p>改正方法：-Xms256m -Xmx256m -XX:MaxNewSize=256m -XX:MaxPermSize=256m<br /><br />我已经试过了，ok。</p>
<img src ="http://www.blogjava.net/Duffblog/aggbug/71676.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Duffblog/" target="_blank">追球者</a> 2006-09-25 11:06 <a href="http://www.blogjava.net/Duffblog/articles/71676.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>IT从业人员必看的10个论坛(转)</title><link>http://www.blogjava.net/Duffblog/articles/68488.html</link><dc:creator>追球者</dc:creator><author>追球者</author><pubDate>Fri, 08 Sep 2006 05:13:00 GMT</pubDate><guid>http://www.blogjava.net/Duffblog/articles/68488.html</guid><wfw:comment>http://www.blogjava.net/Duffblog/comments/68488.html</wfw:comment><comments>http://www.blogjava.net/Duffblog/articles/68488.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Duffblog/comments/commentRss/68488.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Duffblog/services/trackbacks/68488.html</trackback:ping><description><![CDATA[
		<span id="ArticleContent1_ArticleContent1_lblContent">IT方面的论坛太多了，有综合，有专业，有行业，在各个论坛里混了几年，体会颇深，以前是论坛哪里人多，往哪里去，新浪论坛，网易是经常去的，人多啊，好几十万，去了以后才发现没有意思，没有共同的语言，于是逛专业论坛，行业论坛，终于找到了共同语言，总结一下论坛的经验：人不在多，有仙则灵，贴不在多，有精则行，逛了大半辈子，一个IT人发展方向一定要除了技术外，业务，理论，思想一个都不能少，于是我推荐如下这些论坛，或许真能帮助您，做论坛，都是赔本的买卖，不收费还帮助你学习，得向斑竹们致敬啊。 <br />　　<br />　　　　以下论坛排名不分先后，还有许多业界知名的论坛，主要有点偏门，这个不做概述，呵呵。 <br />　　<br />　　　　IT技术开发综合类 <br />　　<br />　　　　<a href="http://community.csdn.net/"><font color="#73af1d">http://community.csdn.net/</font></a><br />　　<br />　　　　适合人群：只适合软件开发者 <br />　　<br />　　　　技术开发最全面的论坛，里面可以遇到很多牛人，版面也很全，什么J2EE，.NET啊，该有的全上，在这里基本上可以提出任何问题，人气也是最旺的，不过一般提出的意见都有正方两面的，所以最终解决问题，还是靠自己。 <br />　　<br />　　　　评价：专业，很牛逼，就是速度慢。 <br />　　<br />　　　　<a href="http://www.itpub.net/"><font color="#73af1d">www.itpub.net</font></a><br />　　<br />　　　　适合人群：数据库开发人员 <br />　　<br />　　　　数据库方面是非常著名的，牛人不少，不过，现在比较杂，什么都做，网络，操作系统，行业应用，到体育贴图，当然有些也不错，人气非常高，特别是灌水方面，^_*. <br />　　<br />　　　　评价：强，速度一般； <br />　　<br />　　　　<a href="http://bbs.chinaunix.net/forum/"><font color="#73af1d">http://bbs.chinaunix.net/forum/</font></a><br />　　<br />　　　　适合人员：系统工程师 <br />　　<br />　　　　这里的特色就是操作系统方面在业界是最著名的，牛人不少，目前，在数据库，网络方面也颇有建树，当然灌水方面也不赖，呵呵，属于温柔性 <br />　　<br />　　　　评价：强，速度还可以 <br />　　<br />　　　　bbs.chinajavaworld.com/ <br />　　<br />　　　　适合人员：JAVA开发 <br />　　<br />　　　　JAVA方面非常综合的论坛了，牛人也很多，是一个难得的JAVA论坛，涉及你想象的关于JAVA目前任何技术。 <br />　　<br />　　　　评论：强，速度还可以。 <br />　　<br />　　　　<a href="http://www.huihoo.com/forum/"><font color="#73af1d">http://www.huihoo.com/forum/</font></a><br />　　<br />　　　　适合人员：中间件开发者 <br />　　<br />　　　　人气不错，版面风格独特，在开源，中间件，工作流方面非常不错，问题讨论都非常深刻、也很专业。 <br />　　<br />　　　　评价：很好，速度一般； <br />　　<br />　　　　IT售前技术顾问综合类 <br />　　<br />　　　　<a href="http://www.sysvs.com/bbs"><font color="#73af1d">http://www.sysvs.com/bbs</font></a><br />　　<br />　　　　适合人员：IT售前及技术顾问 <br />　　<br />　　　　业界知名的售前技术顾问论坛，比较新异的知识点，各个IT行业版快划分也比较好，也非常专业，绝对是我稀饭（喜欢）的风格，网站风格业内罕见，也有很多专业文章，没有地方灌水，厉害。 <br />　　<br />　　　　评价：很好，速度比较快 <br />　　<br />　　　　网络工程类 <br />　　<br />　　　　<a href="http://www.1000bbs.com/"><font color="#73af1d">www.1000bbs.com</font></a><br />　　<br />　　　　适合人员：布线/网络工程师 <br />　　<br />　　　　人气很旺，特色是版面比较紧凑，综合布线这一块很权威，很窄很专，时间非常久了，颜色比较明快，就是太低端了， <br />　　<br />　　　　评价：不错，速度一般 <br />　　<br />　　　　<a href="http://www.sharecenter.net/"><font color="#73af1d">http://www.sharecenter.net/</font></a><br />　　<br />　　　　适合人员：网络工程师 <br />　　<br />　　　　之所以我喜欢是这个网站很多做CISCO工程都知道，也是别人介绍我去的，时间非常久了，颜色比较暗谈，属于忧郁型。 <br />　　<br />　　　　评价：不错，速度也还可以 <br />　　<br />　　　　IT营销管理类 <br />　　<br />　　　　<a href="http://www.topren.net/forum/index.php"><font color="#73af1d">http://www.topren.net/forum/index.php</font></a>  <br />　　<br />　　　　适合人员：企业策划，CIO <br />　　<br />　　　　业界知名的知识站点“唐人社区”，信息化管理顾问可以去看看，人也很多，可惜，都是下载，实质性内容需要改观，我记得是非常专业的网站。 <br />　　<br />　　　　评价：不错，速度也还可以。 <br />　　<br />　　　　IT管理综合类 <br />　　<br />　　　　<a href="http://club.amteam.org/"><font color="#73af1d">http://club.amteam.org/</font></a><br />　　<br />　　　　适合人群：大多数， <br />　　<br />　　　　评论类比较多，基本上在其他媒体上看到的评论，这里都会有，要想了解IT发展的情况，就来这里看看。 <br />　　<br />　　　　评价：很好，休闲工作都可以看。 <!--文章结束--><br /><br /><a href="http://dev.csdn.net/article/72/72374.shtm">http://dev.csdn.net/article/72/72374.shtm</a></span>
<img src ="http://www.blogjava.net/Duffblog/aggbug/68488.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Duffblog/" target="_blank">追球者</a> 2006-09-08 13:13 <a href="http://www.blogjava.net/Duffblog/articles/68488.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在 Java 应用程序中计划重复执行的任务（转）</title><link>http://www.blogjava.net/Duffblog/articles/66679.html</link><dc:creator>追球者</dc:creator><author>追球者</author><pubDate>Wed, 30 Aug 2006 08:00:00 GMT</pubDate><guid>http://www.blogjava.net/Duffblog/articles/66679.html</guid><wfw:comment>http://www.blogjava.net/Duffblog/comments/66679.html</wfw:comment><comments>http://www.blogjava.net/Duffblog/articles/66679.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Duffblog/comments/commentRss/66679.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Duffblog/services/trackbacks/66679.html</trackback:ping><description><![CDATA[
		<div>
				<blockquote>所有类型的 Java 应用程序一般都需要计划重复执行的任务。企业应用程序需要计划每日的日志或者晚间批处理过程。一个 J2SE 或者 J2ME 日历应用程序需要根据用户的约定计划闹铃时间。不过，标准的调度类 <code><font face="新宋体">Timer</font></code> 和 <code><font face="新宋体">TimerTask</font></code> 没有足够的灵活性，无法支持通常需要的计划任务类型。在本文中，Java 开发人员 Tom White 向您展示了如何构建一个简单通用的计划框架，以用于执行任意复杂的计划任务。</blockquote>
				<p>我将把 <code><font face="新宋体">java.util.Timer</font></code> 和 <code><font face="新宋体">java.util.TimerTask</font></code> 统称为 <i>Java 计时器框架</i>，它们使程序员可以很容易地计划简单的任务（注意这些类也可用于 J2ME 中）。在 Java 2 SDK, Standard Edition, Version 1.3 中引入这个框架之前，开发人员必须编写自己的调度程序，这需要花费很大精力来处理线程和复杂的 <code><font face="新宋体">Object.wait()</font></code> 方法。不过，Java 计时器框架没有足够的能力来满足许多应用程序的计划要求。甚至一项需要在每天同一时间重复执行的任务，也不能直接使用 <code><font face="新宋体">Timer</font></code> 来计划，因为在夏令时开始和结束时会出现时间跳跃。 </p>
				<p>本文展示了一个通用的 <code><font face="新宋体">Timer</font></code> 和 <code><font face="新宋体">TimerTask</font></code> 计划框架，从而允许更灵活的计划任务。这个框架非常简单 —— 它包括两个类和一个接口 —— 并且容易掌握。如果您习惯于使用 Java 定时器框架，那么您应该可以很快地掌握这个计划框架。</p>
				<p>
						<a name="1.0">
								<span class="atitle2">计划单次任务</span>
						</a>
						<br />计划框架建立在 Java 定时器框架类的基础之上。因此，在解释如何使用计划框架以及如何实现它之前，我们将首先看看如何用这些类进行计划。</p>
				<p>想像一个煮蛋计时器，在数分钟之后（这时蛋煮好了）它会发出声音提醒您。清单 1 中的代码构成了一个简单的煮蛋计时器的基本结构，它用 Java 语言编写：</p>
				<a name="IDAFLSVB">
						<b>清单 1. EggTimer 类</b>
				</a>
				<br />
				<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#cccccc" border="1">
						<tbody>
								<tr>
										<td>
												<pre>
														<code>
package org.tiling.scheduling.examples;

import java.util.Timer;
import java.util.TimerTask;

public class EggTimer {
    private final Timer timer = new Timer();
    private final int minutes;

    public EggTimer(int minutes) {
        this.minutes = minutes;
    }

    public void start() {
        timer.schedule(new TimerTask() {
            public void run() {
                playSound();
                timer.cancel();
            }
            private void playSound() {
                System.out.println("Your egg is ready!");
                // Start a new thread to play a sound...
            }
        }, minutes * 60 * 1000);
    }

    public static void main(String[] args) {
        EggTimer eggTimer = new EggTimer(2);
        eggTimer.start();
    }

}
</code>
												</pre>
										</td>
								</tr>
						</tbody>
				</table>
				<p>
						<code>
								<font face="新宋体">EggTimer</font>
						</code> 实例拥有一个 <code><font face="新宋体">Timer</font></code> 实例，用于提供必要的计划。用 <code><font face="新宋体">start()</font></code> 方法启动煮蛋计时器后，它就计划了一个 <code><font face="新宋体">TimerTask</font></code>，在指定的分钟数之后执行。时间到了，<code><font face="新宋体">Timer</font></code> 就在后台调用 <code><font face="新宋体">TimerTask</font></code> 的 <code><font face="新宋体">start()</font></code> 方法，这会使它发出声音。在取消计时器后这个应用程序就会中止。</p>
				<p>
						<a name="2.0">
								<span class="atitle2">计划重复执行的任务</span>
						</a>
						<br />通过指定一个固定的执行频率或者固定的执行时间间隔，<code><font face="新宋体">Timer</font></code> 可以对重复执行的任务进行计划。不过，有许多应用程序要求更复杂的计划。例如，每天清晨在同一时间发出叫醒铃声的闹钟不能简单地使用固定的计划频率 86400000 毫秒（24 小时），因为在钟拨快或者拨慢（如果您的时区使用夏令时）的那些天里，叫醒可能过晚或者过早。解决方案是使用日历算法计算每日事件下一次计划发生的时间。而这正是计划框架所支持的。考虑清单 2 中的 <code><font face="新宋体">AlarmClock</font></code> 实现：</p>
				<a name="IDABNSVB">
						<b>清单 2. AlarmClock 类</b>
				</a>
				<p>
				</p>
				<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#cccccc" border="1">
						<tbody>
								<tr>
										<td>
												<pre>
														<code>
package org.tiling.scheduling.examples;

import java.text.SimpleDateFormat;

import java.util.Date;

import org.tiling.scheduling.Scheduler;
import org.tiling.scheduling.SchedulerTask;
import org.tiling.scheduling.examples.iterators.DailyIterator;

public class AlarmClock {

    private final Scheduler scheduler = new Scheduler();
    private final SimpleDateFormat dateFormat =
        new SimpleDateFormat("dd MMM yyyy HH:mm:ss.SSS");
    private final int hourOfDay, minute, second;

    public AlarmClock(int hourOfDay, int minute, int second) {
        this.hourOfDay = hourOfDay;
        this.minute = minute;
        this.second = second;
    }

    public void start() {
        scheduler.schedule(new SchedulerTask() {
            public void run() {
                soundAlarm();
            }
            private void soundAlarm() {
                System.out.println("Wake up! " +
                    "It's " + dateFormat.format(new Date()));
                // Start a new thread to sound an alarm...
            }
        }, new DailyIterator(hourOfDay, minute, second));
    }

    public static void main(String[] args) {
        AlarmClock alarmClock = new AlarmClock(7, 0, 0);
        alarmClock.start();
    }
}
</code>
												</pre>
										</td>
								</tr>
						</tbody>
				</table>
				<p>注意这段代码与煮蛋计时器应用程序非常相似。<code><font face="新宋体">AlarmClock</font></code> 实例拥有一个 <code><font face="新宋体">Scheduler</font></code> （而不是 <code><font face="新宋体">Timer</font></code>）实例，用于提供必要的计划。启动后，这个闹钟对<code><font face="新宋体"> SchedulerTask</font></code> （而不是 <code><font face="新宋体">TimerTask</font></code>）进行调度用以发出报警声。这个闹钟不是计划一个任务在固定的延迟时间后执行，而是用 <code><font face="新宋体">DailyIterator</font></code> 类描述其计划。在这里，它只是计划任务在每天上午 7:00 执行。下面是一个正常运行情况下的输出：</p>
				<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#cccccc" border="1">
						<tbody>
								<tr>
										<td>
												<pre>
														<code>
Wake up! It's 24 Aug 2003 07:00:00.023
Wake up! It's 25 Aug 2003 07:00:00.001
Wake up! It's 26 Aug 2003 07:00:00.058
Wake up! It's 27 Aug 2003 07:00:00.015
Wake up! It's 28 Aug 2003 07:00:00.002
...
</code>
												</pre>
										</td>
								</tr>
						</tbody>
				</table>
				<p>
						<code>
								<font face="新宋体">DailyIterator</font>
						</code> 实现了<code><font face="新宋体"> ScheduleIterator</font></code>，这是一个将<code><font face="新宋体"> SchedulerTask</font></code> 的计划执行时间指定为一系列 <code><font face="新宋体">java.util.Date</font></code> 对象的接口。然后 <code><font face="新宋体">next()</font></code> 方法按时间先后顺序迭代 <code><font face="新宋体">Date</font></code> 对象。返回值 <code><font face="新宋体">null</font></code> 会使任务取消（即它再也不会运行）—— 这样的话，试图再次计划将会抛出一个异常。清单 3 包含 <code><font face="新宋体">ScheduleIterator</font></code> 接口：</p>
				<a name="listing3">
						<b>清单 3. ScheduleIterator 接口</b>
				</a>
				<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#cccccc" border="1">
						<tbody>
								<tr>
										<td>
												<pre>
														<code>
package org.tiling.scheduling;

import java.util.Date;

public interface ScheduleIterator {
    public Date next();
}

</code>
												</pre>
										</td>
								</tr>
						</tbody>
				</table>
				<p>
						<code>
								<font face="新宋体">DailyIterator </font>
						</code>的 <code><font face="新宋体">next()</font></code> 方法返回表示每天同一时间（上午 7:00）的 <code><font face="新宋体">Date</font></code> 对象，如清单 4 所示。所以，如果对新构建的 <code><font face="新宋体">next()</font></code> 类调用 <code><font face="新宋体">next()</font></code>，那么将会得到传递给构造函数的那个日期当天或者后面一天的 7:00 AM。再次调用 <code><font face="新宋体">next()</font></code> 会返回后一天的 7:00 AM，如此重复。为了实现这种行为，<code><font face="新宋体">DailyIterator</font></code> 使用了 <code><font face="新宋体">java.util.Calendar</font></code> 实例。构造函数会在日历中加上一天，对日历的这种设置使得第一次调用 <code><font face="新宋体">next()</font></code> 会返回正确的 <code><font face="新宋体">Date</font></code>。注意代码没有明确地提到夏令时修正，因为 <code><font face="新宋体">Calendar</font></code> 实现（在本例中是 <code><font face="新宋体">GregorianCalendar</font></code>）负责对此进行处理，所以不需要这样做。</p>
				<a name="IDAHRSVB">
						<b>清单 4. DailyIterator 类</b>
				</a>
				<br />
				<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#cccccc" border="1">
						<tbody>
								<tr>
										<td>
												<pre>
														<code>
package org.tiling.scheduling.examples.iterators;

import org.tiling.scheduling.ScheduleIterator;

import java.util.Calendar;
import java.util.Date;

/**
 * A DailyIterator class returns a sequence of dates on subsequent days
 * representing the same time each day.
 */
public class DailyIterator implements ScheduleIterator {
    private final int hourOfDay, minute, second;
    private final Calendar calendar = Calendar.getInstance();

    public DailyIterator(int hourOfDay, int minute, int second) {
        this(hourOfDay, minute, second, new Date());
    }

    public DailyIterator(int hourOfDay, int minute, int second, Date date) {
        this.hourOfDay = hourOfDay;
        this.minute = minute;
        this.second = second;
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, hourOfDay);
        calendar.set(Calendar.MINUTE, minute);
        calendar.set(Calendar.SECOND, second);
        calendar.set(Calendar.MILLISECOND, 0);
        if (!calendar.getTime().before(date)) {
            calendar.add(Calendar.DATE, -1);
        }
    }

    public Date next() {
        calendar.add(Calendar.DATE, 1);
        return calendar.getTime();
    }

}
</code>
												</pre>
										</td>
								</tr>
						</tbody>
				</table>
				<p>
						<a name="3.0">
								<span class="atitle2">实现计划框架</span>
						</a>
						<br />在上一节，我们学习了如何使用计划框架，并将它与 Java 定时器框架进行了比较。下面，我将向您展示如何实现这个框架。除了 清单 3 中展示的 <code><font face="新宋体">ScheduleIterator</font></code> 接口，构成这个框架的还有另外两个类 —— <code><font face="新宋体">Scheduler</font></code> 和 <code><font face="新宋体">SchedulerTask</font></code> 。这些类实际上在内部使用 <code><font face="新宋体">Timer</font></code> 和 <code><font face="新宋体">SchedulerTask</font></code>，因为计划其实就是一系列的单次定时器。清单 5 和 6 显示了这两个类的源代码：</p>
				<a name="IDASSSVB">
						<b>清单 5. Scheduler</b>
				</a>
				<br />
				<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#cccccc" border="1">
						<tbody>
								<tr>
										<td>
												<pre>
														<code>
package org.tiling.scheduling;

import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class Scheduler {

    class SchedulerTimerTask extends TimerTask {
        private SchedulerTask schedulerTask;
        private ScheduleIterator iterator;
        public SchedulerTimerTask(SchedulerTask schedulerTask,
                ScheduleIterator iterator) {
            this.schedulerTask = schedulerTask;
            this.iterator = iterator;
        }
        public void run() {
            schedulerTask.run();
            reschedule(schedulerTask, iterator);
        }
    }

    private final Timer timer = new Timer();

    public Scheduler() {
    }

    public void cancel() {
        timer.cancel();
    }

    public void schedule(SchedulerTask schedulerTask,
            ScheduleIterator iterator) {

        Date time = iterator.next();
        if (time == null) {
            schedulerTask.cancel();
        } else {
            synchronized(schedulerTask.lock) {
                if (schedulerTask.state != SchedulerTask.VIRGIN) {
                  throw new IllegalStateException("Task already 
                  scheduled " + "or cancelled");
                }
                schedulerTask.state = SchedulerTask.SCHEDULED;
                schedulerTask.timerTask =
                    new SchedulerTimerTask(schedulerTask, iterator);
                timer.schedule(schedulerTask.timerTask, time);
            }
        }
    }

    private void reschedule(SchedulerTask schedulerTask,
            ScheduleIterator iterator) {

        Date time = iterator.next();
        if (time == null) {
            schedulerTask.cancel();
        } else {
            synchronized(schedulerTask.lock) {
                if (schedulerTask.state != SchedulerTask.CANCELLED) {
                    schedulerTask.timerTask =
                        new SchedulerTimerTask(schedulerTask, iterator);
                    timer.schedule(schedulerTask.timerTask, time);
                }
            }
        }
    }

}
</code>
												</pre>
										</td>
								</tr>
						</tbody>
				</table>
				<p>清单 6 显示了 <code><font face="新宋体">SchedulerTask</font></code> 类的源代码：</p>
				<a name="IDACTSVB">
						<b>清单 6. SchedulerTask</b>
				</a>
				<br />
				<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#cccccc" border="1">
						<tbody>
								<tr>
										<td>
												<pre>
														<code>
package org.tiling.scheduling;

import java.util.TimerTask;

public abstract class SchedulerTask implements Runnable {

    final Object lock = new Object();

    int state = VIRGIN;
    static final int VIRGIN = 0;
    static final int SCHEDULED = 1;
    static final int CANCELLED = 2;

    TimerTask timerTask;

    protected SchedulerTask() {
    }

    public abstract void run();

    public boolean cancel() {
        synchronized(lock) {
            if (timerTask != null) {
                timerTask.cancel();
            }
            boolean result = (state == SCHEDULED);
            state = CANCELLED;
            return result;
        }
    }

    public long scheduledExecutionTime() {
        synchronized(lock) {
         return timerTask == null ? 0 : timerTask.scheduledExecutionTime();
        }
    }

}
</code>
												</pre>
										</td>
								</tr>
						</tbody>
				</table>
				<p>就像煮蛋计时器，<code><font face="新宋体">Scheduler</font></code> 的每一个实例都拥有 <code><font face="新宋体">Timer</font></code> 的一个实例，用于提供底层计划。<code><font face="新宋体">Scheduler</font></code> 并没有像实现煮蛋计时器时那样使用一个单次定时器，它将一组单次定时器串接在一起，以便在由 <code><font face="新宋体">ScheduleIterator</font></code> 指定的各个时间执行 <code><font face="新宋体">SchedulerTask</font></code> 类。</p>
				<p>考虑 <code><font face="新宋体">Scheduler</font></code> 上的 public <code><font face="新宋体">schedule()</font></code> 方法 —— 这是计划的入口点，因为它是客户调用的方法。通过调用 <code><font face="新宋体">ScheduleIterator</font></code> 接口的 <code><font face="新宋体">next()</font></code>，发现第一次执行 <code><font face="新宋体">SchedulerTask</font></code> 的时间。然后通过调用底层 <code><font face="新宋体">Timer</font></code> 类的单次 <code><font face="新宋体">schedule()</font></code> 方法，启动计划在这一时刻执行。为单次执行提供的 <code><font face="新宋体">TimerTask</font></code> 对象是嵌入的 <code><font face="新宋体">SchedulerTimerTask</font></code> 类的一个实例，它包装了任务和迭代器（iterator）。在指定的时间，调用嵌入类的 <code><font face="新宋体">run()</font></code> 方法，它使用包装的任务和迭代器引用以便重新计划任务的下一次执行。<code><font face="新宋体">reschedule()</font></code> 方法与 <code><font face="新宋体">schedule()</font></code> 方法非常相似，只不过它是 private 的，并且执行一组稍有不同的 <code><font face="新宋体">SchedulerTask</font></code> 状态检查。重新计划过程反复重复，为每次计划执行构造一个新的嵌入类实例，直到任务或者调度程序被取消（或者 JVM 关闭）。</p>
				<p>类似于 <code><font face="新宋体">TimerTask</font></code>，<code><font face="新宋体">SchedulerTask</font></code> 在其生命周期中要经历一系列的状态。创建后，它处于 <code><font face="新宋体">VIRGIN</font></code> 状态，这表明它从没有计划过。计划以后，它就变为 <code><font face="新宋体">SCHEDULED</font></code> 状态，再用下面描述的方法之一取消任务后，它就变为 <code><font face="新宋体">CANCELLED</font></code> 状态。管理正确的状态转变 —— 如保证不对一个非 <code><font face="新宋体">VIRGIN</font></code> 状态的任务进行两次计划 —— 增加了 <code><font face="新宋体">Scheduler</font></code> 和 <code><font face="新宋体">SchedulerTask</font></code> 类的复杂性。在进行可能改变任务状态的操作时，代码必须同步任务的锁对象。</p>
				<p>
						<a name="3.1">
								<span class="atitle3">取消任务</span>
						</a>
						<br />取消计划任务有三种方式。第一种是调用 <code><font face="新宋体">SchedulerTask</font></code> 的 <code><font face="新宋体">cancel()</font></code> 方法。这很像调用 <code><font face="新宋体">TimerTask</font></code> 的 <code><font face="新宋体">cancel()</font></code>方法：任务再也不会运行了，不过已经运行的任务<i>仍会</i>运行完成。 <code><font face="新宋体">cancel()</font></code> 方法的返回值是一个布尔值，表示如果没有调用 <code><font face="新宋体">cancel()</font></code> 的话，计划的任务是否还会运行。更准确地说，如果任务在调用 <code><font face="新宋体">cancel()</font></code> 之前是 <code><font face="新宋体">SCHEDULED</font></code> 状态，那么它就返回 <code><font face="新宋体">true</font></code>。如果试图再次计划一个取消的（甚至是已计划的）任务，那么 <code><font face="新宋体">Scheduler</font></code> 就会抛出一个 <code><font face="新宋体">IllegalStateException</font></code>。</p>
				<p>取消计划任务的第二种方式是让 <code><font face="新宋体">ScheduleIterator</font></code> 返回 <code><font face="新宋体">null</font></code>。这只是第一种方式的简化操作，因为 <code><font face="新宋体">Scheduler</font></code> 类调用 <code><font face="新宋体">SchedulerTask</font></code> 类的 <code><font face="新宋体">cancel()</font></code>方法。如果您想用迭代器而不是任务来控制计划停止时间时，就用得上这种取消任务的方式了。</p>
				<p>第三种方式是通过调用其 <code><font face="新宋体">cancel()</font></code> 方法取消整个 <code><font face="新宋体">Scheduler</font></code>。这会取消调试程序的所有任务，并使它不能再计划任何任务。</p>
				<p>
						<a name="4.0">
								<span class="atitle2">扩展 cron 实用程序</span>
						</a>
						<br />可以将计划框架比作 UNIX 的 <code><font face="新宋体">cron</font></code> 实用程序，只不过计划次数的规定是强制性而不是声明性的。例如，在 <code><font face="新宋体">AlarmClock</font></code> 实现中使用的 <code><font face="新宋体">DailyIterator</font></code> 类，它的计划与 <code><font face="新宋体">cron</font></code> 作业的计划相同，都是由以 <code><font face="新宋体">0 7 * * *</font></code> 开始的 <code><font face="新宋体">crontab</font></code> 项指定的（这些字段分别指定分钟、小时、日、月和星期）。</p>
				<p>不过，计划框架比 <code><font face="新宋体">cron</font></code> 更灵活。想像一个在早晨打开热水的 <code><font face="新宋体">HeatingController</font></code> 应用程序。我想指示它“在每个工作日上午 8:00 打开热水，在周未上午 9:00 打开热水”。使用 <code><font face="新宋体">cron</font></code>，我需要两个 <code><font face="新宋体">crontab</font></code> 项（<code><font face="新宋体">0 8 * * 1,2,3,4,5</font></code> 和<code><font face="新宋体"> 0 9 * * 6,7</font></code>）。而使用 <code><font face="新宋体">ScheduleIterator</font></code> 的解决方案更简洁一些，因为我可以使用复合（composition）来定义单一迭代器。清单 7 显示了其中的一种方法：</p>
				<a name="IDA51SVB">
						<b>清单 7. 用复合定义单一迭代器</b>
				</a>
				<br />
				<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#cccccc" border="1">
						<tbody>
								<tr>
										<td>
												<pre>
														<code>
    int[] weekdays = new int[] {
        Calendar.MONDAY,
        Calendar.TUESDAY,
        Calendar.WEDNESDAY,
        Calendar.THURSDAY,
        Calendar.FRIDAY
    };
    int[] weekend = new int[] {
        Calendar.SATURDAY,
        Calendar.SUNDAY
    };
    ScheduleIterator i = new CompositeIterator(
        new ScheduleIterator[] {
            new RestrictedDailyIterator(8, 0, 0, weekdays),
            new RestrictedDailyIterator(9, 0, 0, weekend)
        }
    );
</code>
												</pre>
										</td>
								</tr>
						</tbody>
				</table>
				<p>
						<code>
								<font face="新宋体">RestrictedDailyIterator</font>
						</code> 类很像 <code><font face="新宋体">DailyIterator</font></code>，只不过它限制为只在一周的特定日子里运行，而一个 <code><font face="新宋体">CompositeIterator</font></code> 类取得一组 <code><font face="新宋体">ScheduleIterator</font></code>s，并将日期正确排列到单个计划中。</p>
				<p>有许多计划是 <code><font face="新宋体">cron</font></code> 无法生成的，但是 <code><font face="新宋体">ScheduleIterator</font></code> 实现却可以。例如，“每个月的最后一天”描述的计划可以用标准 Java 日历算法来实现（用 <code><font face="新宋体">Calendar</font></code> 类），而用 <code><font face="新宋体">cron</font></code> 则无法表达它。应用程序甚至无需使用 <code><font face="新宋体">Calendar</font></code> 类。在本文的源代码中，我加入了一个安全灯控制器的例子，它按“在日落之前 15 分钟开灯”这一计划运行。这个实现使用了 Calendrical Calculations Software Package ，用于计算当地（给定经度和纬度）的日落时间。</p>
				<p>
						<a name="5.0">
								<span class="atitle2">实时保证</span>
						</a>
						<br />在编写使用计划的应用程序时，一定要了解框架在时间方面有什么保证。我的任务是提前还是延迟执行？如果有提前或者延迟，偏差最大值是多少？不幸的是，对这些问题没有简单的答案。不过在实际中，它的行为对于很多应用程序已经足够了。下面的讨论假设系统时钟是正确的（有关网络时间协议(Network Time Protocol)的信息）。</p>
				<p>因为 <code><font face="新宋体">Scheduler</font></code> 将计划委托给 <code><font face="新宋体">Timer</font></code> 类，<code><font face="新宋体">Scheduler</font></code> 可以做出的实时保证与 <code><font face="新宋体">Timer</font></code> 的一样。<code><font face="新宋体">Timer</font></code> 用 <code><font face="新宋体">Object.wait(long)</font></code> 方法计划任务。当前线程要等待直到唤醒它，唤醒可能出于以下原因之一：</p>
				<ol>
						<li>另一个线程调用对象的 <code><font face="新宋体">notify()</font></code> 或者 <code><font face="新宋体">notifyAll()</font></code> 方法。 </li>
						<li>线程被另一个线程中断。 </li>
						<li>在没有通知的情况下，线程被唤醒（称为 <i>spurious wakeup</i>，Joshua Bloch 的 <i>Effective Java Programming Language Guide</i> 一书中 Item 50 对其进行了描述 ）。 </li>
						<li>规定的时间已到。 </li>
				</ol>
				<p>对于 <code><font face="新宋体">Timer</font></code> 类来说，第一种可能性是不会发生的，因为对其调用 <code><font face="新宋体">wait()</font></code> 的对象是私有的。即便如此，<code><font face="新宋体">Timer</font></code> 实现仍然针对前三种提前唤醒的原因进行了保护，这样保证了线程在规定时间后才唤醒。目前，<code><font face="新宋体">Object.wait(long)</font></code> 的文档注释声明，它会在规定的时间“前后”苏醒，所以线程有可能提前唤醒。在本例中，<code><font face="新宋体">Timer</font></code> 会让另一个 <code><font face="新宋体">wait()</font></code> 执行（<code><font face="新宋体">scheduledExecutionTime - System.currentTimeMillis()</font></code>）毫秒，从而保证<i>任务永远不会提前执行</i>。</p>
				<p>任务是否会延迟执行呢？会的。延迟执行有两个主要原因：线程计划和垃圾收集。</p>
				<p>Java 语言规范故意没有对线程计划做严格的规定。这是因为 Java 平台是通用的，并针对于大范围的硬件及其相关的操作系统。虽然大多数 JVM 实现都有公平的线程调度程序，但是这一点没有任何保证 —— 当然，各个实现都有不同的为线程分配处理器时间的策略。因此，当 <code><font face="新宋体">Timer</font></code> 线程在分配的时间后唤醒时，它实际执行其任务的时间取决于 JVM 的线程计划策略，以及有多少其他线程竞争处理器时间。因此，要减缓任务的延迟执行，应该将应用程序中可运行的线程数降至最少。为了做到这一点，可以考虑在一个单独的 JVM 中运行调度程序。</p>
				<p>对于创建大量对象的大型应用程序，JVM 花在垃圾收集（GC）上的时间会非常多。默认情况下，进行 GC 时，整个应用程序都必须等待它完成，这可能要有几秒钟甚至更长的时间（<code><font face="新宋体">Java</font></code> 应用程序启动器的命令行选项 <code><font face="新宋体">-verbose:gc</font></code> 将导致向控制台报告每一次 GC 事件）。要将这些由 GC 引起的暂停（这可能会影响快速任务的执行）降至最少，应该将应用程序创建的对象的数目降至最低。同样，在单独的 JVM 中运行计划代码是有帮助的。同时，可以试用几个微调选项以尽可能地减少 GC 暂停。例如，增量 GC 会尽量将主收集的代价分散到几个小的收集上。当然这会降低 GC 的效率，但是这可能是时间计划的一个可接受的代价。</p>
				<p>
						<a name="5.1">
								<span class="atitle3">我被计划到什么时候？</span>
						</a>
						<br />如果任务本身能监视并记录所有延迟执行的实例，那么对于确定任务是否能按时运行会很有帮助。<code><font face="新宋体">SchedulerTask</font></code> 类似于<code><font face="新宋体"> TimerTask</font></code>，有一个 <code><font face="新宋体">scheduledExecutionTime()</font></code> 方法，它返回计划任务最近一次执行的时间。在任务的 <code><font face="新宋体">run()</font></code> 方法开始时，对表达式 <code><font face="新宋体">System.currentTimeMillis() - scheduledExecutionTime()</font></code> 进行判断，可以让您确定任务延迟了多久执行（以毫秒为单位）。可以记录这个值，以便生成一个关于延迟执行的分布统计。可以用这个值决定任务应当采取什么动作 —— 例如，如果任务太迟了，那么它可能什么也不做。在遵循上述原则的情况下，如果应用程序需要更严格的时间保证，可参考 Java 的实时规范。</p>
				<p>
						<a name="6.0">
								<span class="atitle2">结束语</span>
						</a>
						<br />在本文中，我介绍了 Java 定时器框架的一个简单增强，它使得灵活的计划策略成为可能。新的框架实质上是更通用的 <code><font face="新宋体">cron</font></code> —— 事实上，将 <code><font face="新宋体">cron</font></code> 实现为一个 <code><font face="新宋体">ScheduleIterator</font></code> 接口，用以替换单纯的 Java <code><font face="新宋体">cron</font></code>，这是非常有用的。虽然没有提供严格的实时保证，但是许多需要计划定期任务的通用 Java 应用程序都可以使用这一框架。</p>
				<p>下载本文中使用的 <a href="http://www.dingl.com/src/java/j-schedule.zip"><u>源代码</u></a>。<br /><br /><a href="http://www.dingl.com/view.shtml?xh=362">http://www.dingl.com/view.shtml?xh=362</a></p>
		</div>
<img src ="http://www.blogjava.net/Duffblog/aggbug/66679.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Duffblog/" target="_blank">追球者</a> 2006-08-30 16:00 <a href="http://www.blogjava.net/Duffblog/articles/66679.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java虚拟机的 10 年(转)</title><link>http://www.blogjava.net/Duffblog/articles/66677.html</link><dc:creator>追球者</dc:creator><author>追球者</author><pubDate>Wed, 30 Aug 2006 07:56:00 GMT</pubDate><guid>http://www.blogjava.net/Duffblog/articles/66677.html</guid><wfw:comment>http://www.blogjava.net/Duffblog/comments/66677.html</wfw:comment><comments>http://www.blogjava.net/Duffblog/articles/66677.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Duffblog/comments/commentRss/66677.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Duffblog/services/trackbacks/66677.html</trackback:ping><description><![CDATA[Java虚拟机的起源与构造<br />当我们说到“Java”这个词的时候，指的是四个相互关联的概念：Java语言、Java API、Java Class文件格式、Java虚拟机。整个Java体系是基于Java 虚拟机构造的，正因为如此，才能实现Java的安全性和网络移动性。Java并非是第一个采用“虚拟机”概念的体系，但却是第一个得到广泛运用的虚拟机平台。 “虚拟”，是一种隔离物理资源与逻辑资源的手段。Java虚拟机的“虚拟”，则是用来隔离物理机器、底层操作系统与Java语言规范实现的手段。<br />虽然Java是一种面向对象的语言，我们平时大量使用的，是对象间的多态、组合(Composition)、委派（Delegation）,但当我们讨论虚拟机的时候，我们看见的基本概念却是“栈(Stack)”和“堆(Heap)”。根据冯诺依曼的“存储计算”模型，所有的代码都保存在代码空间中，随着程序计数器指针的变化进行程序的执行、跳转。Java虚拟机中没有寄存器的概念，方法调用是采用“栈”进行的，这是一种安全、简洁的方法。<br />Java虚拟机通过类装载器支持对类的隔离，这也是Java实现安全性的基础。每个类都具有自己的命名空间，在具有不同安全级别的沙箱中运行，因此不会产生低安全级别的代码来越权访问高级别代码的机会。类装载器的出现是Java虚拟机与大部分用C实现的虚拟机的显著不同之处。<br />Java虚拟机的另外一个显著特点就是实现了自动的垃圾收集。在往常，写程序的时候要牢记对象之间的关联，在每个程序块中假若申请了对象空间，就必须在出口释放掉，方法调用往往同时也就是对象的边界。而自动垃圾收集带给开发者的最大好处，就是可以非常方便地从整体上把系统的对象组织成一张对象图，只需往这张图中添加对象，维护对象之间的关联，却不需要自己做复杂的清扫工作。正是有了这种思维单纯的对象图的支持，OR Mapping(关系数据库与对象映射）技术在最近得以大行其道，设计模式也更容易被Java群体所接受。<br /><br />虚拟机的优化<br />1995年第一代的Java出台之时，其虚拟机执行是依靠“字节码解释器（Byte Code Interceptor）”的，也就是说每条指令都由虚拟机来当场解释执行，这造成速度令人抓狂地缓慢。更有甚者有人开始总结许多的“速度优化经验”，比如说：“尽量把所有的代码都放在较大的方法中执行”与“少用接口”等等，这完全与Java语言的设计目的背道而驰，现在看起来是多么可笑的奇谈怪论，当时却是很多程序员津津乐道的经验之谈。无他，Java本身执行太慢了。Java生命的前十分之三就是如此缓慢地渡过的。<br />于是，Sun的工程师开始拼命想着提高执行速度。JIT静态编译器的出现是在1996年十月，Sun放出了第一个编译器。JIT编译器在每段代码执行前进行编译，编译的结果为本地静态机器码，执行速度有了质的提高。Symantec公司当时凭借其傲人的JIT编译器，在整个Java界受到热烈的追捧。在其后的1998年，Java 1.2发布的时候，附带了JIT编译器，从此Java的使用者终于可以抛开上面说的那些奇怪的“速度优化经验”了。<br />JIT静态编译器虽然可以解决一些问题，但是性能仍然和C/C++有很大的差距。对一段程序而言，一名优秀的程序员是如何来改进运行速度的呢？首先，他不会傻到把所有的代码都来优化，他会观察、思考到底哪段代码对整体性能影响最大？然后集中精力来优化这一段代码。按照经验，整个程序 10%-20%的代码，会占据 80%-90%的运行时间。用这种方法，在同样的时间、付出同样程度的努力后，这名优秀的程序员使整个程序的性能得到了很大程度的优化。HotSpot引擎，就是模仿人工的这种方法进行优化的。在程序运行的开始，Java代码仍然解释执行，但HotSpot引擎开始进行采样(Profiling)。根据采样的结果，决定某段程序是占用较多运行时间的，就认为它是“HotSpot”，它也就是目前程序的瓶颈， 引擎开始启动一个单独的线程进行优化。因为不象原始的 JIT编译器那样无差别的编译所有代码，HotSpot引擎可以集中精力来对HotSpot代码进行深度优化，这样这部分代码执行起来更加迅捷。之前的静态编译器只能按照预定的策略进行编译优化，而HotSpot引擎的优化是基于采样的结果的，因此这种方法对所有的应用程序都有效。1999年3月27日，Sun放出了第一个HotSpot引擎。在随后的2000年5月的JDK 1.3中，包含了HotSopt引擎，这也使1.3成了一个具有里程碑意义的发行版本。到这里，Java的十年生命，已经过去了一半。<br />HotSpot代表的是一种动态编译的技术。对Java这种大量使用委派、组合等面向对象特性的程序来说，动态编译比起静态编译来有显著的优势。比如Method Inlining。方法的调用是一个很耗时的操作，假若可以把方法调用直接内嵌到调用者的代码中，就可以节省大量的时间， 这被称为“Method Inlining”。因为涉及到类的重载，静态优化很难确切知道哪些属性、方法被重载，因此很难对method进行合并，只好在方法内部进行静态编译，假若每个方法都很小，静态优化能起到的作用也就比较小。而动态编译因为可以完全随时掌握类的重载情况，就可以把相关的方法合并进行深度优化。现代的Java程序，特别是在设计模式教育得到普及之后，大量使用类的继承、委派，形成了很多短小的方法，动态编译的优势就更加明显。<br />自从出现了HotSpot之后，整个Java界为之一振。<br />最近的五年，就是继续优化的五年。继续进行优化的方法有几条路，一是研究新的采样算法。因为采样关系到不同的优化策略，会对整体性能有比较大的影响。二是研究深度优化的方法。三是研究垃圾收集的算法。垃圾收集会带来程序短暂的停顿，这会带来负面的用户体验。于是，如何提高垃圾收集的效率，减少延迟，出现了五花八门的算法，比如渐进式收集、火车算法等。在多处理器的时候，如何利用多处理器进行并行收集也是研究的一个热点。这方面，BEA的JRocket走在了前面。<br /><br />现实生活中的虚拟机<br />最后，让我们来盘点一下目前市面上可见的各个虚拟机。<br />首先要提到的，毫无疑问是Sun的虚拟机。作为大众心目中的“官方实现”，Sun拥有最大的用户群，并且拥有“兼容基准”的地位，其他虚拟机都必须要考虑和Sun虚拟机的兼容性问题。比如 JRocket就会在某些特殊情况下表现出和Sun不同的特性，可能对程序运行有影响。不过Sun也的确没有让广大用户失望，虽然在早期性能比不上Symantec,后来在1.2 的时候性能又被IBM超越，但Sun一直在努力革新，特别是 1.4.2之后，性能有了长足的进步。虽然JDK 1.5的虚拟机在性能上没有什么提高，但是增强了稳定性，据说修改了8000处bug，真是让人汗流不止。原来我们在1.4.2下面一直在享受这么多bug啊。<br />其次是老牌劲旅IBM。IBM的JDK在1.3的时代创下了最好的性能记录，从此树立了高端形象。特别是在其WebSphere产品中得到了很好的评价。其JDK也是最早支持64bit的JDK之一。到了现在，IBM JDK在高端仍然是和BEA可以一拼的。<br />然后是后起之秀，BEA的JRocket。说到BEA突然在JVM领域一夜之间异军突起，多少让人有些瞠目，不过它采取的战略特别简单：自己没有，索性花钱买了在此领域深有研究的JRocket，在前面加上BEA的标志就可以了。JRocket瞄准高端服务器市场，在多处理器环境下有不俗的表现。<br />除此之外，还有几个开放源代码的JVM值得一提。首先就是大名鼎鼎的JikesRVM。说起其大名，大多数人都知道Jikes编译器是 IBM开发的，效率比同等的javac编译器高得多，很多开发者都使用Jikes编译器来取代javac。而JikesRVM则是IBM开源出来的一整套虚拟机技术，包含了JIT，GC的完整实现，在其网站上也有众多的论文，实在是想要深入研究JVM者的绝佳资源([url]http://jikesrvm.sourceforge.net)[/url]。<br />Kaffe是一个老牌的JVM,不过现在已经很少听到了。作者撰写此文时，[url]www.kaffe.org[/url]网站已经没有响应，也不知道现在的情况如何了。<br />GNU则有两个计划：GCJ和GNU classpath。GNU classpath是一个底层实现，而GCJ是支持java的预编译器。<br /><br />结束语<br />时光流转，轰轰烈烈的Java虚拟机性能争论仿佛还在耳边回响，现在新的争论却已经是“Java的性能是否已经超越C/C++”。Joakim Dahlstedt 是 JRockit 的主要架构设计师之一，他坚持认为，Java绝不是一种速度慢，效率低的语言，JVM 是一个关键的组件，确保了系统的部署与运行和开发一样快速、轻松。特别是在目前开发趋势是采用大量预制的框架时，动态编译有可能比C/C++这样的静态优化获得更好的性能。<br /><br /><br />J2EE五年: 从起源到目的<br />文/刘天北<br /><br /><br />起点<br />在“J2EE”这个缩略语被第一次介绍给世人的时刻，也许没有几个人可以预料出它在日后的奇特历程。那是在1999年6月的JavaOne年会上，时任Sun公司Java企业开发部门主管的Mala Chandra兴奋地预告了Java世界的这位新成员。那些不熟悉背景的听众们，揣摩着她演说中出现的一串串全新术语，表情大概又是惊喜、又是迷惑:一个完整的“多层企业开发架构”、以“容器”和“组件”的形式提供服务、一套“厂商中立的开放技术规范”、对开发者隐藏了不同平台和“中间件”的技术细节、实现了企业级应用间的“无缝集成”等等。在今天的开发者看来，这些似乎都已经是老生常谈，但在当时的场景下，闪动在幻灯片上的每一个口号，都意味着听众们事后又要经历一段困难的学习过程。<br />幸亏Chandra有一副了不起的口才；这位本科念建筑学的印度裔高层主管，谈起软件架构来也有特强的空间想象力。她清晰地说明了设计J2EE架构的两个初衷：首先，对于厂商，J2EE意味着一套开放标准，加入这个标准，他们的产品就可以运行在各种不同的操作系统和工作环境下，成为一个成熟的企业运算体系中可替换的部件；其次，对于开发者，J2EE是一套现成的解决方案，采用这个方案，企业应用开发中的很多技术难题（包括跨平台移植、事务处理、安全性等等）就会迎刃而解，“信息像一条不间断的河流，经过各种各样的平台和设备，从企业应用系统的这一端流向那一端”。<br />要想理解这段话在当时的实际效应，我们仍然要把时间指针拨回1999年。除了预备迎接千年虫之外，99年你做了什么？为了回答这个犀利的问题，我翻出6年前的工作记录，发现了自己那时参与的一个项目的规格说明书，它正好能提供一幅“Java企业开发”在1999年的标准照。这是一家日本知名IT厂商的企业信息管理系统，运行在NetScape 3.0 Gold浏览器中的Java Applet界面，通过一个专用的中间层系统与Oracle 8数据库连接。这个中间层已经相当现成、完善，能够提供远程对象调用、事务处理等一系列的底层服务；留给我们的任务只是完成服务器端业务对象代码，以及相应的客户端交互开发。<br />除了Applet客户端有些特别之外，上述系统与今天常见的J2EE架构很接近；尤其是业务对象编码也由home类、PK（主键）类、entity类等部分构成，很多机制都与EJB如出一辙——只不过这些类并没有继承javax.ejb包的接口，而是采用了专用的API。它与EJB之间的相似不像是偶然的，设计者肯定参照了Sun在1997年底推出的EJB 1.0技术规范。<br />换言之，在J2EE诞生伊始的语境中，市面上已经存在着很多程度不一的“准J2EE中间件”了。它们主要用于解决三大类问题：事务处理、分布式对象管理和Web请求处理。首先，事务处理管理器（Transaction Processing Monitor）一直是高端企业计算领域的热门产品，著名的应用服务器厂商BEA，正是通过收购事务处理软件Tuxedo进入中间件市场的。另一方面，从90年代初开始，越来越多的人把“N层分布式对象架构” 当成传统的客户端/服务器架构的替代方案。那时刚刚兴起的CORBA技术是推动这一趋势的重要力量（比如说，前面提到的那个由日本厂商自行开发的专用中间层，就采用了CORBA作为基础架构）。最后，Java技术在Web领域中的应用也是当时初露头角的热点。1997年6月，Sun在发布一款“Java Web Server”的同时第一次公布了Servlet API；没想到这项技术副产品（连同1998年问世的JSP）正好迎合了厂商的战略需要。对于上面提到的N层架构来说，HTTP服务是一个非常理想的前端；所以基于Java的Web引擎，也在此时成了企业级Java解决方案的一个必不可少的部分。<br />Java、Web、事务、分布式对象，这几股开发潮流汇合在一处，形成了当时最热门的产品“应用服务器（Application Server）”或“中间件（Middleware）”。为了给定语“最热门”作个注释，我们可以参照一下BEA公司在1998年收购Web应用服务器厂商Weblogic的成交价：1.92亿美元。而这并不是一桩孤立的收购，NetScape和Sun也以相近的价格买下了另外两家企业Kiva和NetDynamics。而这也正是J2EE规范出台的背景：几乎所有要厂商都推出了、或是正在赶制自己的应用服务器产品，但这个“应用服务器”究竟应该是什么东西，竞争者们又各有表述、莫衷一是。<br />说到这里，我们才梳理出了J2EE技术规范的第一个版本在1999年12月问世的实际意义。首先，它为Java企业开发提供了一幅清晰的全景，各项分支技术在这个领域中的地位和作用得到了客观、准确的定义。至此大家才对一个Java企业解决方案的构成要素有了基本共识。其次，它使用“容器”和“组件”等概念描绘了Java企业系统的一般架构，明确地划分了中间件厂商和应用开发者的职责所在。最后（但绝非最不重要地），J2EE通过一套公开标准规定了应用服务器产品的具体行为，在执行此标准的厂商产品之间实现了一定程度的可替换性和互操作性。当时的媒体用“B2B开发的默认标准”之类的说法欢呼这项里程碑式的成就——那些撰稿人哪里知道，在J2EE与那个被称为“B2B” 的短命新贵之间，其实并不会有太多故事发生；同样，他们也不会想到，J2EE要想成为一种真正成熟的开发范式，前方还有一段远为艰辛的旅程。<br /><br />社区的形成<br />记得Kruglinski在名著《Inside Visual C++》的某个版本中给出了一个Web浏览器的代码例子；在这一节的开头他说到：如果你几年前开发了一个Web浏览器，那肯定会给你带来上千万的收益；但如果你现在才想到开发这个东西——那也就是个C++语言的练习罢了。在今天的程序员眼中，应用服务器似乎也成了价格低廉（如果不是全然免费）的日用消费品。所以，想要理解它们在那几年的大行其道，就非得借助Kruglinski这样的智慧不可。在1999年底，市面上可以找到30种以上自称“Java应用服务器”的产品，可见当时这类软件是网络风险投资的宠儿。但是此时出台的J2EE规范就像是一阵席卷整个产业的劲风，在一夜之间，所有人都有了判断什么是一个“应用服务器”的权威途径。<br />为了获得一张J2EE竞技场的入场券，各家厂商面临两项考验：首先，要具有能够覆盖J2EE中所有主要技术的产品线。这在当时是一项非常苛刻的要求，在没有开源产品可供参照的情况下，短时间内推出包括EJB容器、Web引擎和JMS中间件的整体解决方案，这决不是随便哪家创业公司都能办到的。完成了若干次成功的并购之后，BEA在这一点上抢占了先机，完整的产品线使它成了人们心目中的首选J2EE平台提供商。其次，要让产品通过Sun的J2EE兼容性测试。要做到这一点同样不易：就连IBM的WebSphere也一时还没达到百分之百的EJB支持。到2000年底为止，共有15家厂商能够提供完整的J2EE解决方案，其中9家（包括Sun本身）实现了“J2EE兼容”，他们中间包括了日后这个领域的主要竞争者。毫无疑问，这是一次非常残酷的行业洗牌，但留在场内的厂商也相应地形成了推动J2EE发展的主体力量。<br />上面说过，在它的孵化阶段，Sun的J2EE团队主管是女强人Mala Chandra，她本人虽不是工程师出身，但对技术有着很强的感知能力和想象力；J2EE一出台就能够为人们提供一幅完整、直观而不失深邃的图景，此中当然有Chandra本人的大量贡献。在她直接领导下工作的几位工程师，也都是Sun内部非常杰出的人才。无论是制定了JDBC、JMS等规范的Mark Hapner、JavaMail的设计者Bill Shannon，还是EJB的主要设计者Vlada Matena，后来都是业界一言九鼎的技术领袖。这个班子的合作时间并不太长：2000年左右的那个时期正是IT界创业的黄金年月，Chandra很快就和Sun公司Java部门的总裁（也是创造Java的功臣之一）Alan Baratz一起，到一家刚起步的Email中间件公司Zaplet淘金去了；捷克裔的开发天才Matena也离开Sun开办了自己的公司。留下的两个人Hapner和Shannon先后担任了J2EE技术的首席设计师。<br />多年以后，Hapner回忆起J2EE初创的那个时期，深感如今Sun对Java的左右能力已经大不如前：“现在，Java事实上属于整个技术社区，它的发展有赖全体参与者的推动。”的确，如今Sun已经不太可能重演当年的开拓性功绩，很难再为一个已经成形的领域重绘版图。但正如上文所说，即使是在1999年，J2EE设计者们面对的也不是一张从未着墨的白纸。他们的设计始终要以各大厂商的现有产品为出发点，这也是天才的设计师们做出的设计却远非完美的原因之一：与从头设计一门全新的编程语言不同，J2EE规范从一开始就是各方博弈和妥协的产物。<br />很容易注意到，J2EE与Java社区的决策机制JCP（Java Community Process）是几乎同步产生的。J2EE下属的各种技术规范，包括1.4版之后的J2EE本身，都作为待决规范议案（JSR，Java Specification Request）被纳入了JCP的议程。这些议案的审议过程很少是一帆风顺的，几乎每一个都要经历18个月以上的拉锯战。在多项技术规范的审议过程中，我们都见到了这样的现象：最初列名审议委员会的某家主要厂商，没能等到该规范通过就已经被收购或倒闭了。与微软在.NET平台上的乾刚独断相比，J2EE发展中的这个“牛步”特征虽说是审慎和民主的表现，但终归不符合软件演化应有的速度。<br />J2EE社区中的另一股重要力量，当然是种类极为丰富的开放源代码项目。2002年以来，在J2EE领域的各个层面上，几乎所有主流产品都有来自开源项目的替代方案，在其中很多位置上，开源产品反而是胜过商业产品的首选。但请别误解，这里的“开源”并不意味着完全的自动自发，J2EE世界中的开源项目也与Linux或PHP世界颇为不同。在很多非常成功的J2EE开源项目背后，我们都能发现商业机构的推动作用：Apache的Jakarta社区是IBM扶植的结果；实现了开源应用服务器JOnAS的ObjectWeb，则是许多法国IT厂商（包括若干政府部门）合资支持的一个联盟组织……这些有商业背景的开源项目资金雄厚，人员齐整；更重要的是，从投资者到开发者，参与这些项目的很多人都体现了软件工业中难得的非功利心态，因而最终推出的产品质量甚至高于同类型的商业软件。在主流厂商之外，它们是支撑J2EE大厦存在的一组基石。<br />另一方面，不少开发者也间接地通过自己的开源产品获得了可观的盈利。这些人大多以免费的开源产品为依托，以收费方式提供附加的咨询、方案实施以及技术支持服务。Marc Fleury，开源应用服务器的JBoss创始人，不无矛盾地把自己倡导的这种商业模式称为“职业开源开发”。<br />无论叫它什么，高端产品的开源化/免费化运动注定要在J2EE产业的发展过程中制造显著的后果。“JBoss的行径恶化了J2EE的商业环境，”这是McNealy先生2002年的著名论断。他的推理过程如下：只有做好商业推广，J2EE产品才能最终击溃邪恶的.NET平台；但开源服务器会降低主流厂商的销售利润；销售利润越低，用于商业推广的预算就越少；因此，整个J2EE阵营都将受损于JBoss。<br />但在狂热的开源运动支持者看来，以上论证的大前提就是可疑的。“难道只有会做广告的软件才是好软件？MySQL有过多少广告预算”争论的双方都认为对手误解了软件商业模型的实质。究竟谁才掌握了这里的真理呢？也许只有根据J2EE的未来——也就是它的目标和终点（Telos）——才能做出最终的裁决。<br /><br />技术的离心力<br />考察事物的演化，通常有两种对立的方法。考古学家（Archaeologist）探究肇始和起源；目的论者（Teleologist）则揭示目的和终点。对于前者，“开端（希腊语Arche）”从根本上决定了此后的发展，参天大树的繁茂都包含在种子最初的萌芽中；而对于后者，“目的（Telos）”才是事物的根本和旨归：谁没见过样态完善的树，谁也就没法弄懂种子到底是怎么回事。<br />在J2EE五年之后，人们只能交替地用这两种目光审视它的演化历程。它的起源与它的目的、“它从何处来”与“它往何处去” 的问题紧密地交织在一起，谁拾起了其中的一个，谁也就要连同另一个一起回答。<br />今天的J2EE在多大程度上符合它的初衷？回答这个问题并不涉及对J2EE技术成败的评判，而只是要考察一下：它是否还运行在最初开辟的那个空间之中。在事务处理、对象分布化和Web请求处理这三个方面中，也许J2EE对事务和Web保持了一贯的忠诚。我们记得Fleury喜欢重复的一个信条:“He who owns the transactional Web owns the Web（谁掌握了带事务处理的Web，谁就掌握了Web）”Web接口是今天大部分J2EE应用暴露的唯一接口；而虽然事务处理的常用方法已经有了很大改变（借助AOP机制，很多非EJB架构的系统也自如地实现了声明式的事务处理），但对事务的重视当然仍将是J2EE开发中的要素之一。<br />换言之，在5年的演化中，J2EE发生的最大变化可能就在于它放弃了对“分布式对象模型”的强调。EJB2.0引入的本地接口使得Web层与EJB层可以运行在同一个Java虚拟机中，从而使Web容器与EJB容器的物理分离部署变成一种昂贵的冗余；J2EE 1.4以后版本支持的Web Services兼容性，使得客户端可以通过粗粒度的Web接口调用远程服务——这两次变化事实上都是在论证“分布式对象架构”的无用性。人们发现，同一系统的各个分层最好采用细粒度接口调用，并且运行在同一个进程中；之所以划分不同的层次，与其说是为了实现物理上的可扩展性，不如说是设计美学上的考虑。而对于异质系统之间的调用，则应该尽量选用异步的、粗粒度的服务接口（所以Web Services成为了非常理想的选择）。换句话说，传统上的“分布式对象架构”，现在看来似乎只适合于银行远程支付等要求极为苛刻的应用场景，而绝不是所有J2EE应用都该考虑的标准方案。<br />前面描述的离心现象毕竟还遵循了J2EE发展的内在逻辑，说到底，EJB的革新和Web Services的引入更多地是主流厂商倡导的结果。但在近年来，还有一股更强劲的离心潮流在深刻地影响着J2EE的演进，它肇始于上文提到的开源软件运动。最初它只在Rickard Oberg的动态代理RMI设计与JBoss服务器的微内核架构中显露过邪恶的一角，但是两三年来，经过多个项目、各种技术杂志/论坛/Blog的折射和放大，它已经形成了一个名为“轻量级容器架构”的完整解决方案，并暴露出完全取代传统EJB架构的终极野心。按照这一运动信徒们的说法，J2EE的发展史上只出现过一个错误——不幸的是，这个错误名叫EJB。与EJB提供的重量级架构不同，借助AOP和IoC机制，轻量级容器能够最大程度地降低代码对于专用接口的依赖性，以简短、轻便、专注、可移植的方式实现业务对象。从“轻量级容器架构”这个词被发明出来的那一刻起，人们对J2EE远景的考虑就发生了根本性的分裂：Sun和大部分主流厂商更多地关注于“Web Services”和“快速开发工具”这些利润增长点，而一部分离经叛道的独立专家和开发者则认为，如果不把轻量级容器纳入规划，J2EE的发展蓝图就注定无足称道。其实，双方争执的关键是传统意义上的“应用服务器”的存亡——如果所有企业级服务都可以通过AOP机制提供给普通Java对象，如果管理业务对象生命周期的可以是一个最微不足道的“微内核”，那么深盔重铠的应用服务器还有什么存在理由？而如果失去了应用服务器的这个产品类型，那些靠这项销售起家的厂商又将何以自处？<br />正是在这里，两个阵营之间存在着最深刻的利益分歧；而这场争执的结局当然也将决定J2EE（乃至Java企业开发）的最终走向。或许两年之后，我们将从纷争中胜利者一方的角度重述J2EE的整部历史——或许两年之后的J2EE本身也将随着纷争的解决而成为历史。但让我们换个乐观的口吻：问世五年，J2EE的历史仍在持续的创生之中；此时善待这树种的人，也必在今后的树荫下获得它的祝福。<br /><br />Java十年有成<br />——谈J2ME的发展历史<br />文/王森<br /><br /><br />Java本来就是为了嵌入式系统而生<br />1990年12月，Sun内部由James Gosling、Patrick Naughton以及Mike Sheridan成立了一个叫做Green Team的小组。Green Team小组的主要目标，是要发展一种新架构，而这种架构必须能够在消费性电子产品作业平台上运行，现在我们普遍认识的PDA、手机或是信息家电(IA)，都是属于这种架构的目标平台。接着，Green Team在1992年的9月3号，发表了一款由Java 技术之父 James Gosling所领军研发，名叫Star Seven(*7)的机器，研发出一部交互式的掌上型家用娱乐装置，可透过使用动画触碰式屏幕的使用者接口来控制其它电子设备。<br />经过了13年的时间，现在我们检视J2ME的发展历史，我们可以发现，虽然在1999年，Java被切割成J2SE、J2ME、J2EE，所以有了J2ME这个名词的出现。但是Java并非1999年开始才开始发展嵌入式系统上的应用。其实，Java本来就是为了嵌入式系统而发展的一种架构。即使目前大家多半将Java的应用聚焦于企业上的J2EE应用。但是严格来说，J2ME才是Java真正“回归本心”的领域。<br /><br />半路杀出的Personal Java<br />Personal Java是正规Java版本的一个分支，其目的在于能够让PDA或高阶手机执行Java程序，目前在Windows Mobile或Symbian OS(仅限采用UIQ或Nokia Series 80的行动电话)平台上都可以开发Personal Java应用程序。<br />虽然从Java 1.0发表之后，Java就被广泛地使用在桌上型应用程序以及Applet的开发上，但是，从Java 1.1开始，Java又回到了它一开始的老路-也就是嵌入式系统方面的应用，在当时Sun Microsystems发表了Embedded Java与Personal Java（也有人简称为PJava）这两项规格。Personal Java的规格是从Java 1.1之中所分支出来，因此Personal Java的规格是根据Java 1.1的规格而制定的，但是并非Java 1.1的全部规格都包含进来，所以Personal Java只能算是Java 1.1平台的子集合。<br />Personal Java特别适合用在具有丰富图形显示能力的消费性电子产品上面，于是我们可以发现Sun Microsystems网站上对于Personal Java的参考实作是建立在Windows Mobile产品(过去叫做Pocket PC)上头的。<br />在1999年，一般PDA或手机的能力，离Personal Java所需要的硬件条件仍有很大的一段差距，因此Personal Java并不是一个很成功的产品。因此Sun Microsystems在此时将Java区分成J2SE、J2EE、J2ME这三块，希望可以重新塑造整个架构，尤其是J2ME，希望Java可以在嵌入式系统的领域有所发展。<br /><br />J2ME从何而来?<br />谈到J2ME，大家就会联想到KVM这个名词， KVM的设计者Antero Taivalsaari，最早在Sun Microsystems参与Spotless Project，这个项目才是J2ME的最早起源。由于Antero Taivalsaari曾经在世界知名电信设备制造商工作，所以他有了在手机上开发JVM的概念，后来得到公司支持，就有了各位所知的KVM(K Virtual Machine)。<br />最早应用KVM的产品，就是一个可以在Palm OS上执行的KJava。KJava并不算是一个正式产品，只能算是一个概念测试产品。开发人员会开发名为Spotlet的应用程序，透过工具和KVM的辅助，应用程序就可以在PDA上执行。虽然KJava早已成为过去式，但是仍有电信厂商使用这个名词，作为手机上Java平台的名称，不过，已经不是真正的KJava了。有了KJava的发展经验，Sun着手设计J2ME的架构，让J2ME可以应付未来嵌入式系统的发展。<br /><br />J2ME整体架构<br />J2ME最基本的规范制定在JSR-68(Java规格编号第68号)，在此规格里头定义了J2ME的技术架构。根据此规范，J2ME由三种类型的规范堆栈而成，分别是Configuration、Profile以及Optional Packages。这三种类型的规范定义由其它的规范所定义。<br />在最底层的Configuration规范，定义了硬件所必须具备的能力，比方说硬件至少具备多少ROM、RAM，CPU的频率最少应该是多少，连接网络时频宽至少要多快。Configuration规格之中定义了一组低阶的API，这代表Java至少必须提供的低阶功能，这组低阶的API就是核心类别函数库的子集合。<br />在Configuration之上的规范称为Profile。Profile针对各种不同机器的特性定义了高阶的API，这些高阶的API通常都是与其它平台不相关的扩充类别函数库。这些高阶API决定了该种机器上Java程序的撰写方法。比方说行动通讯装置(手机、PDA等)这类型装置上Java程序的撰写方式，以及能够调用的API，都定义在MIDP(Mobile Information Device Profile)之中。<br />就算是同类型的装置，有些功能也不一定具备(有些厂商的机器可能有，有些厂商的机器可能没有，例如手机上的照相机、和弦铃声等)，这些功能就定义在“厂商选择性实现套件(Optional Package)”之中，比方说，有的厂商会提供简单的数据库管理系统(DBMS)在该装置上，那么他们就会实现JDBC Optional Package。不提供数据库管理系统的厂商就不需要实现JDBC Optional Package。所以称作厂商选择性实现套件。<br />所谓的厂商选择性实现套件，意思是说，这是一组和其它规格(或API)没有任何相依性的类别函数库，如果厂商愿意提供这样的功能给程序设计师(通常是因为硬件具有充分的能力可以完成规格之中所制定的功能)，就会将这组类别函数库实现出来，程序设计师也可以利用这些功能开发出功能更多的应用程序。<br /><br />MIDP工业标准<br />虽然J2ME架构完整，但是目前的发展，除了Personal Profile之外，最大的应用在于架构在CLDC之上的MIDP。目前所有标示可以支持Java的手机，所支持的都是MIDP，几乎所有的无线通讯厂商皆采用MIDP作为其开发程序的标准。<br />在MIDP 1.0的时代，由于规格上本身的功能不足，使得许多厂商不得不加入自己专属的API，例如震动、背光、声音等扩充功能(例如:Nokia UI API)，以弥补MIDP平台的不足。<br />到了MIDP 2.0，增加了许多众所期盼的功能，但是，即使规格更清楚了，即使很多新功能都已经由JCP制定成标准的Optional Packages，这些问题依然无解。市面上的MIDP平台仍然处于混乱状态。开发者必须在执行时期侦测各种专属API和Optional Package的存在，这会增加多余的程序代码。平台的混乱会造成在某个装置上可以顺利安装及执行，而到了其它装置时，有可能无法执行，甚至有可能连安装都有问题，所以开发者通常要开发好几种版本的MIDP应用程序供各种厂牌、各种型号的装置使用。<br />为了解决上述问题，进一步提高MIDP应用程序的可移植性，Sun Microsystems以MIDP 2.0规格为核心，设计了JTWI规格。未来的无线通讯平台，将不会只有符合MIDP 2.0规格，而是必须要符合JTWI规格。这将是J2ME软件在可移植性上的一大突破。JTWI(Java Technology for Wireless Industry)是一个统合性的规格，其目的是为了确保MIDP软件的可移植性。所以JTWI规格除了规范无线通讯平台(特别是手机)所必须支持的J2ME标准之外，也对既有规格中模糊不清的地方与以加强。所以新款的手机为了加强移植性，都会支持JTWI标准。JTWI只是一个统合性的规范，并没有制定任何新功能，目的只是要统一当前平台混乱的现象，让J2ME应用程序更具可移植性。JTWI主要分成几个部分:<br />1 .规定平台必须支持的API。<br />2 .统一的应用程序执行环境。<br />3 .既有规格的理清与加强。<br />在规定平台必须支持的API的部分，JTWI规定至少必须支持CLDC 1.0、MIDP 2.0以及WMA 1.1:<br /><br />所以，只要厂商宣称支持JTWI平台，那么代表一定支持CLDC 1.0、MIDP 2.0以及WMA 1.1规格之中的所有功能。另外，厂商可以根据装置本身的能力，将CLDC 1.0提升成CLDC 1.1，可以加入MMAPI 1.1。因此实际上JTWI平台会有一下几种组合方式:<br />其中，CLDC 1.1 + MIDP 2.0 + WMA 1.1 + MMAPI 1.1是最完整、功能最强平台。<br />在统一应用程序执行环境方面，过去让J2ME应用程序开发者最为头大的问题有以下几项:<br />● 应用程序的大小可以多大? <br />● 执行时期的内存有多少可以使用?<br />● 有多少内存空间可以作为永久储存之用?<br />由于规范中对于J2ME应用程序本身的大小和执行环境没有很详细地规范，使得每家厂商都有自己的规范，比方说Nokia限制应用程序最大只能30 KB，Motorola则可以支持50 KB以上的应用程序。这些规范都严重地困扰着开发人员。这些问题在JTWI之中都获得改善。<br />JTWI定义了应用程序的标准大小(Standard-size Application)。JTWI规定，可以执行J2ME应用程序的行动通讯装置，至少可以容许大小为64 KB以上的程序主体(JAR文件)、5 KB以上的应用程序描述文件(JAD文件)、以及30 KB以上的永续储存空间、执行时期的内存(Heap Memory)为256 KB。上述大小只是底线，厂商可以视装置的实际能力支持更大的内存空间。标准应用程序大小(Standard-size Application)将成为一个计算用的单位，举例来说，厂商会说这个装置可以安装20个标准应用程序，开发者所撰写的程序可以说这个程序需要占掉3个标准应用程序的空间。<br />至于对既有规格的理清与加强的部分，我们将在往后章节一一说明。最重要的一点是，JTWI规定，该装置所支持的任何媒体格式(例如图片、声音、影像等)都应该能够使用HTTP 1.1获取，也就是说，存取这些媒体时所使用的URL都必须能够接受http作为存取的通讯协议。<br /><br /><br />Java开发环境的<br />过去、现在和将来<br />文/EclipseCN<br /><br /><br />1995年3月23日，San Jose Mercury News登出一篇题为“Why Sun thinks Hot Java will give you a lift”的文章，在那篇文章里预言Java技术将是下一个重大事件，这个预言现在看来并不仅仅是商家的宣传伎俩，虽然文章是当时Sun的公关经理 Lisa Poulson安排撰写的。从世人知道Java那一刻起到现在，算起来已经过去整整十年，回顾过去的十年值得总结的东西有许多，但在这里笔者只想就Java 开发环境谈些个人的想法与朋友们交流一下。<br />现在的软件开发人员在整个软件的开发生命周期里，也许会根据需要使用各式各样的开发工具来完成相对复杂的开发任务，而在几十年以前，人们还只是使用文本编辑器、编译器和Debugger进行开发，对于这个阶段的开发环境人们称之为CLEs(Command Line Environments)。 而当人们发现如果将那些单独分开的开发工具集成起来就可以有效的提高开发效率时，IDEs(Integrated Development Environments)就出现了。Java的出现尽管只有十年，但其开发环境也大至经历了从CLEs到IDEs再到XDEs这三个阶段，现在即将进入CDEs阶段。在上述Java开发环境发展过程中，有许多值得我们大家关注的地方。<br /><br />Java开发环境的历史回顾<br />纵观过去十年Java开发环境的发展，大致可以粗略的划分为如下几个阶段:<br />●  1995，命令行开发环境CLEs<br />●  1996-2000，集成开发环境IDEs <br />●  2001-2004，扩展开发环境XDEs <br />●  2005至今，协同开发环境CDEs <br />1995年，不平凡的一年，这一年Java 获得了成功。可令人尴尬的是在1995年并没有一个令人满意的Java开发环境，开发人员在进行Java编程时，大多使用文本编辑器编辑源程序，然后再使用命令行的方式进行编译处理。那时的Java开发环境还处于CLEs时代，开发效率非常低，这预示着在Java开发工具上会有一番激烈的竞争。<br />有人称1996年为互联网年，有人却称之为Java年，还有人称之为Web开发年，但不论如何称呼1996年，它都反映了一个事实：Bill Joy将Java与互联网相结合的策略取得了成功。这一年的9月Sun推出了其Java开发环境-Java WorkShop，这是一款基于浏览器的Java开发工具，但由于当时 Java在许多方面还不成熟，所以实际上Java WorkShop并不成功，同年发布的Symantec Visual Cafe由于还是采用C/C++语言进行开发，所以性能与成熟度上就比WorkShop好得多。提到Visual Cafe就不能不提Eugene Wang，因为Eugene Wang常常是与计算机间谍这个词同时出现的人物，有人甚至讲当时Symantec的老板Gordon Eubanks与Eugene Wang签约时，也同时签下了监狱里的一个单元。Visual Cafe就是由Eugene Wang进行主要策划的，它是在同一年发布的Java开发环境中，唯一解决了与数据库连接问题的开发环境，带有一套可以与数据库相连接的组件，无需太多编程使用拖拽的方式就可完成大部分工作，这一优点使得Visual Cafe受到了Java开发人员的欢迎。这一年IBM收购了OTI公司，从而得到了Dave Thomas的弟子John Duimovich、Dave Thomson、Mike Wilson等一大批软件精英，这之中还包括“生活在技术刀锋上的开发者”Brian Barry。<br />1997年，由于微软垄断案，使得微软在Java开发环境上的努力受到了限制，Visual Cafe由于界面直观易用，可以很容易地连接各种数据源等功能再次受到开发人员的欢迎。这一年IBM发布VisualAge for Java。VisualAge for Java是面向代码库的开发环境，它提供代码库和项目管理以便于开发团队在 C/S环境下进行项目开发。但由于大多数Java开发人员比较熟悉面向文件的开发环境，还不太习惯面向代码库的开发，再加上VisalAge for Java对系统资源的要求比较高等因素，使得VisualAge for Java一开始未被Java开发人员所认可。<br />1998年至2000年比较成功的Java开发环境是JBuilder，这是由于Borland较好的把握住 J2SE、J2EE和J2ME发布后，Java技术升级的时机，全面支持Java1.1和Java1.2开发平台，它还提供了多种工具方便用户从旧的平台迁移到新的Java平台。JBuilder本身80%是基于JDK1.2进行开发的，它支持JavaBeans, Enterprise JavaBeans, JDBC等方面的应用开发，可以连接多种关系数据库。为支持分布式应用开发，JBuilder还集成了 VisiBroker ORB、JSP server、数据库和EJB AppServer，并提供Open Tools API便于第三方工具集成。上述种种的优点使得JBuilder一举超越Visual Cafe，成为当时最受欢迎的Java开发环境。在众多Java开发环境中，1999年IBM发布的VisualAge for Java Micro Edition是比较有特色的开发环境，它是由Erich Gamma和与Erich Gamma有“焦不离孟、孟不离焦”之称的John Wiegand共同进行设计的，采用了Java 扩展机制，并集成了JUnit测试框架，其当时所采用的架构深深地影响了后来Eclipse1.0所采用的架构。同时，通过VisualAge for Java Micro Edition的开发，那些来自“未来世界”(Smalltalk们总认为他们来自计算机的未来世界)的软件精英们，全面彻底地对Java技术进行了评估，得出了许多结论性的东西，这之中包括现在闹得沸沸扬扬的Swing和SWT对比。此外，Sun将其收购的NetBeans变成了开源的Java IDE也是一件不大不小的事情。<br />纵观1996年至2000年这五年时间里，随着Java及其相关开发应用的发展，Java开发环境也不断的完善，从CLEs进入到IDEs阶段。为了提高Java开发人员的开发效率，Java开发环境主要从两个方面进行改进与提高。一方面是提高集成在Java IDEs当中开发工具的性能和易用性，另一方面是将Java开发环境尽可能的覆盖到整个软件的开发生命周期。随着基于WEB，采用N-层结构的应用开发成为Java开发人员主要从事的开发任务，Java开发环境需要支持越来越多的技术，比如:XML、JSP、EJB和CORBA等，这就造成了Java IDEs的规模变得越来越大，许多Java开发环境都集成了数据库、JSP Server和AppServer，软件的研究人员将上述IDEs不断膨胀的现象称为“IDEs大爆炸”。<br />“IDEs大爆炸”现象发生以后，有关Java开发环境是走少而精的发展方向，还是走大而全的发展方向就成了广大Java开发人员关注的问题。2001年Java开发人员达到了200万，成为每个软件供应商都无法忽视的力量，这一年JetBrains推出了Java开发环境少而精的代表： IntelliJ IDEA。 IntelliJ IDEA明确的表示只做最好的Java代码编辑器，不做什么文件都可以编写的编辑器。它关注Java开发人员的工作实际并将这些工作进行了优化。由于减掉了一些可有可无的工具，所以价格上相对合理公道。当年IntelliJ IDEA击败JBuilder成为最受Java开发人员欢迎的Java开发环境，不过2002年随着JBuilder将大而全的功力再提升一步，将UML建模工具、JUnit测试框架以及Apache Struts等开发工具集成进来，大而全的发展方向又一次受到Java开发人员追捧。最全还是最好似乎使Java开发人员在选择Java开发环境时处于两难状况，但实际上当Eclipse 1.0发布时，这个问题已经得到了初步的解决，最好和最全是可以兼顾的。<br />Eclipse的出现不是从天上掉下来的，也不是某个天才拍脑袋想出来的，它是一群软件精英们集体智慧的结果。早在1998年IBM就打算开发新一代的工具平台以便将它现有的各种开发工具统一起来，并减少开发各种工具时重复的劳动，同时希望在新的平台上建立新的Java开发环境。经过一段时间的准备， IBM开始建立起一个开发团队，人员构成主要来自VisualAge for Java Micro Edition和VisualAge for Java两个项目的开发人员，选择的标准是过去10年至少开发过5到6个IDE。此外，IBM还联合了9家公司共同成立了一个开源组织Eclipse基金会，将Eclipse提供给开发人员使用，并在开源社区的帮助下进一步完善Eclipse本身。Eclipse在最初设计时，插件模型是静态的，不能实现插件的即插即用功能，即便是大受欢迎的Eclipse 2.1也还是静态的。所以到2004年发布Eclipse 3.0时，Eclipse进行了重大改进，采用OSGi的插件模型，初步实现了插件的即插即用功能，至此一个完美的、可扩展的开发环境展现在Java开发者面前，这时Java开发人员已经达到300万。<br /><br />Java开发环境的现状<br />2004年Eclipse 3.0的发布极大刺激了Eclipse用户的增长，经过一年以后，Java开发人员现在使用Java开发环境的状况是如何的呢？看了下面的表格里的数据也许可以了解一个大致的状况。<br />首先需要指明的是上述的数据并不是当前Java用户使用Java开发环境的准确反映，但我们可以从中了解一个大致的状况。现在的Java环境可以分为三个集团，第一集团是Eclispe它大约占据1/3的份额，第二集团是 IntelliJ IDEA、NetBeans 和JBuilder占据另外1/3的份额，相互之间旗鼓相当，第三集团是以JDeveloper和WSAD为代表的十几种Java开发环境占据剩下的 1/3份额，但每种开发环境占总份额的比重不超过5%。我们考察Eclipse、intelliJ IDEA、NetBeans 和JBuilder这些主流开发环境，可以发觉它们有一个共同的特点那就是可扩展，尽管在实现手段上各有不同。这就是为什么称现在的Java开发环境为XDEs(eXtended Development Environments)的原因，IDEs已经死亡了4年，专业的开发人员需要了解这个事实，因为XDEs也快死了。<br />由于市场的压力，一个软件企业不仅要提高开发人员个体的工作效率，还要提高整个开发团队以及整个企业的开发效率，但在现有的Java开发环境XDEs下无法完全做到这些，所以新一代开发环境CDEs (Collaborative Development Environments)就产生。Grady Booch和Alan W. Brown的研究表明一个程序员一天工作时间的分配是这样的：分析占16%(从5%到40%不等)， 设计占14%(从1%到40%不等)，编程占16%(从0%到60%不等)，测试占10%，打电话占3%，阅读占7%(电子邮件，文档，月刊和杂志)，参加开发会议占10%，无关的会议占7% 。从这些数据可以发现，开发人员用于交流的时间约占工作时间的1/3，开发人员的相互交流非常重要。可是现有的主流Java开发环境一般仅将分析、设计、编程和测试等工具集成进来，却未包括用于交流的工具，这显然不合理。因此，所谓CDEs就是将用于人与人、人与团队以及团对于团队进行交流的工具集成进来的开发环境，比如，CDEs常具有发送电子邮件、进行及时通讯和屏幕分享等功能，通过实现无损耗过程的交流提高开发团队的开发效率。<br />现在已经商业化的CDEs是CodeBeamer Collaborative Development Platform和CodePro AnalytiX，上述两款软件都提供Eclipse的插件，可以与Eclipse集成在一起，使Eclipse升级成为一个CDEs。大家肯定知道Borland已经宣布开发基于Eclipse的新版JBuilder-“Peloton”，Peloton就是一个CDEs(Collaborative Development Environments)，当它明年上半年发布时，就意味着Java开发环境进入CDEs时代，现在Java开发环境还处于XDEs与CDEs交替的阶段。 <br /><br />Java开发环境的未来<br />在可以看得见的将来，Java的开发环境还会是以CDEs的形式存在。开源组织或开发工具供应商将会努力为软件的开发创建一个绝对光滑的平面 (Frictionless Surface)，实现无损耗的开发过程，以提高开发效率。为了实现无损耗的开发过程，Java的开发环境将会关注以下几个方面:<br />●  起步阶段方面 <br />●  协作开发方面 <br />●  维护开发团队有效沟通方面 <br />●  多个任务的时间协调方面 <br />●  相互协商方面 <br />●  资料有效性方面 <br />但这里必须承认未来Java开发环境是如何具体去实现无损耗的开发，还需要时间给与答案，因为现在所能采用的方法未必是最好的，比如，使用面向文件的 CVS进行协同开发就有需要改进的地方。<br /><br />总结<br />罗里罗唆一大堆，归纳起来不过就是:一个目的、三种手段以及一条规律。<br />一个目的:十年Java开发环境的演变，其目的就是为了提高开发效率。<br />三种手段:<br />●  提高集成在Java开发环境中开发工具的性能和易用性 <br />●  将Java开发环境尽可能的覆盖到整个软件的开发生命周期 <br />●  集成人与人、人与团队以及团对于团队进行交流的工具 <br />一条规律:软件开发环境的发展过程是从CLEs到IDEs再到XDEs最后进入CDEs，这是由Grady Booch总结出来的，套在Java开发环境上也适用。 <br /><br /><br />参考文献<br />◇ Grady Booch and Alan W. Brown, "Collaborative Development Environments",  Advances in Computers 59, Aug. 2003.<br />◇ Li-Te Cheng,Cleidson R. B. de Souza,Susanne Hupfer,John Patterson, Steven Ross, "Building Collaboration into IDEs", ACM Queue vol. 1, no. 9 - December/January 2003-2004<br />◇ J. des Rivie` res,J. Wiegand, "Eclipse: A platform for integrating development tools", IBM System Journal,Volume 43, Number 2, 2004<br />◇ The Java Extension Mechanism.<br />◇ Grady Booch, "History of Development Environments", January 29, 20<br /><br /><br />J2SE发展演变史<br />文/Matirx Java社区　杨洪波　王志舜<br /><br /><br />J2SE:怀胎<br />Java的历史可以追溯到1991年4月，Sun公司的James Gosling领导的绿色计划(Green Project)开始着力发展一种分布式系统结构，使其能够在各种消费性电子产品上运行，他们使用了C/C++/Oak语言。由于多种原因，绿色计划逐渐陷于停滞状态。<br />直至 1994年下半年，由于Internet的迅猛发展和环球信息网的快速增长，第一个全球信息网络浏览器Mosaic诞生了；此时，工业界对适合在网络异构环境下使用的语言有一种非常急迫的需求;Games Gosling决定改变绿色计划的发展方向，他们对Oak进行了小规模的改造，就这样，Java在1995年的3月23日诞生了！Java的诞生标志着互联网时代的开始，它能够被应用在全球信息网络的平台上编写互动性及强的Applet程序，而1995年的Applet无疑能给人们无穷的视觉和脑力震荡。<br />但没有相应的开发库而只靠Java语言来进行开发肯定是困难重重，所以Sun公司在1996年的1月23日发布了JDK 1.0来帮助开发人员的开发。JDK包括两大部分:运行环境和开发工具。紧跟着，Sun公司在1997年2月18日发布了JDK 1.1。JDK1.1相对于旧版本最大的改进，是推出了JIT(Just-In-Time)编译器，另外一个改进是AWT 1.1。<br />在JDK 1.1时代，Java平台分为PersonalJava与EmbeddedJava，前者比较适用于运算资源和内存丰富的设备，而资源有限者适用于后者。这样的分类明显不符合时代发展的潮流，所以，Java平台处处蕴藏着新的翻天覆地的革命……<br /><br />J2SE1.2:诞生<br />JDK 1.2在1998年12月4日的隆重发布，标志着Java2平台的诞生。Java 2的J2SE 1.2时代是一个大变革时代，它进行了如下的三大革命:<br /><br />● 市场推广革命<br />Sun公司在Java 1.2版以后将JDK 1.2改名为J2SDK，将Java改名为Java 2。在1999年Sun公司还将Java 2平台分为三大块:J2SE，J2EE，J2ME。这次市场推广革命顺应了网络急速发展的潮流，对Java 2平台的发展起到了很好的催化剂的作用。<br /><br />● API供应标准革命<br />而随着供应商的不同，Java的API分为三大类:<br />Java Core API:由Sun公司制定的基本的API，所有的Java平台都应该提供。<br />Java Optional API:由Sun公司制定的扩充API，Java平台可以有选择地提供。<br />特殊API:由特殊厂商或者组织提供的API。<br /><br />● API制定过程的革命<br />如果你有需求不能通过遵循标准的API来实现,可以向JCP提出制定新的API的请求,经过审核,你的请求可能被通过或者驳回;如果是被通过,则开始进入制定该API的程序。<br />J2SE 1.2时代进行的这些革命形成的制度一直沿用到现在,对Java技术的发展形成了深远的影响。<br />除了上述的三大革命，Java 2还支持并新增了许多新特性，最受追捧的当属Swing库。Swing是轻量级的API，它不但有各式各样先进的组件，而且连组件风格都可抽换。Swing出现之后，大家很快地就不太使用AWT了。Java 2还废弃了一些API，最重要的莫过于Thread类中对suspend(),resume()和stop()等方法的废弃。由于JDK 1.1的集合类库中的Vector类和HashTable类都考虑了同步，在平常的使用中影响效率，所以Java 2专门添加了对应的非同步类，并完善了集合类库。<br /><br />J2SE1.3:拓广<br />Java 2平台推出后，得到了市场的强烈反响，所以，在2000年5月8日推出的J2SE 1.3对J2SE 1.2的改进，主要是对各种已有API的加强和对新API的拓展。<br />数字运算:加入了java.lang.StrictMath,方便我们的一般的数字运算。<br />新的Timer API:相信大家对其中的java.util.Timer和java.util.TimerTask一定不陌生。<br />Collections包:加入了一些新的API，方便我们的使用。<br />虚拟机停止钩子:J2SE 1.3还加入了一个强大的功能，那就是虚拟机停止钩子(Virtual Machine Shutdown Hooks)，这个功能使得我们能够在虚拟机停止时完成我们自己的操作，比如关闭网络连接或者保存会话状态或者清除临时文件等等。<br />DNS服务:在JNDI接口方面，加入了一个DNS服务的实现。<br />Jini实现:J2SE 1.3包含了一个Jini实现，这使得我们可以方便地把诸如打印机、摄像机和磁盘驱动设备插入现有网络中，并且能自动搜索已在网上的设备可以提供的服务并享用这些服务。<br />XML支持：由于计算机网络和XML技术的快速发展， J2SE 1.3在Optional API中引入了Java API for XML包。<br />HotSpot虚拟机:J2SE 1.3引入了HotSpot虚拟机。在Solaris版的JDK 1.3中，已经不支持传统的虚拟机，而Windows版的JDK 1.3同时支持传统虚拟机和HotSpot虚拟机。<br />从上面的分析可以看出，J2SE 1.3主要是对J2SE 1.2查漏补缺和拓展新的API。从应用领域方面考虑，J2SE 1.3已经涵盖了数据库、WEB、多媒体、网络、电话、影像、加解密、图形等等大部分的信息技术领域。<br />在这个时期Java 2还有一个重要活动就是推出SCSL(Sun社区源代码许可)许可协议。Sun公司开放源代码项目的“女1号”Danese Cooper在1999年加入公司，负责Sun（包括Java）和开放源代码社区之间的协调工作。Sun一直尽可能在赢利和开放源代码之间寻求更好的平衡。<br />Java的大行其道引起了Microsoft的警惕并直接导致了.Net的产生，这同时也宣布了Java作为独一无二的Internet平台地位的结束。这两个对手在较量中相互学习，现在在技术架构上的目标上已趋相同。<br /><br />J2SE 1.4:快速<br />J2SE 1.4平台的推出发生在2002年2月13日，由于此前在Java平台和.NET平台间发生了规模浩大的孰优孰劣的论战，而论战中，Java平台最大的缺点就是性能问题，所以J2SE 1.4平台把性能的改善放在了最重要的位置。<br />HotSpot虚拟机:HotSpot虚拟机能够很大程度上提高性能，所以J2SE 1.4已经不支持传统的虚拟机。现在，启动应用程序应该通过-client或者-server选项来启动。 <br />锁机制:由于旧版的HotSpot虚拟机的锁机制会导制严重的性能和功能问题，J2SE 1.4已经改写了该锁机制。<br />安全API:JCE、JSSE和JAAS这三大安全API从optional API移到了core API中。这样，J2SE 1.4的安全域(SecureRandom)实现可以利用操作系统提供的安全机制，以便缩短应用程序的启动时间。<br />RandomAccess标记接口:加入了RandomAccess标记接口，如果一个List实现了该接口，则表示它支持快速的随机访问，这样可以提高List访问的速度。<br />LinkedHashMap:加入了LinkedHashMap，这是一个插入排序的Map实现，但它的运行速度和HashMap一样快。<br />反射:很多产品中都要使用反射(Reflection)机制，但大家知道，反射是相当耗时的，所以，J2SE 1.4中重写了java.lang.reflect.Field、java.lang.reflect.Method.invoke()、java.lang.reflect.Constructor.newInstance()和Class.newInstance()等方法，使得我们利用反射也能写出高性能的应用程序。<br />64位计算:J2SE 1.4支持64位计算。<br />新的I/O API:J2SE 1.4在API层面最大的变动，就是它更新了原有的java.io包，以及加入了一组更有效率更多功能的New I/O API。<br />断言和日志处理:J2SE 1.4版本在Java语言层面上加入了断言（assert关键字），在API层面上加入日志处理API，这些为程序的调试提供了强有力的支持。<br />从上面的分析可以看出，Java 2平台在经过数年的发展后，已经比较成熟稳定，J2SE 1.4主要是对平台的性能进行较多的考虑和修改。在分布式程序方面，1.4版比1.3版的运行效率提高了一半以上；而在客户端程序方面，1.4版比1.3版的效率提高了1/3。<br />J2SE 1.4版是J2SE第一个参与了 Java共同体过程(JCP)的J2SE版本。 像Borland、Compaq、Fujitsu、 SAS、 Symbian、 IBM这样的公司，和Sun一起定义并发展了J2SE 1.4规范。在开放、良好的文档编撰与管理的过程中，形成了一个高质量的、代表了Java共同体的多样性的规范。<br /><br />J2SE5.0:易用<br />在2004年十月J2SE 5.0发布的时候，Sun公司这样解释这次版本名称不是J2SE 1.5而是J2SE 5.0的原因：“从Java诞生至今已有9年时间，而从有J2SE算起也有5个年头了；在这样的背境下，将该版本号从1.5改为5.0可以更好的反映出新版的J2SE的成熟度、稳定性、可伸缩性、安全性。”<br />J2SE的这次变更之重大和意义之深远，的确也值得我们为之把版本号变换到J2SE 5.0。我们再看看Sun公司网站对J2SE 5.0的features描述:“通过增强Java平台的力量，允许开发者更容易地使用，Java编程语言的这些改进将吸引大量各种Java开发者”，这是“Java技术发展历程的一个重要里程碑” 。从这个描述我们可以看出，J2SE 5.0最大的目标是通过提供易用性而吸引各种开发者(当然包括以前的C/C++开发者) ，而它对以前版本的修改并不仅仅是API的升级，而且包括对Java语言层面的改进，被誉为是”自Java问世以来的最大一次语言标准变化”。<br />访问环境变量:最初的Java语言有一个访问环境变量的方法System.getenv()，但因为Java宣称的”Write Once,Run AnyWhere”特性，所以在JDK 1.0中去掉了这个能够访问平台专有信息的方法。在J2SE 5.0中，它又来了，并有所扩充。由此可见J2SE 5.0对编程方便性的重视程度。<br />泛型:J2SE 5.0提供了强大的泛型机制，让程序员可以减少代码重复，这个变化应该可以吸引小部分的C#开发人员吧。<br />增强的for循环:为了克服普通for循环的代码臃肿特点，J2SE 5.0提供了增强的for循环，我们现在可以这样写一个for循环:<br /><br />public void printAll(Collection coll)<br />{<br />for(String str : coll)<br />{<br />  System.out.println(str);<br />}<br />}<br /><br />怎么样？是不是简单了很多？<br />自动的装箱/拆箱:<br />可变参数数目J2SE 5.0开始支持Varargs(不固定自变量个数)，J2SE 5.0中还加入了以前抛弃的枚举和C风格的格式化输出，这应该是为了吸引以前的C开发者吧。毕竟,在C开发中枚举和格式化输出用的是太多了。<br />并发 J2SE 5.0中加入了java.util.concurrent包，并向集合框架中加入了Queue接口，J2SE 5.0还为各种集合提供了并发情况下的实现。<br />Properties类增强 由于XML的普及性应用，J2SE 5.0为java.util.Properties类加入了从XML文件中装载属性和把属性值存储到XML文件中的方法。<br />Annotation功能J2SE 5.0提供了注解(annotation)/元数据（metadata）功能，相信以后的大部分应用产品都将充分利用它的注解而实现产品的各种特性。<br />其它J2SE 5.0还在多线程（并发机制）、安全、国际化、UI等方面进行了大规模的变更，使得我们能够更方便地进行Java开发。<br />其实，上面的这些变更，并不是我们程序员非要不可的内容。我们完全可以通过自己的办法来达到这些变更实现的功能。但J2SE 5.0的目标就是让我们程序员能够更加方便地进行开发，所以，我们在基于J2SE 5.0开发时，应该能够明显的体会到它的易用性。<br /><br />展望<br />时至今日，J2SE已经发展为一个覆盖面广、效率高、易用性强的技术平台(见如下的J2SE API体系结构图)，但Java并没有停止前进的脚步。Mustang版本的J2SE正在紧锣密鼓的开发当中，按以前的惯例，每两年会发布一个全新的J2SE版本，所以Mustang开发版对应的J2SE 6.0发布版将在2006年完成。<br />2005年5月23日是Java技术十周年庆典日，在这十年的发展中，Java平台吸引了四百万开发者，在网络计算遍及全球的今天，更是有17.5亿台设备使用了Java技术。作为Java技术的基础，J2SE的功绩不可掩没，我们期望J2SE伴随Java平台一路走好！<br /><br />MATRIX社区介绍:<br />Matrix，面向Java爱好者的非赢利性组织。成立以来，Matrix一直不遗余力地为推动中国Java技术和开源软件的进步和发展而努力，发布了Jasmin反编译器，Jmatrix全站系统等开源产品。加入Matrix，与Java共舞（[url]www.matrix.org.cn[/url]）<br /><br />中国企业走近JCP<br />文/黄海波<br /><br />对Java开发人员，JCP（Java Community Process）这个名词并不陌生。但对国内大部分Java开发人员来说，JCP更多的是一个符号，一个国际Java开发社区的象征。而对JCP这个组织的来源、组成、运作模式以及JCP对中国软件产业，甚至是我们自身工作事业的影响可能不甚了了。由于历史原因、文化语言的差异，国内Java厂商一直未能对JCP引起足够重视，从而导致国内的软件厂商无法参与到JCP的行业标准的制定过程中去，结果就使我们只能跟随制定好的标准，而不能影响标准向着有利于国内软件产业的方向发展。<br /><br />跟随的劣势是很明显的，以万众期待的下一代Java持久化标准EJB 3为例。EJB 3规范目前仍在早期规范阶段，预计要到２００６年中期才能完成最终版本，但EJB 3专家组中的Java厂商都已经根据讨论的初步意见开始了产品开发，有些甚至开始发布预览版本。而国内的J2EE厂商却可能要等到EJB 3的最终版才可以着手进行研究和开发（根据早期规范不可靠，变动通常很大），差距自然巨大。在其他诸如如商业智能、工作流、数据挖掘等领域都存在类似情况。<br /><br />可喜的是国内软件业的Java行业组织和管理部门都已经认识到，继续徘徊在JCP的门外不利于国内Java产业的生存和发展，也和国内庞大的软件市场不相符合。在许许多多有志之士（很多是笔者的前辈，他们为国内软件业发展默默努力，实在让人钦佩）的共同努力下，JCP的中国分支也即将成立。而作为第一个尝试，中国的Java应用体验认证实验室在国家应用软件产品质量监督检验中心、Sun计算机系统（中国）有限公司、中国软件行业协会中间件分会、北京软件与信息服务业促进中心四单位共同努力下在北京成立，为中国的Java软件厂商在国内进行软件的JCP认证和兼容测试。<br /><a href="http://www.souzz.net/bbs/archiver/?tid-49.html">http://www.souzz.net/bbs/archiver/?tid-49.html</a><img src ="http://www.blogjava.net/Duffblog/aggbug/66677.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Duffblog/" target="_blank">追球者</a> 2006-08-30 15:56 <a href="http://www.blogjava.net/Duffblog/articles/66677.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>编译原理学习导论(转)</title><link>http://www.blogjava.net/Duffblog/articles/64817.html</link><dc:creator>追球者</dc:creator><author>追球者</author><pubDate>Mon, 21 Aug 2006 08:24:00 GMT</pubDate><guid>http://www.blogjava.net/Duffblog/articles/64817.html</guid><wfw:comment>http://www.blogjava.net/Duffblog/comments/64817.html</wfw:comment><comments>http://www.blogjava.net/Duffblog/articles/64817.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Duffblog/comments/commentRss/64817.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Duffblog/services/trackbacks/64817.html</trackback:ping><description><![CDATA[
		<div>大学课程为什么<strong>要</strong>开设编译原理呢？这门课程关注的是编译器方面的产生原理和技术问题，似乎和计算机的基础领域不沾边，可是编译原理却一直作为大学本科的必修课程，同时也成为了研究生入学考试的必考内容。编译原理及技术从本质上来讲就是一个算法问题而已，当然由于这个问题十分复杂，其解决算法也相对复杂。我们学的数据结构与算法分析也是讲算法的，不过讲的基础算法，换句话说讲的是算法导论，而编译原理这门课程讲的就是比较专注解决一种的算法了。在20世纪50年代，编译器的编写一直被认为是十分困难的事情，第一Fortran的编译器据说花了18年的时间才完成。在人们尝试编写编译器的同时，诞生了许多跟编译相关的理论和技术，而这些理论和技术比一个实际的编译器本身价值更大。就犹如数学家们在解决著名的哥德巴赫猜想一样，虽然没有最终解决问题，但是其间诞生不少名著的相关数论。 
<b>推荐参考书</b> 虽然编译理论发展到今天，已经有了比较成熟的部分，但是作为一个大学生来说，要自己写出一个像Turboc 
C,Java那样的编译器来说还是太难了。不仅写编译器困难，学习编译原理这门课程也比较困难。 
正是因为编译原理学习相对困难，那么就要求有好的教师和好的教材。教师方面不是我们能自己更改的，而在教材方面我们却可以按自己的意愿来阅读。我下面推荐几本好的编译原理的教材。我推荐的书籍都是国外的经典教材，因为在国内的教材中，确实还没发现什么让人满意的。 
第一本书的原名叫《Compilers Principles,Techniques,and 
Tools》,另外一个响亮的名字就是龙书。原因是这本书的封面上有条红色的龙，也因为獗臼樵诒嘁朐砘×煊蛉肥堤忻?所以很多国外的学者都直接取名为龙书。最近机械工业出版社已经出版了此书的中文版，名字就叫《编译原理》。该书出的比较早，大概是在85或86年编写完成的，作者之一还是著名的贝尔实验室的科学家。里面讲解的核心编译原理至今都没有变过，所以一直到今天，它的价值都非凡。这本书最大的特点就是一开始就通过一个实际的小例子，把编译原理的大致内容罗列出来，让很多编译原理的初学者很快心里有了个底,也知道为什么会有这些理论，怎么运用这些理论。而这一点是我感觉国内的教材缺乏的东西，所以国内的教材都不是写给愿意自学的读者，总之让人看了半天，却不知道里面的东西有什么用。 
第二本书的原名叫《Modern Compiler 
Design》,中文名字叫做《现代编译程序设计》。该书由人民邮电出版社所出。此书比较关注的是编译原理的实践，书中给出了不少的实际程序代码，还有很多实际的编译技术问题等等。此书另外一个特点就是其“现代”而字。在传统的编译原理教材中，你是不可能看到如同Java中的“垃圾回收”等算法的。因为Java这样的解释执行语言是在近几年才流行起来的东西。如果你想深入学习编译原理的理论知识，那么你肯定得看前面那本龙书，如果你想自己动手做一个先进的编译器，那么你得看这本《现代编译程序设计》。 
第三本书就是很多国内的编译原理学者都推荐的那本《编译原理及实践》。或许是这本书引入国内比较早吧，我记得我是在高中就买了这本书，不过也是在前段时间才把整本书看完。此书作为入门教程也的确是个不错的选择。书中给出的编译原理讲解也相当细致，虽然不如前面的龙书那么深入，但是很多地方都是点到为止，作为大学本科教学已经是十分深入了。该书的特点就是注重实践，不过感觉还不如前面那本《现代编译程序设计》的实践味道更重。此书的重点还是在原理上的实践，而非前面那本那样的技术实践。《编译原理及实践》在讲解编译原理的各个部分的同时，也在逐步实践一个现代的编译器Tiny 
C.等你把整本书看完，差不多自己也可以写一个Tiny 
C了。作者还对Lex和Yacc这两个常用的编译相关的工具进行了很详细的说明，这一点也是很难在国内的教材中看到的。 
推荐了这三本教材，都有英文版和中文版的。很多英文好的同学只喜欢看原版的书，不我的感觉是这三本书的翻译都很不错，没有必要特别去买英文版的。理解理论的实质比理解表面的文字更为重要。 
<b>编译原理的实质</b> 
前面已经说过，学习编译原理其实也就是学习算法而已，没什么特别的。只不过这些算法的产生已经形成了一套理论。下面我来看看编译原理里面到底有什么高深的理论吧。 
几乎每本编译原理的教材都是分成词法分析，语法分析（LL算法，递归下降算法，LR算法），语义分析，运行时环境，中间代码，代码生成，代码优化这些部分。其实现在很多编译原理的教材都是按照85,86出版的那本龙书来安排教学内容的，所以那本龙书的内容格式几乎成了现在编译原理教材的定式，包括国内的教材也是如此。一般来说，大学里面的本科教学是不可能把上面的所有部分都认真讲完的，而是比较偏重于前面几个部分。像代码优化那部分东西，就像个无底洞一样，如果要认真讲，就是单独开一个学期的课也不可能讲得清楚。所以，一般对于本科生，对词法分析和语法分析掌握要求就相对要高一点了。 
词法分析相对来说比较简单。可能是词法分析程序本身实现起来很简单吧，很多没有学过编译原理的人也同样可以写出各种各样的词法分析程序。不过编译原理在讲解词法分析的时候，重点把正则表达式和自动机原理加了进来，然后以一种十分标准的方式来讲解词法分析程序的产生。这样的做法道理很明显，就是要让词法分析从程序上升到理论的地步。 
语法分析部分就比较麻烦一点了。现在一般有两种语法分析算法，LL自顶向下算法和LR自底向上算法。LL算法还好说，到了LR算法的时候，困难就来了。很多自学编译原理的都是遇到LR算法的理解成问题后就放弃了自学。其实这些东西都是只要大家理解就可以了，又不是像词法分析那样非得自己写出来才算真正的会。像LR算法的语法分析器，一般都是用工具Yacc来生成，实践中完全没有比较自己来实现。对于LL算法中特殊的递归下降算法，因为其实践十分简单，那么就应该要求每个学生都能自己写。当然，现在也有不少好的LL算法的语法分析器，不过要是换在非C平台，比如Java,Delphi,你不能运用YACC工具了，那么你就只有自己来写语法分析器。 
等学到词法分析和语法分析时候，你可能会出现这样的疑问：“词法分析和语法分析到底有什么？”就从编译器的角度来讲，编译器需要把程序员写的源程序转换成一种方便处理的数据结构（抽象语法树或语法树）,那么这个转换的过程就是通过词法分析和语法分析的。其实词法分析并非一开始就被列入编译器的必备部分，只是我们为了简化语法分析的过程，就把词法分析这种繁琐的工作单独提取出来，就成了现在的词法分析部分。除了编译器部分，在其它地方，词法分析和语法分析也是有用的。比如我们在DOS,Unix,Linux下输入命令的时候，程序如何分析你输入的命令形式，这也是简单的应用。总之，这两部分的工作就是把不“规则”的文本信息转换成一种比较好分析好处理的数据结构。那么为什么编译原理的教程都最终把要分析的源分析转换成“树”这种数据结构呢？数据结构中有Stack, 
Line,List…这么多数据结构，各自都有各自的特点。但是Tree这种结构有很强的递归性，也就是说我们可以把Tree的任何结点Node提取出来后，它依旧是一颗完整的Tree。这一点符合我们现在编译原理分析的形式语言，比如我们在函数里面使用函树，循环中使用循环，条件中使用条件等等，那么就可以很直观地表示在Tree这种数据结构上。同样，我们在执行形式语言的程序的时候也是如此的递归性。在编译原理后面的代码生成的部分，就会介绍一种堆栈式的中间代码，我们可以根据分析出来的抽象语法树，很容易，很机械地运用递归遍历抽象语法树就可以生成这种指令代码。而这种代码其实也被广泛运用在其它的解释型语言中。像现在流行的Java,.NET，其底层的字节码bytecode,可以说就是这中基于堆栈的指令代码的。 
关于语义分析，语法制导翻译，类型检查等等部分，其实都是一种完善前面得到的抽象语法树的过程。比如说，我们写C语言程序的时候，都知道，如果把一个浮点数直接赋值给一个整数，就会出现类型不匹配，那么C语言的编译器是怎么知道的呢？就是通过这一步的类型检查。像C++语言这中支持多态函数的语言，这部分要处理的问题就更多更复杂了。大部编译原理的教材在这部分都是讲解一些比较好的处理策略而已。因为新的问题总是在发生，旧的办法不见得足够解决。 
本来说，作为一个编译器，起作用的部分就是用户输入的源程序到最终的代码生成。但是在讲解最终代码生成的时候，又不得不讲解机器运行环境等内容。因为如果你不知道机器是怎么执行最终代码的，那么你当然无法知道如何生成合适的最终代码。这部分内容我自我感觉其意义甚至超过了编译原理本身。因为它会把一个计算机的程序的运行过程都通通排在你面前，你将来可能不会从事编译器的开发工作，但是只要是和计算机软件开发相关的领域,都会涉及到程序的执行过程。运行时环境的讲解会让你更清楚一个计算机程序是怎么存储，怎么装载，怎么执行的。关于部分的内容，我强烈建议大家看看龙书上的讲解，作者从最基本的存储组织，存储分配策略，非局部名字的访问，参数传递，符号表到动态存储分配(malloc,new)都作了十分详细的说明。这些东西都是我们编写平常程序的时候经常要做的事情，但是我们却少去探求其内部是如何完成。 
</div>
<img src ="http://www.blogjava.net/Duffblog/aggbug/64817.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Duffblog/" target="_blank">追球者</a> 2006-08-21 16:24 <a href="http://www.blogjava.net/Duffblog/articles/64817.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>为什么SAX|DOM同时存在?(转)</title><link>http://www.blogjava.net/Duffblog/articles/64659.html</link><dc:creator>追球者</dc:creator><author>追球者</author><pubDate>Sun, 20 Aug 2006 13:30:00 GMT</pubDate><guid>http://www.blogjava.net/Duffblog/articles/64659.html</guid><wfw:comment>http://www.blogjava.net/Duffblog/comments/64659.html</wfw:comment><comments>http://www.blogjava.net/Duffblog/articles/64659.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Duffblog/comments/commentRss/64659.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Duffblog/services/trackbacks/64659.html</trackback:ping><description><![CDATA[SAX (Simple API for XML) 和 DOM (Document Object Model) 都是为了让程序员不用写一个解析器就
可以访问他们的资料信息。通过利用XML 1.0格式保存信息,以及使用SAX或者DOM APIs你的程序可以使用任何解析器。这是因为使用他们所喜爱
的语言开发解析器的开发者必须实现SAX和DOM APIs。 SAX和DOM APIs 对多种语言中都可以实现(Java, C++, Perl,
 Python, 其它...)。<p> 所以SAX 和 DOM都是为了同样的目的而存在,这就是使用户可以利用任何编程语言访问存入XML文档中的信息(要有一个那种编程语言的解析器)。虽然他们在提供给你访问信息的方法上大不相同。</p><br /><p>什么是DOM?</p><p> DOM 可以让你以分层次对象模型来访问储存在XML文档中的信息。DOM生成一棵节点树(以XML文档的结构和信息为基础)你可以通过这棵树来访问你的信息。在XML文档中的文本信息转变成一组树的节点。<br />
不管你的XML文档中的信息的类型 (不管是表格数据,或是一列items,或者只是文档), DOM在你创建一个XML文档的文档对象时创建一棵节点
树。 DOM强迫你使用树状模型(就像 Swing TreeModel)去访问你的XML文档中的信息。这种模式确实不错因为XML原本就是分层次的。
这也是DOM为什么可以把你的信息放到一棵树中的原因(即使信息是表格式的或者简单的列表????这里不知道该怎么翻原文是：
even if the information is actually tabular or a simple list??????)。</p><p>
因为在DOM中,每一个元素节点实际上都有一系列的其他节点作为它的孩子。这些孩子节点可以包含文本值或者是其他元素节点。乍看起来，通过遍历访问一个元
素的所有孩子节点来访问这个节点的值是没有必要的(举例来说:节点 "&lt;name&gt; Nazmul &lt;/name&gt;",
 Nazmul是值)。如果每个元素只有值的话，这确实是没有必要的。但是，元素可能含有文本数据或者其他元素;这是你要在DOM中做额外的工作来获取元
素节点值的原因。 通常当你的文档中只有纯数据时,把所有的数据压成一个“块“放到字串中并让DOM把那个字串当成某个特定元素节点的值返回是适当的。这
种方式并不适合如果在你的XML文档中的数据是个文档（比如像WORD文档或者FRAMEMAKER文档） 在文档中，元素的顺序是非常重要的。对于纯数
据(像一个数据库表)元素的顺序是不要紧的。 之所以DOM保持从XML文档中读出的元素的顺序，因为它把所有的事物都当成文档来处理。 文档对像模型的
叫法由此而来。</p><p>
如果你计划用DOM做为JAVA对象模型用于你存储在XML文档中的信息，那么你不需要考虑SAX。可是如果你发现DOM不是一个可以用于处理XML文档
信息的好的对象模式，那么你可能想看看SAX了。在一些必须使用自定义对象模型的案例中使用SAX是非常普遍的。说一句让事情看来有些糊涂的话，你也可以
在DOM的基础之上创建自己的对象模式。面向对象真是个好东东。</p><br /><p>什么是SAX?</p><p> SAX让你访问储存在XML文档中的信息，不是通过节点树，而是一系列的事件。你会问，这有什么益处？回答是，SAX选择不在XML文档上创建JAVA对象模型(像DOM做的那样)。 这样使得SAX更快, 同时使下面所述成为必要:</p><p> 创立你自己的自定义对像模型<br /> 创建一个监听SAX事件的类同时创建你自己的对象模型<br /> 注意这些步骤对DOM而言是不必要的，因为DOM已经为你创建了一个对象模型(将你的信息用一棵节点树表示)。</p><p>
在使用DOM的情况下,解析器做了绝大多数事情, 读入XML文档, 在这基础之上创建JAVA对象模型，然后给你一个对这个对象的引用(一个
 Document对象)，因而你可以操作使用它。SAX被叫做Simple API for XML不是没有原因的, 她真的很简单。 SAX没有期待
解析器去做这么多工作，所有SAX 要求的是解析器应该读入XML文档,同时根据所遇到的XML文档的标签发出一系列事件。你要自己写一个XML文档处理
器类（XML document handler class）来处理这些事件,这意味着使所有标签事件有意义还有用你自己的对象模型创建对象。所以你要
完成:</p><p> 控制所有XML文档信息的自定义对象模型（或者源文档在这里的写法从来没有见过，或者怀疑源文档在这里有排版错误，先这么翻了）<br /> 一个监听SAX事件(事件由SAX解析器读取你的XML文档时产生)的文档处理器，还有解释这些事件创建你自定义对象模型中的对象<br /> 如果你的对象模型简单的话那么SAX在运行时会非常快。在这种情况下，它会比DOM快,因为它忽略了为你的信息创建一个树形对象模型的过程。从另一方面来说，你必须写一个SAX 文档处理器来解释所有的SAX事件(这会是一件很繁重的工作)。</p><p>
什么类型的SAX事件被SAX解析器抛出了哪? 这些事件实际上是非常简单的。SAX会对每一个开始标签抛出事件,对每一个结束标签也是如此。它对
#PCDATA和 CDATA 部分同样抛出事件。你的文档处理器 (对这些事件的监听器)要解释这些事件同时还要在他们基础之上创建你自定义的对象模
型。 你的文档处理器必须对这些事件做出解释，同时这些事件发生的顺序是非常重要的。SAX同时也对processing instructions,
 DTDs, comments, 抛出事件. 但是它们在概念上是一样的, 你的解析器要解释这些事件(还有这些事件的发生顺序)以及使他们有意义。</p><br /><p>什么时候使用DOM</p><p>
如果你的XML文档包含文档数据(例如, Framemaker documents stored in XML format), 那么DOM就是你
的解决方案的最自然选择。如果你要创建一些类似于文档信息管理的系统，那么你不得不处理大量的文档数据。Datachannel RIO 产品就是这么一
个例子,它可以索引和组织各种类型文档资源中的信息(例如Word和Excel 文件)。在这种情况下，DOM是非常合适程序去访问存贮在这些文档中的信
息的。</p><p> 然而,如果你主要处理的是结构化的数据(在XML中的序列化的JAVA对象the equivalent of serialized Java objects in XML)，DOM不是最好的选择。那就是SAX会比较合适的地方。</p><br /><p>什么时候使用SAX</p><p> 如果在你XML文档中的信息是机器易读的(和机器生成的)数据，那么SAX是让你可以访问这些信息的合适的API。机器易读和生成的数据类型包含像下面这些东东:</p><p> 存成XML格式的Java对象属性<br /> 用一些以文本为基础的查询语句(SQL, XQL, OQL)表示的查询<br /> 由查询生成的结果集(这也许包含关系型数据库表中的数据编码成XML).<br /> 这么看来机器生成的数据是你一般要在java中生成数据结构和类的信息。一个简单的例子是包含个人信息的地址簿，在上图所示。这个地址簿xml文件不像字处理器文档，它是一个包含已经被编码成文本的纯数据的XML文档。</p><p>
当你的数据是这种样式，你要创建你自己的数据结构和类（对象模型）来管理操作以及持续保存这些数据。SAX容许你快速创建一个可以生成你的对象模型实例的
处理器类。一个实例是：一个SAX文档处理器。它完成的工作有读入包含我的地址薄信息的XML文档，创建一个可以访问到这些信息的AddressBook
类。SAX指南告诉你该怎么做到这些。这个地址薄XML文档包含person元素，person元素中有name和email元素。我的
AddressBook对象模型包括下面的类：</p><p> AddressBook 类,Person对象的容器<br /> Person 类,String 型的name和email的容器<br /> 这样我的“SAX 地址簿文档处理器”可以把person元素转变成Person对象了，然后把它们都存入AddressBook对象。这个文档处理器将name和email元素转变为String对象。</p><br />结论<p> --------------------------------------------------------------------------------</p> 你写的SAX文档处理器（SAX document handler）做了将元素映射为对象的工作。如果你的信息被结构化成可以容易创建这样的映射，你应该使用SAX API。从另一方面来说，如果你的数据更适宜用树来表示那么你应该使用DOM<br /><img src ="http://www.blogjava.net/Duffblog/aggbug/64659.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Duffblog/" target="_blank">追球者</a> 2006-08-20 21:30 <a href="http://www.blogjava.net/Duffblog/articles/64659.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用开源实现系统托盘(转)</title><link>http://www.blogjava.net/Duffblog/articles/63346.html</link><dc:creator>追球者</dc:creator><author>追球者</author><pubDate>Sun, 13 Aug 2006 09:49:00 GMT</pubDate><guid>http://www.blogjava.net/Duffblog/articles/63346.html</guid><wfw:comment>http://www.blogjava.net/Duffblog/comments/63346.html</wfw:comment><comments>http://www.blogjava.net/Duffblog/articles/63346.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Duffblog/comments/commentRss/63346.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Duffblog/services/trackbacks/63346.html</trackback:ping><description><![CDATA[
网上主要流传有两种方式实现系统托盘:<br />1.Windows Tray Icon ( http://jeans.studentenweb.org/java/trayicon/trayicon.html )<br /><br /><br />2.SysTray for Java ( http://systray.sourceforge.net/ )<br /><br /><br />这两个都是开源的...可以根据上面的下载.<br /><br />相对来说,我更喜欢SysTray for Java,原因很简单,SysTray for Java实现了我所要的功能而且相对来说比Windows Tray Icon 要简单.<br /><br />使用SysTray是很简单的.下载下来的文件有个例子Example.java,照着这个实现你所需要的功能应该不算困难.<br /><br />主要是菜单和按钮的操作,和操作一般的JFrame一样.<br /><br />下面是一个例子程序:<br />         package qiya.systray;<br /><br />import java.awt.Dimension;<br />import java.awt.Font;<br />import java.awt.Rectangle;<br />import java.awt.Toolkit;<br />import java.awt.event.ActionEvent;<br />import java.awt.event.ActionListener; <br /><br />import javax.swing.ImageIcon;<br />import javax.swing.JButton;<br />import javax.swing.JFrame;<br />import javax.swing.JLabel;<br />import javax.swing.JOptionPane;<br />import javax.swing.UIManager;<br />import javax.swing.UnsupportedLookAndFeelException; <br /><br />import snoozesoft.systray4j.SysTrayMenu;<br />import snoozesoft.systray4j.SysTrayMenuEvent;<br />import snoozesoft.systray4j.SysTrayMenuIcon;<br />import snoozesoft.systray4j.SysTrayMenuItem;<br />import snoozesoft.systray4j.SysTrayMenuListener; <br /><br />public class MainFrame extends JFrame implements ActionListener,<br />  SysTrayMenuListener { <br /><br /> static final int INIT_WIDTH = 400;// 默认窗口宽度 <br /><br /> static final int INIT_HEIGHT = 244;// 默认窗口高度 <br /><br /> private static final String toolTip = "宽带计费接口";// 提示文字 <br /><br /> static final SysTrayMenuIcon icon = new SysTrayMenuIcon("rocket.gif");// 图片信息 <br /><br /> SysTrayMenu menu;// 菜单 <br /><br /> private JButton launchButton = new JButton();// 启动按钮 <br /><br /> private JButton exitButton = new JButton();// 退出按钮 <br /><br /> private JLabel statusLabel = new JLabel();// 运行状态 <br /><br /> public static void main(String[] args) {<br />  try {<br />   UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());<br />  } catch (ClassNotFoundException e) {<br />   e.printStackTrace();<br />  } catch (InstantiationException e) {<br />   e.printStackTrace();<br />  } catch (IllegalAccessException e) {<br />   e.printStackTrace();<br />  } catch (UnsupportedLookAndFeelException e) {<br />   e.printStackTrace();<br />  } <br /><br />  new MainFrame();<br /> } <br /><br /> public MainFrame() {<br />  super("宽带计费接口");// 标题<br />  setIconImage(new ImageIcon(getClass().getResource("rocket.gif"))<br />    .getImage());// 图标<br />  this.setLayout(null);<br />  this.setSize(new Dimension(INIT_WIDTH, INIT_HEIGHT));<br />  Dimension dimScreen = Toolkit.getDefaultToolkit().getScreenSize();<br />  int xPos = (dimScreen.width - INIT_WIDTH) / 2;<br />  int yPos = (dimScreen.height - INIT_HEIGHT) / 2; <br /><br />  statusLabel.setText("系统状态监视");<br />  statusLabel.setBounds(new Rectangle(45, 35, 280, 40));<br />  statusLabel.setToolTipText("当前系统的运行状态");<br />  statusLabel.setFont(new Font("宋体", 0, 14)); <br /><br />  launchButton.setText("启动");<br />  launchButton.setBounds(new Rectangle(80, 180, 80, 23)); <br /><br />  exitButton.setText("退出");<br />  exitButton.setBounds(new Rectangle(230, 180, 80, 23)); <br /><br />  this.getContentPane().add(statusLabel, null);<br />  this.getContentPane().add(launchButton, null);<br />  this.getContentPane().add(exitButton, null); <br /><br />  launchButton.addActionListener(this);<br />  exitButton.addActionListener(this); <br /><br />  this.setBounds(xPos, yPos, INIT_WIDTH, INIT_HEIGHT); <br /><br />  icon.addSysTrayMenuListener(this);<br />  this.createMenu();<br />  this.setVisible(true);<br /> } <br /><br /> /**<br />  * 创建菜单<br />  * <br />  */<br /> private void createMenu() {<br />  SysTrayMenuItem subItem1 = new SysTrayMenuItem("退出", "退出");<br />  subItem1.addSysTrayMenuListener(this); <br /><br />  SysTrayMenuItem subItem2 = new SysTrayMenuItem("关于", "关于");<br />  subItem2.addSysTrayMenuListener(this); <br /><br />  SysTrayMenuItem subItem3 = new SysTrayMenuItem("帮助", "帮助");<br />  subItem3.addSysTrayMenuListener(this); <br /><br />  menu = new SysTrayMenu(icon, toolTip);// 生成菜单<br />  menu.addItem(subItem1);<br />  menu.addSeparator();<br />  menu.addItem(subItem2);<br />  menu.addItem(subItem3);<br /> } <br /><br /> /**<br />  * 点击按钮事件<br />  */<br /> public void actionPerformed(ActionEvent e) {<br />  if (e.getActionCommand().equalsIgnoreCase("退出")) {<br />   System.exit(0);<br />  } else if (e.getActionCommand().equalsIgnoreCase("启动")) {<br />   // 启动计费程序 <br /><br />  }<br /> } <br /><br /> /**<br />  * 菜单选择事件<br />  */<br /> public void menuItemSelected(SysTrayMenuEvent e) {<br />  if (e.getActionCommand().equalsIgnoreCase("退出")) {<br />   System.exit(0);<br />  } else if (e.getActionCommand().equalsIgnoreCase("关于")) {<br />   JOptionPane.showMessageDialog(this, "宽带计费接口" + "完成于2005-3-27");<br />  } else if (e.getActionCommand().equalsIgnoreCase("帮助")) {<br />   JOptionPane.showMessageDialog(this, "宽带计费接口" + "帮助文件待写...");<br />  }<br /> } <br /><br /> /**<br />  * 左键单击事件<br />  */<br /> public void iconLeftClicked(SysTrayMenuEvent e) {<br />  if (this.isVisible()) {// 如果可见,最小化<br />   this.setVisible(false);<br />  } else {// 如果不可见显示出来<br />   this.setVisible(true);<br />  }<br /> } <br /><br /> /**<br />  * 左键双击事件<br />  */<br /> public void iconLeftDoubleClicked(SysTrayMenuEvent e) {<br />  if (this.isVisible()) {// 如果可见,最小化<br />   this.setVisible(false);<br />  } else {// 如果不可见显示出来<br />   this.setVisible(true);<br />  }<br /> }<br />}<br />        <br /><br />转自：http://www.xjtublog.com/user1/1034/archives/2006/64310.shtml<br /><img src ="http://www.blogjava.net/Duffblog/aggbug/63346.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Duffblog/" target="_blank">追球者</a> 2006-08-13 17:49 <a href="http://www.blogjava.net/Duffblog/articles/63346.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Swt/JFace制做系统托盘程序(转)</title><link>http://www.blogjava.net/Duffblog/articles/63345.html</link><dc:creator>追球者</dc:creator><author>追球者</author><pubDate>Sun, 13 Aug 2006 09:48:00 GMT</pubDate><guid>http://www.blogjava.net/Duffblog/articles/63345.html</guid><wfw:comment>http://www.blogjava.net/Duffblog/comments/63345.html</wfw:comment><comments>http://www.blogjava.net/Duffblog/articles/63345.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Duffblog/comments/commentRss/63345.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Duffblog/services/trackbacks/63345.html</trackback:ping><description><![CDATA[一些桌面应用程序会在系统的工具条上显示一个图标，即使程序最小化了，也可以供用户方便地操作程序。以前使用Swing来制做这个功能的时候费了不小的力
气，使用了JNI来完成这个功能(JNI：Java Native Interface
Java本地编程接口，可以通过调用汇编或C或C++程序来完成某些功能)。自从Eclipse推出之后，swt就占据了java开发桌面应用的大部分份
额，其中最大的优点就是swt为我们提供了与操作系统交互的接口（其实，swt内容的实现机制就是通过JNI来实现的）。下面是今天完成的系统托盘的例
子。<br /><br /><div class="UBBPanel"><div class="UBBTitle"><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: rgb(238, 238, 238);"><span style="color: rgb(0, 128, 128);"> </span><img src="../../Images/OutliningIndicators/None.gif" align="top" /><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);"> 取得系统托盘对象</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 2</span><span style="color: rgb(0, 128, 0);"><img src="../../Images/OutliningIndicators/None.gif" align="top" /></span><span style="color: rgb(0, 0, 255);">final</span><span style="color: rgb(0, 0, 0);"> Tray tray </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> shell.getDisplay().getSystemTray();<br /></span><span style="color: rgb(0, 128, 128);"> 3</span><span style="color: rgb(0, 0, 0);"><img src="../../Images/OutliningIndicators/None.gif" align="top" /><br /></span><span style="color: rgb(0, 128, 128);"> 4</span><span style="color: rgb(0, 0, 0);"><img id="Codehighlighter1_86_1699_Open_Image" onclick="this.style.display='none'; Codehighlighter1_86_1699_Open_Text.style.display='none'; Codehighlighter1_86_1699_Closed_Image.style.display='inline'; Codehighlighter1_86_1699_Closed_Text.style.display='inline';" src="../../Images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_86_1699_Closed_Image" style="display: none;" onclick="this.style.display='none'; Codehighlighter1_86_1699_Closed_Text.style.display='none'; Codehighlighter1_86_1699_Open_Image.style.display='inline'; Codehighlighter1_86_1699_Open_Text.style.display='inline';" src="../../Images/OutliningIndicators/ContractedBlock.gif" align="top" /></span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);"> (tray </span><span style="color: rgb(0, 0, 0);">!=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">null</span><span style="color: rgb(0, 0, 0);">) </span><span id="Codehighlighter1_86_1699_Closed_Text" style="border: 1px solid rgb(128, 128, 128); display: none; background-color: rgb(255, 255, 255);"><img src="../../Images/dot.gif" /></span><span id="Codehighlighter1_86_1699_Open_Text"><span style="color: rgb(0, 0, 0);">{<br /></span><span style="color: rgb(0, 128, 128);"> 5</span><span style="color: rgb(0, 0, 0);"><img src="../../Images/OutliningIndicators/InBlock.gif" align="top" />        </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);"> 生成托盘对象</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 6</span><span style="color: rgb(0, 128, 0);"><img src="../../Images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="color: rgb(0, 0, 0);">        </span><span style="color: rgb(0, 0, 255);">final</span><span style="color: rgb(0, 0, 0);"> TrayItem item </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> TrayItem(tray, SWT.NONE);<br /></span><span style="color: rgb(0, 128, 128);"> 7</span><span style="color: rgb(0, 0, 0);"><img src="../../Images/OutliningIndicators/InBlock.gif" align="top" />        </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);"> 为托盘对象添加鼠标停留时的文字</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 8</span><span style="color: rgb(0, 128, 0);"><img src="../../Images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="color: rgb(0, 0, 0);">        item.setToolTipText(“六月天”);<br /></span><span style="color: rgb(0, 128, 128);"> 9</span><span style="color: rgb(0, 0, 0);"><img src="../../Images/OutliningIndicators/InBlock.gif" align="top" />        </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);"> 为托盘添加事件</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 128, 128);">10</span><span style="color: rgb(0, 128, 0);"><img id="Codehighlighter1_262_349_Open_Image" onclick="this.style.display='none'; Codehighlighter1_262_349_Open_Text.style.display='none'; Codehighlighter1_262_349_Closed_Image.style.display='inline'; Codehighlighter1_262_349_Closed_Text.style.display='inline';" src="../../Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_262_349_Closed_Image" style="display: none;" onclick="this.style.display='none'; Codehighlighter1_262_349_Closed_Text.style.display='none'; Codehighlighter1_262_349_Open_Image.style.display='inline'; Codehighlighter1_262_349_Open_Text.style.display='inline';" src="../../Images/OutliningIndicators/ContractedSubBlock.gif" align="top" /></span><span style="color: rgb(0, 0, 0);">        item.addListener(SWT.Show, </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> Listener() </span><span id="Codehighlighter1_262_349_Closed_Text" style="border: 1px solid rgb(128, 128, 128); display: none; background-color: rgb(255, 255, 255);"><img src="../../Images/dot.gif" /></span><span id="Codehighlighter1_262_349_Open_Text"><span style="color: rgb(0, 0, 0);">{<br /></span><span style="color: rgb(0, 128, 128);">11</span><span style="color: rgb(0, 0, 0);"><img id="Codehighlighter1_305_345_Open_Image" onclick="this.style.display='none'; Codehighlighter1_305_345_Open_Text.style.display='none'; Codehighlighter1_305_345_Closed_Image.style.display='inline'; Codehighlighter1_305_345_Closed_Text.style.display='inline';" src="../../Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_305_345_Closed_Image" style="display: none;" onclick="this.style.display='none'; Codehighlighter1_305_345_Closed_Text.style.display='none'; Codehighlighter1_305_345_Open_Image.style.display='inline'; Codehighlighter1_305_345_Open_Text.style.display='inline';" src="../../Images/OutliningIndicators/ContractedSubBlock.gif" align="top" />                </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> handleEvent(Event event) </span><span id="Codehighlighter1_305_345_Closed_Text" style="border: 1px solid rgb(128, 128, 128); display: none; background-color: rgb(255, 255, 255);"><img src="../../Images/dot.gif" /></span><span id="Codehighlighter1_305_345_Open_Text"><span style="color: rgb(0, 0, 0);">{<br /></span><span style="color: rgb(0, 128, 128);">12</span><span style="color: rgb(0, 0, 0);"><img src="../../Images/OutliningIndicators/InBlock.gif" align="top" />                        System.out.println(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">show</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">);<br /></span><span style="color: rgb(0, 128, 128);">13</span><span style="color: rgb(0, 0, 0);"><img src="../../Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />                }</span></span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">14</span><span style="color: rgb(0, 0, 0);"><img src="../../Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />        }</span></span><span style="color: rgb(0, 0, 0);">);<br /></span><span style="color: rgb(0, 128, 128);">15</span><span style="color: rgb(0, 0, 0);"><img id="Codehighlighter1_397_484_Open_Image" onclick="this.style.display='none'; Codehighlighter1_397_484_Open_Text.style.display='none'; Codehighlighter1_397_484_Closed_Image.style.display='inline'; Codehighlighter1_397_484_Closed_Text.style.display='inline';" src="../../Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_397_484_Closed_Image" style="display: none;" onclick="this.style.display='none'; Codehighlighter1_397_484_Closed_Text.style.display='none'; Codehighlighter1_397_484_Open_Image.style.display='inline'; Codehighlighter1_397_484_Open_Text.style.display='inline';" src="../../Images/OutliningIndicators/ContractedSubBlock.gif" align="top" />        item.addListener(SWT.Hide, </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> Listener() </span><span id="Codehighlighter1_397_484_Closed_Text" style="border: 1px solid rgb(128, 128, 128); display: none; background-color: rgb(255, 255, 255);"><img src="../../Images/dot.gif" /></span><span id="Codehighlighter1_397_484_Open_Text"><span style="color: rgb(0, 0, 0);">{<br /></span><span style="color: rgb(0, 128, 128);">16</span><span style="color: rgb(0, 0, 0);"><img id="Codehighlighter1_440_480_Open_Image" onclick="this.style.display='none'; Codehighlighter1_440_480_Open_Text.style.display='none'; Codehighlighter1_440_480_Closed_Image.style.display='inline'; Codehighlighter1_440_480_Closed_Text.style.display='inline';" src="../../Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_440_480_Closed_Image" style="display: none;" onclick="this.style.display='none'; Codehighlighter1_440_480_Closed_Text.style.display='none'; Codehighlighter1_440_480_Open_Image.style.display='inline'; Codehighlighter1_440_480_Open_Text.style.display='inline';" src="../../Images/OutliningIndicators/ContractedSubBlock.gif" align="top" />                </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> handleEvent(Event event) </span><span id="Codehighlighter1_440_480_Closed_Text" style="border: 1px solid rgb(128, 128, 128); display: none; background-color: rgb(255, 255, 255);"><img src="../../Images/dot.gif" /></span><span id="Codehighlighter1_440_480_Open_Text"><span style="color: rgb(0, 0, 0);">{<br /></span><span style="color: rgb(0, 128, 128);">17</span><span style="color: rgb(0, 0, 0);"><img src="../../Images/OutliningIndicators/InBlock.gif" align="top" />                        System.out.println(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">hide</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">);<br /></span><span style="color: rgb(0, 128, 128);">18</span><span style="color: rgb(0, 0, 0);"><img src="../../Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />                }</span></span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">19</span><span style="color: rgb(0, 0, 0);"><img src="../../Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />        }</span></span><span style="color: rgb(0, 0, 0);">);<br /></span><span style="color: rgb(0, 128, 128);">20</span><span style="color: rgb(0, 0, 0);"><img id="Codehighlighter1_537_629_Open_Image" onclick="this.style.display='none'; Codehighlighter1_537_629_Open_Text.style.display='none'; Codehighlighter1_537_629_Closed_Image.style.display='inline'; Codehighlighter1_537_629_Closed_Text.style.display='inline';" src="../../Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_537_629_Closed_Image" style="display: none;" onclick="this.style.display='none'; Codehighlighter1_537_629_Closed_Text.style.display='none'; Codehighlighter1_537_629_Open_Image.style.display='inline'; Codehighlighter1_537_629_Open_Text.style.display='inline';" src="../../Images/OutliningIndicators/ContractedSubBlock.gif" align="top" />        item.addListener(SWT.Selection, </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> Listener() </span><span id="Codehighlighter1_537_629_Closed_Text" style="border: 1px solid rgb(128, 128, 128); display: none; background-color: rgb(255, 255, 255);"><img src="../../Images/dot.gif" /></span><span id="Codehighlighter1_537_629_Open_Text"><span style="color: rgb(0, 0, 0);">{<br /></span><span style="color: rgb(0, 128, 128);">21</span><span style="color: rgb(0, 0, 0);"><img id="Codehighlighter1_580_625_Open_Image" onclick="this.style.display='none'; Codehighlighter1_580_625_Open_Text.style.display='none'; Codehighlighter1_580_625_Closed_Image.style.display='inline'; Codehighlighter1_580_625_Closed_Text.style.display='inline';" src="../../Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_580_625_Closed_Image" style="display: none;" onclick="this.style.display='none'; Codehighlighter1_580_625_Closed_Text.style.display='none'; Codehighlighter1_580_625_Open_Image.style.display='inline'; Codehighlighter1_580_625_Open_Text.style.display='inline';" src="../../Images/OutliningIndicators/ContractedSubBlock.gif" align="top" />                </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> handleEvent(Event event) </span><span id="Codehighlighter1_580_625_Closed_Text" style="border: 1px solid rgb(128, 128, 128); display: none; background-color: rgb(255, 255, 255);"><img src="../../Images/dot.gif" /></span><span id="Codehighlighter1_580_625_Open_Text"><span style="color: rgb(0, 0, 0);">{<br /></span><span style="color: rgb(0, 128, 128);">22</span><span style="color: rgb(0, 0, 0);"><img src="../../Images/OutliningIndicators/InBlock.gif" align="top" />                        System.out.println(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">selection</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">);<br /></span><span style="color: rgb(0, 128, 128);">23</span><span style="color: rgb(0, 0, 0);"><img src="../../Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />                }</span></span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">24</span><span style="color: rgb(0, 0, 0);"><img src="../../Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />        }</span></span><span style="color: rgb(0, 0, 0);">);<br /></span><span style="color: rgb(0, 128, 128);">25</span><span style="color: rgb(0, 0, 0);"><img id="Codehighlighter1_689_789_Open_Image" onclick="this.style.display='none'; Codehighlighter1_689_789_Open_Text.style.display='none'; Codehighlighter1_689_789_Closed_Image.style.display='inline'; Codehighlighter1_689_789_Closed_Text.style.display='inline';" src="../../Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_689_789_Closed_Image" style="display: none;" onclick="this.style.display='none'; Codehighlighter1_689_789_Closed_Text.style.display='none'; Codehighlighter1_689_789_Open_Image.style.display='inline'; Codehighlighter1_689_789_Open_Text.style.display='inline';" src="../../Images/OutliningIndicators/ContractedSubBlock.gif" align="top" />        item.addListener(SWT.DefaultSelection, </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> Listener() </span><span id="Codehighlighter1_689_789_Closed_Text" style="border: 1px solid rgb(128, 128, 128); display: none; background-color: rgb(255, 255, 255);"><img src="../../Images/dot.gif" /></span><span id="Codehighlighter1_689_789_Open_Text"><span style="color: rgb(0, 0, 0);">{<br /></span><span style="color: rgb(0, 128, 128);">26</span><span style="color: rgb(0, 0, 0);"><img id="Codehighlighter1_732_785_Open_Image" onclick="this.style.display='none'; Codehighlighter1_732_785_Open_Text.style.display='none'; Codehighlighter1_732_785_Closed_Image.style.display='inline'; Codehighlighter1_732_785_Closed_Text.style.display='inline';" src="../../Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_732_785_Closed_Image" style="display: none;" onclick="this.style.display='none'; Codehighlighter1_732_785_Closed_Text.style.display='none'; Codehighlighter1_732_785_Open_Image.style.display='inline'; Codehighlighter1_732_785_Open_Text.style.display='inline';" src="../../Images/OutliningIndicators/ContractedSubBlock.gif" align="top" />                </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> handleEvent(Event event) </span><span id="Codehighlighter1_732_785_Closed_Text" style="border: 1px solid rgb(128, 128, 128); display: none; background-color: rgb(255, 255, 255);"><img src="../../Images/dot.gif" /></span><span id="Codehighlighter1_732_785_Open_Text"><span style="color: rgb(0, 0, 0);">{<br /></span><span style="color: rgb(0, 128, 128);">27</span><span style="color: rgb(0, 0, 0);"><img src="../../Images/OutliningIndicators/InBlock.gif" align="top" />                        System.out.println(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">default selection</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">);<br /></span><span style="color: rgb(0, 128, 128);">28</span><span style="color: rgb(0, 0, 0);"><img src="../../Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />                }</span></span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">29</span><span style="color: rgb(0, 0, 0);"><img src="../../Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />        }</span></span><span style="color: rgb(0, 0, 0);">);<br /></span><span style="color: rgb(0, 128, 128);">30</span><span style="color: rgb(0, 0, 0);"><img src="../../Images/OutliningIndicators/InBlock.gif" align="top" />        </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);"> 为托盘对象添加显示用的图标</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 128, 128);">31</span><span style="color: rgb(0, 128, 0);"><img src="../../Images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="color: rgb(0, 0, 0);">        item.setImage(image);<br /></span><span style="color: rgb(0, 128, 128);">32</span><span style="color: rgb(0, 0, 0);"><img src="../../Images/OutliningIndicators/InBlock.gif" align="top" />        </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);"> 生成菜单项</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 128, 128);">33</span><span style="color: rgb(0, 128, 0);"><img src="../../Images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="color: rgb(0, 0, 0);">        </span><span style="color: rgb(0, 0, 255);">final</span><span style="color: rgb(0, 0, 0);"> Menu menu </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> Menu(shell, SWT.POP_UP);<br /></span><span style="color: rgb(0, 128, 128);">34</span><span style="color: rgb(0, 0, 0);"><img src="../../Images/OutliningIndicators/InBlock.gif" align="top" />        MenuItem miShow </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> MenuItem(menu, SWT.PUSH);<br /></span><span style="color: rgb(0, 128, 128);">35</span><span style="color: rgb(0, 0, 0);"><img src="../../Images/OutliningIndicators/InBlock.gif" align="top" />        miShow.setText(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">S&amp;how</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">);<br /></span><span style="color: rgb(0, 128, 128);">36</span><span style="color: rgb(0, 0, 0);"><img src="../../Images/OutliningIndicators/InBlock.gif" align="top" />        <br /></span><span style="color: rgb(0, 128, 128);">37</span><span style="color: rgb(0, 0, 0);"><img id="Codehighlighter1_1030_1226_Open_Image" onclick="this.style.display='none'; Codehighlighter1_1030_1226_Open_Text.style.display='none'; Codehighlighter1_1030_1226_Closed_Image.style.display='inline'; Codehighlighter1_1030_1226_Closed_Text.style.display='inline';" src="../../Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_1030_1226_Closed_Image" style="display: none;" onclick="this.style.display='none'; Codehighlighter1_1030_1226_Closed_Text.style.display='none'; Codehighlighter1_1030_1226_Open_Image.style.display='inline'; Codehighlighter1_1030_1226_Open_Text.style.display='inline';" src="../../Images/OutliningIndicators/ContractedSubBlock.gif" align="top" />        miShow.addSelectionListener(</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> SelectionListener() </span><span id="Codehighlighter1_1030_1226_Closed_Text" style="border: 1px solid rgb(128, 128, 128); display: none; background-color: rgb(255, 255, 255);"><img src="../../Images/dot.gif" /></span><span id="Codehighlighter1_1030_1226_Open_Text"><span style="color: rgb(0, 0, 0);">{<br /></span><span style="color: rgb(0, 128, 128);">38</span><span style="color: rgb(0, 0, 0);"><img id="Codehighlighter1_1084_1152_Open_Image" onclick="this.style.display='none'; Codehighlighter1_1084_1152_Open_Text.style.display='none'; Codehighlighter1_1084_1152_Closed_Image.style.display='inline'; Codehighlighter1_1084_1152_Closed_Text.style.display='inline';" src="../../Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_1084_1152_Closed_Image" style="display: none;" onclick="this.style.display='none'; Codehighlighter1_1084_1152_Closed_Text.style.display='none'; Codehighlighter1_1084_1152_Open_Image.style.display='inline'; Codehighlighter1_1084_1152_Open_Text.style.display='inline';" src="../../Images/OutliningIndicators/ContractedSubBlock.gif" align="top" />                </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> widgetSelected(SelectionEvent arg0) </span><span id="Codehighlighter1_1084_1152_Closed_Text" style="border: 1px solid rgb(128, 128, 128); display: none; background-color: rgb(255, 255, 255);"><img src="../../Images/dot.gif" /></span><span id="Codehighlighter1_1084_1152_Open_Text"><span style="color: rgb(0, 0, 0);">{<br /></span><span style="color: rgb(0, 128, 128);">39</span><span style="color: rgb(0, 0, 0);"><img src="../../Images/OutliningIndicators/InBlock.gif" align="top" />                        shell.setVisible(</span><span style="color: rgb(0, 0, 255);">true</span><span style="color: rgb(0, 0, 0);">);<br /></span><span style="color: rgb(0, 128, 128);">40</span><span style="color: rgb(0, 0, 0);"><img src="../../Images/OutliningIndicators/InBlock.gif" align="top" />                        shell.setMaximized(</span><span style="color: rgb(0, 0, 255);">true</span><span style="color: rgb(0, 0, 0);">);<br /></span><span style="color: rgb(0, 128, 128);">41</span><span style="color: rgb(0, 0, 0);"><img src="../../Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />                }</span></span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">42</span><span style="color: rgb(0, 0, 0);"><img src="../../Images/OutliningIndicators/InBlock.gif" align="top" />        <br /></span><span style="color: rgb(0, 128, 128);">43</span><span style="color: rgb(0, 0, 0);"><img id="Codehighlighter1_1216_1222_Open_Image" onclick="this.style.display='none'; Codehighlighter1_1216_1222_Open_Text.style.display='none'; Codehighlighter1_1216_1222_Closed_Image.style.display='inline'; Codehighlighter1_1216_1222_Closed_Text.style.display='inline';" src="../../Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_1216_1222_Closed_Image" style="display: none;" onclick="this.style.display='none'; Codehighlighter1_1216_1222_Closed_Text.style.display='none'; Codehighlighter1_1216_1222_Open_Image.style.display='inline'; Codehighlighter1_1216_1222_Open_Text.style.display='inline';" src="../../Images/OutliningIndicators/ContractedSubBlock.gif" align="top" />                </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> widgetDefaultSelected(SelectionEvent arg0) </span><span id="Codehighlighter1_1216_1222_Closed_Text" style="border: 1px solid rgb(128, 128, 128); display: none; background-color: rgb(255, 255, 255);"><img src="../../Images/dot.gif" /></span><span id="Codehighlighter1_1216_1222_Open_Text"><span style="color: rgb(0, 0, 0);">{<br /></span><span style="color: rgb(0, 128, 128);">44</span><span style="color: rgb(0, 0, 0);"><img src="../../Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />                }</span></span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">45</span><span style="color: rgb(0, 0, 0);"><img src="../../Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />        }</span></span><span style="color: rgb(0, 0, 0);">);<br /></span><span style="color: rgb(0, 128, 128);">46</span><span style="color: rgb(0, 0, 0);"><img src="../../Images/OutliningIndicators/InBlock.gif" align="top" />        <br /></span><span style="color: rgb(0, 128, 128);">47</span><span style="color: rgb(0, 0, 0);"><img src="../../Images/OutliningIndicators/InBlock.gif" align="top" />        MenuItem miExit </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> MenuItem(menu, SWT.PUSH);<br /></span><span style="color: rgb(0, 128, 128);">48</span><span style="color: rgb(0, 0, 0);"><img src="../../Images/OutliningIndicators/InBlock.gif" align="top" />        miExit.setText(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">E&amp;xit</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">);<br /></span><span style="color: rgb(0, 128, 128);">49</span><span style="color: rgb(0, 0, 0);"><img src="../../Images/OutliningIndicators/InBlock.gif" align="top" />        <br /></span><span style="color: rgb(0, 128, 128);">50</span><span style="color: rgb(0, 0, 0);"><img id="Codehighlighter1_1367_1527_Open_Image" onclick="this.style.display='none'; Codehighlighter1_1367_1527_Open_Text.style.display='none'; Codehighlighter1_1367_1527_Closed_Image.style.display='inline'; Codehighlighter1_1367_1527_Closed_Text.style.display='inline';" src="../../Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_1367_1527_Closed_Image" style="display: none;" onclick="this.style.display='none'; Codehighlighter1_1367_1527_Closed_Text.style.display='none'; Codehighlighter1_1367_1527_Open_Image.style.display='inline'; Codehighlighter1_1367_1527_Open_Text.style.display='inline';" src="../../Images/OutliningIndicators/ContractedSubBlock.gif" align="top" />        miExit.addSelectionListener(</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> SelectionListener() </span><span id="Codehighlighter1_1367_1527_Closed_Text" style="border: 1px solid rgb(128, 128, 128); display: none; background-color: rgb(255, 255, 255);"><img src="../../Images/dot.gif" /></span><span id="Codehighlighter1_1367_1527_Open_Text"><span style="color: rgb(0, 0, 0);">{<br /></span><span style="color: rgb(0, 128, 128);">51</span><span style="color: rgb(0, 0, 0);"><img id="Codehighlighter1_1421_1451_Open_Image" onclick="this.style.display='none'; Codehighlighter1_1421_1451_Open_Text.style.display='none'; Codehighlighter1_1421_1451_Closed_Image.style.display='inline'; Codehighlighter1_1421_1451_Closed_Text.style.display='inline';" src="../../Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_1421_1451_Closed_Image" style="display: none;" onclick="this.style.display='none'; Codehighlighter1_1421_1451_Closed_Text.style.display='none'; Codehighlighter1_1421_1451_Open_Image.style.display='inline'; Codehighlighter1_1421_1451_Open_Text.style.display='inline';" src="../../Images/OutliningIndicators/ContractedSubBlock.gif" align="top" />                </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> widgetSelected(SelectionEvent arg0) </span><span id="Codehighlighter1_1421_1451_Closed_Text" style="border: 1px solid rgb(128, 128, 128); display: none; background-color: rgb(255, 255, 255);"><img src="../../Images/dot.gif" /></span><span id="Codehighlighter1_1421_1451_Open_Text"><span style="color: rgb(0, 0, 0);">{<br /></span><span style="color: rgb(0, 128, 128);">52</span><span style="color: rgb(0, 0, 0);"><img src="../../Images/OutliningIndicators/InBlock.gif" align="top" />                        exitAction.run();<br /></span><span style="color: rgb(0, 128, 128);">53</span><span style="color: rgb(0, 0, 0);"><img src="../../Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />                }</span></span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">54</span><span style="color: rgb(0, 0, 0);"><img src="../../Images/OutliningIndicators/InBlock.gif" align="top" />                <br /></span><span style="color: rgb(0, 128, 128);">55</span><span style="color: rgb(0, 0, 0);"><img id="Codehighlighter1_1517_1523_Open_Image" onclick="this.style.display='none'; Codehighlighter1_1517_1523_Open_Text.style.display='none'; Codehighlighter1_1517_1523_Closed_Image.style.display='inline'; Codehighlighter1_1517_1523_Closed_Text.style.display='inline';" src="../../Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_1517_1523_Closed_Image" style="display: none;" onclick="this.style.display='none'; Codehighlighter1_1517_1523_Closed_Text.style.display='none'; Codehighlighter1_1517_1523_Open_Image.style.display='inline'; Codehighlighter1_1517_1523_Open_Text.style.display='inline';" src="../../Images/OutliningIndicators/ContractedSubBlock.gif" align="top" />                </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> widgetDefaultSelected(SelectionEvent arg0) </span><span id="Codehighlighter1_1517_1523_Closed_Text" style="border: 1px solid rgb(128, 128, 128); display: none; background-color: rgb(255, 255, 255);"><img src="../../Images/dot.gif" /></span><span id="Codehighlighter1_1517_1523_Open_Text"><span style="color: rgb(0, 0, 0);">{<br /></span><span style="color: rgb(0, 128, 128);">56</span><span style="color: rgb(0, 0, 0);"><img src="../../Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />                }</span></span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">57</span><span style="color: rgb(0, 0, 0);"><img src="../../Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />        }</span></span><span style="color: rgb(0, 0, 0);">);<br /></span><span style="color: rgb(0, 128, 128);">58</span><span style="color: rgb(0, 0, 0);"><img src="../../Images/OutliningIndicators/InBlock.gif" align="top" />        <br /></span><span style="color: rgb(0, 128, 128);">59</span><span style="color: rgb(0, 0, 0);"><img src="../../Images/OutliningIndicators/InBlock.gif" align="top" />        </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);"> 为托盘对象添加事件，当右键点击图标时，显示菜单</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 128, 128);">60</span><span style="color: rgb(0, 128, 0);"><img id="Codehighlighter1_1613_1695_Open_Image" onclick="this.style.display='none'; Codehighlighter1_1613_1695_Open_Text.style.display='none'; Codehighlighter1_1613_1695_Closed_Image.style.display='inline'; Codehighlighter1_1613_1695_Closed_Text.style.display='inline';" src="../../Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_1613_1695_Closed_Image" style="display: none;" onclick="this.style.display='none'; Codehighlighter1_1613_1695_Closed_Text.style.display='none'; Codehighlighter1_1613_1695_Open_Image.style.display='inline'; Codehighlighter1_1613_1695_Open_Text.style.display='inline';" src="../../Images/OutliningIndicators/ContractedSubBlock.gif" align="top" /></span><span style="color: rgb(0, 0, 0);">        item.addListener(SWT.MenuDetect, </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> Listener() </span><span id="Codehighlighter1_1613_1695_Closed_Text" style="border: 1px solid rgb(128, 128, 128); display: none; background-color: rgb(255, 255, 255);"><img src="../../Images/dot.gif" /></span><span id="Codehighlighter1_1613_1695_Open_Text"><span style="color: rgb(0, 0, 0);">{<br /></span><span style="color: rgb(0, 128, 128);">61</span><span style="color: rgb(0, 0, 0);"><img id="Codehighlighter1_1656_1691_Open_Image" onclick="this.style.display='none'; Codehighlighter1_1656_1691_Open_Text.style.display='none'; Codehighlighter1_1656_1691_Closed_Image.style.display='inline'; Codehighlighter1_1656_1691_Closed_Text.style.display='inline';" src="../../Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_1656_1691_Closed_Image" style="display: none;" onclick="this.style.display='none'; Codehighlighter1_1656_1691_Closed_Text.style.display='none'; Codehighlighter1_1656_1691_Open_Image.style.display='inline'; Codehighlighter1_1656_1691_Open_Text.style.display='inline';" src="../../Images/OutliningIndicators/ContractedSubBlock.gif" align="top" />                </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> handleEvent(Event event) </span><span id="Codehighlighter1_1656_1691_Closed_Text" style="border: 1px solid rgb(128, 128, 128); display: none; background-color: rgb(255, 255, 255);"><img src="../../Images/dot.gif" /></span><span id="Codehighlighter1_1656_1691_Open_Text"><span style="color: rgb(0, 0, 0);">{<br /></span><span style="color: rgb(0, 128, 128);">62</span><span style="color: rgb(0, 0, 0);"><img src="../../Images/OutliningIndicators/InBlock.gif" align="top" />                        menu.setVisible(</span><span style="color: rgb(0, 0, 255);">true</span><span style="color: rgb(0, 0, 0);">);<br /></span><span style="color: rgb(0, 128, 128);">63</span><span style="color: rgb(0, 0, 0);"><img src="../../Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />                }</span></span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">64</span><span style="color: rgb(0, 0, 0);"><img src="../../Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />        }</span></span><span style="color: rgb(0, 0, 0);">);<br /></span><span style="color: rgb(0, 128, 128);">65</span><span style="color: rgb(0, 0, 0);"><img src="../../Images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span></div></div></div><br />总结：swt/jface为java程序员提供了快速反映的界面，由于swt/jface本身也是利用JNI来调用系统的界面，所以在实现界面的同时也为程序员提供了一些与操作系统交互的方法。利用这些方法，可以很方便快捷地完成我们的功能。<br /><br />Eclipse的Forms也非常不错，提供了华丽的界面，写出来的程序就如同网页一样，当然要有一定的审美眼光，有兴趣的朋友不仿研究研究。<br /><br />转自：http://www.blogjava.net/hiswing/archive/2006/08/09/62593.html<br /><img src ="http://www.blogjava.net/Duffblog/aggbug/63345.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Duffblog/" target="_blank">追球者</a> 2006-08-13 17:48 <a href="http://www.blogjava.net/Duffblog/articles/63345.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SQLServer和Oracle的常用函数对比</title><link>http://www.blogjava.net/Duffblog/articles/55171.html</link><dc:creator>追球者</dc:creator><author>追球者</author><pubDate>Mon, 26 Jun 2006 08:20:00 GMT</pubDate><guid>http://www.blogjava.net/Duffblog/articles/55171.html</guid><wfw:comment>http://www.blogjava.net/Duffblog/comments/55171.html</wfw:comment><comments>http://www.blogjava.net/Duffblog/articles/55171.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Duffblog/comments/commentRss/55171.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Duffblog/services/trackbacks/55171.html</trackback:ping><description><![CDATA[　---------数学函数
<p>　　1.绝对值 <br />　　S:select abs(-1) value<br />　　O:select abs(-1) value from dual</p><p>　　2.取整(大) <br />　　S:select ceiling(-1.001) value <br />　　O:select ceil(-1.001) value from dual</p><p>　　3.取整（小） <br />　　S:select floor(-1.001) value <br />　　O:select floor(-1.001) value from dual</p><p>　　4.取整（截取）<br />　　S:select cast(-1.002 as int) value <br />　　O:select trunc(-1.002) value from dual </p><p>　　5.四舍五入<br />　　S:select round(1.23456,4) value 1.23460<br />　　O:select round(1.23456,4) value from dual 1.2346</p><p>　　6.e为底的幂 <br />　　S:select Exp(1) value 2.7182818284590451 <br />　　O:select Exp(1) value from dual 2.71828182</p><p>　　7.取e为底的对数<br />　　S:select log(2.7182818284590451) value 1<br />　　O:select ln(2.7182818284590451) value from dual; 1</p><p>　　8.取10为底对数<br />　　S:select log10(10) value 1<br />　　O:select log(10,10) value from dual; 1</p><p>　　9.取平方<br />　　S:select SQUARE(4) value 16<br />　　O:select power(4,2) value from dual 16</p><p>　　10.取平方根<br />　　S:select SQRT(4) value 2<br />　　O:select SQRT(4) value from dual 2</p><p>　　11.求任意数为底的幂<br />　　S:select power(3,4) value 81<br />　　O:select power(3,4) value from dual 81</p><p>　　12.取随机数<br />　　S:select rand() value <br />　　O:select sys.dbms_random.value(0,1) value from dual;</p><p>　　13.取符号<br />　　S:select sign(-8) value -1<br />　　O:select sign(-8) value from dual -1<br />　　----------数学函数</p><p>　　14.圆周率<br />　　S:SELECT PI() value 3.1415926535897931<br />　　O:不知道</p><p>　　15.sin,cos,tan 参数都以弧度为单位<br />　　例如：select sin(PI()/2) value 得到1（SQLServer）</p><p>　　16.Asin,Acos,Atan,Atan2 返回弧度</p><p>　　17.弧度角度互换(SQLServer，Oracle不知道)<br />　　DEGREES：弧度-〉角度<br />　　RADIANS：角度-〉弧度</p><p>　　---------数值间比较</p><p>　　18. 求集合最大值<br />　　S:select max(value) value from <br />　　(select 1 value<br />　　union<br />　　select -2 value<br />　　union<br />　　select 4 value<br />　　union<br />　　select 3 value)a</p><p>　　O:select greatest(1,-2,4,3) value from dual</p><p>　　19. 求集合最小值<br />　　S:select min(value) value from <br />　　(select 1 value<br />　　union<br />　　select -2 value<br />　　union<br />　　select 4 value<br />　　union<br />　　select 3 value)a</p><p>　　O:select least(1,-2,4,3) value from dual</p><p>　　20.如何处理null值(F2中的null以10代替)<br />　　S:select F1,IsNull(F2,10) value from Tbl<br />　　O:select F1,nvl(F2,10) value from Tbl</p><p>　　--------数值间比较</p><p>　　21.求字符序号<br />　　S:select ascii('a') value<br />　　O:select ascii('a') value from dual</p><p>　　22.从序号求字符<br />　　S:select char(97) value<br />　　O:select chr(97) value from dual</p><p>　　23.连接<br />　　S:select '11'+'22'+'33' value<br />　　O:select CONCAT('11','22')||33 value from dual</p><p>　　23.子串位置 --返回3<br />　　S:select CHARINDEX('s','sdsq',2) value <br />　　O:select INSTR('sdsq','s',2) value from dual</p><p>　　23.模糊子串的位置 --返回2,参数去掉中间%则返回7<br />　　S:select patindex('%d%q%','sdsfasdqe') value <br />　　O:oracle没发现，但是instr可以通过第四霾问刂瞥鱿执问?BR&gt;　　select INSTR('sdsfasdqe','sd',1,2) value from dual 返回6</p><p>　　24.求子串<br />　　S:select substring('abcd',2,2) value <br />　　O:select substr('abcd',2,2) value from dual</p><p>　　25.子串代替 返回aijklmnef<br />　　S:SELECT STUFF('abcdef', 2, 3, 'ijklmn') value<br />　　O:SELECT Replace('abcdef', 'bcd', 'ijklmn') value from dual</p><p>　　26.子串全部替换<br />　　S:没发现<br />　　O:select Translate('fasdbfasegas','fa','我' ) value from dual</p><p>　　27.长度<br />　　S:len,datalength<br />　　O:length</p><p>　　28.大小写转换 lower,upper</p><p>　　29.单词首字母大写<br />　　S:没发现<br />　　O:select INITCAP('abcd dsaf df') value from dual</p><p>　　30.左补空格（LPAD的第一个参数为空格则同space函数）<br />　　S:select space(10)+'abcd' value<br />　　O:select LPAD('abcd',14) value from dual</p><p>　　31.右补空格（RPAD的第一个参数为空格则同space函数）<br />　　S:select 'abcd'+space(10) value<br />　　O:select RPAD('abcd',14) value from dual</p><p>　　32.删除空格<br />　　S:ltrim,rtrim<br />　　O:ltrim,rtrim,trim</p><p>　　33. 重复字符串<br />　　S:select REPLICATE('abcd',2) value <br />　　O:没发现</p><p>　　34.发音相似性比较(这两个单词返回值一样，发音相同)<br />　　S:SELECT SOUNDEX ('Smith'), SOUNDEX ('Smythe')<br />　　O:SELECT SOUNDEX ('Smith'), SOUNDEX ('Smythe') from dual<br />　　SQLServer中用SELECT DIFFERENCE('Smithers', 'Smythers') 比较soundex的差<br />　　返回0-4，4为同音，1最高</p><p>　　--------------日期函数</p><p>　　35.系统时间<br />　　S:select getdate() value<br />　　O:select sysdate value from dual</p><p>　　36.前后几日<br />　　直接与整数相加减</p><p>　　37.求日期<br />　　S:select convert(char(10),getdate(),20) value<br />　　O:select trunc(sysdate) value from dual<br />　　select to_char(sysdate,'yyyy-mm-dd') value from dual</p><p>　　38.求时间<br />　　S:select convert(char(8),getdate(),108) value<br />　　O:select to_char(sysdate,'hh24:mm:ss') value from dual</p><p>　　39.取日期时间的其他部分<br />　　S:DATEPART 和 DATENAME 函数 （第一个参数决定） <br />　　O:to_char函数 第二个参数决定</p><p>　　参数---------------------------------下表需要补充<br />　　year yy, yyyy <br />　　quarter qq, q (季度)<br />　　month mm, m (m O无效)<br />　　dayofyear dy, y (O表星期)<br />　　day dd, d (d O无效)<br />　　week wk, ww (wk O无效)<br />　　weekday dw (O不清楚)<br />　　Hour hh,hh12,hh24 (hh12,hh24 S无效)<br />　　minute mi, n (n O无效)<br />　　second ss, s (s O无效)<br />　　millisecond ms (O无效)<br />　　----------------------------------------------</p><p>　　40.当月最后一天<br />　　S:不知道<br />　　O:select LAST_DAY(sysdate) value from dual</p><p>　　41.本星期的某一天（比如星期日）<br />　　S:不知道<br />　　O:SELECT Next_day(sysdate,7) vaule FROM DUAL;</p><p>　　42.字符串转时间<br />　　S:可以直接转或者select cast('2004-09-08'as datetime) value<br />　　O:SELECT To_date('2004-01-05 22:09:38','yyyy-mm-dd hh24-mi-ss') vaule FROM DUAL;</p><p>　　43.求两日期某一部分的差（比如秒）<br />　　S:select datediff(ss,getdate(),getdate()+12.3) value<br />　　O:直接用两个日期相减（比如d1-d2=12.3）<br />　　SELECT (d1-d2)*24*60*60 vaule FROM DUAL;</p><p>　　44.根据差值求新的日期（比如分钟）<br />　　S:select dateadd(mi,8,getdate()) value<br />　　O:SELECT sysdate+8/60/24 vaule FROM DUAL;</p><p>　　45.求不同时区时间<br />　　S:不知道<br />　　O:SELECT New_time(sysdate,'ydt','gmt' ) vaule FROM DUAL;</p><p>　　-----时区参数,北京在东8区应该是Ydt-------<br />　　AST ADT 大西洋标准时间<br />　　BST BDT 白令海标准时间<br />　　CST CDT 中部标准时间<br />　　EST EDT 东部标准时间<br />　　GMT 格林尼治标准时间<br />　　HST HDT 阿拉斯加—夏威夷标准时间<br />　　MST MDT 山区标准时间<br />　　NST 纽芬兰标准时间<br />　　PST PDT 太平洋标准时间<br />　　YST YDT YUKON标准时间<br />　　---------------------------------------</p><img src ="http://www.blogjava.net/Duffblog/aggbug/55171.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Duffblog/" target="_blank">追球者</a> 2006-06-26 16:20 <a href="http://www.blogjava.net/Duffblog/articles/55171.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Eclipse版本介绍</title><link>http://www.blogjava.net/Duffblog/articles/53621.html</link><dc:creator>追球者</dc:creator><author>追球者</author><pubDate>Sun, 18 Jun 2006 11:18:00 GMT</pubDate><guid>http://www.blogjava.net/Duffblog/articles/53621.html</guid><wfw:comment>http://www.blogjava.net/Duffblog/comments/53621.html</wfw:comment><comments>http://www.blogjava.net/Duffblog/articles/53621.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Duffblog/comments/commentRss/53621.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Duffblog/services/trackbacks/53621.html</trackback:ping><description><![CDATA[
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span class="CharCharChar">
						<span style="mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">
								<font face="宋体">可以从</font>
						</span>
				</span>
				<span class="CharCharChar">
						<span lang="EN-US" style="FONT-FAMILY: 'Times New Roman'">eclipse.org</span>
				</span>
				<span class="CharCharChar">
						<span style="mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">
								<font face="宋体">网站</font>
						</span>
				</span>
				<span class="CharCharChar">
						<span lang="EN-US" style="FONT-FAMILY: 'Times New Roman'">(</span>
				</span>
				<span lang="EN-US" style="FONT-FAMILY: DFKai-SB">
						<a href="http://www.eclipse.org/downloads">
								<span style="mso-fareast-font-family: 宋体">http://www.eclipse.org/downloads</span>
						</a>
				</span>
				<span class="CharCharChar">
						<span lang="EN-US" style="FONT-FAMILY: 'Times New Roman'">)</span>
				</span>
				<span class="CharCharChar">
						<span style="mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">
								<font face="宋体">下载，可以发现『最新』与『最好』的版本，这两种版本通常不一样，基本上有五种版本</font>
						</span>
				</span>
				<span class="CharCharChar">
						<span style="mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">
								<font face="宋体">或建置</font>
						</span>
				</span>
				<span class="CharCharChar">
						<span lang="EN-US" style="FONT-FAMILY: 'Times New Roman'">(build)</span>
				</span>
				<span class="CharCharChar">
						<span style="mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">
								<font face="宋体">可供下载：</font>
						</span>
				</span>
		</p>
		<p class="MsoBodyText" style="MARGIN: 0cm 0cm 0pt 24pt; TEXT-INDENT: -24pt; mso-list: l0 level1 lfo1; tab-stops: list 24.0pt">
				<span>
						<span style="mso-list: Ignore">
								<span lang="EN-US" style="FONT-FAMILY: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings">
										<span style="mso-list: Ignore">n<span style="FONT: 7pt 'Times New Roman'">  </span></span>
								</span>
								<span style="FONT: 7pt 'Times New Roman'">  </span>
						</span>释出版</span>
				<span>(Latest Release builds)</span>
				<span>
						<span style="mso-spacerun: yes"> </span>E.g.,<a href="http://download.eclipse.org/eclipse/downloads/drops/R-3.1.2-200601181600/index.php">3.1.2</a><?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /?><o:p></o:p></span>
		</p>
		<p class="MsoBodyText" style="MARGIN: 0cm 0cm 0pt 24pt; TEXT-INDENT: -24pt; mso-list: l0 level1 lfo1; tab-stops: list 24.0pt">
				<span lang="EN-US" style="FONT-FAMILY: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings">
						<span style="mso-list: Ignore">
								<span style="FONT: 7pt 'Times New Roman'">               </span>
						</span>
				</span>
				<span>Releases are builds that have been declared major releases by the development team - for example "R1.0". Releases are the right builds for people who want to be on a stable, tested release, and don't need the latest greatest features and improvements. Release builds always have an "R" at the beginning of the name i.e. R1.0, R2.0 etc. Non-release builds are named according to the date of the build - for example 20011027 is the build from Oct 27, 2001.<o:p></o:p></span>
		</p>
		<p class="MsoBodyTextIndent" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">
				<font face="宋体">由<span lang="EN-US">Eclipse</span>开发团队所宣称的主要稳定版本。<span lang="EN-US">Release builds</span>经过完整测试，并具有一致性、定义清楚的功  能。它的定位就跟上市的商业软件一样。</font>
		</p>
		<p class="MsoBodyText" style="MARGIN: 0cm 0cm 0pt 24pt; TEXT-INDENT: -24pt; mso-list: l0 level1 lfo1; tab-stops: list 24.0pt">
				<span>
						<span style="mso-list: Ignore">
								<span lang="EN-US" style="FONT-FAMILY: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings">
										<span style="mso-list: Ignore">n<span style="FONT: 7pt 'Times New Roman'">  </span></span>
								</span>
								<span style="FONT: 7pt 'Times New Roman'">  </span>
						</span>稳定版</span>
				<span>(Stream Stable <span style="mso-spacerun: yes"> </span>builds)</span>
				<span>E.g., <a href="http://download.eclipse.org/eclipse/downloads/drops/S-3.2RC7-200606021317/index.php">3.2RC7</a><o:p></o:p></span>
		</p>
		<p class="MsoBodyText" style="MARGIN: 0cm 0cm 0pt 24pt; TEXT-INDENT: -24pt; mso-list: l0 level1 lfo1; tab-stops: list 24.0pt">
				<span lang="EN-US" style="FONT-FAMILY: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings">
						<span style="mso-list: Ignore">
								<span style="FONT: 7pt 'Times New Roman'">         </span>
						</span>
				</span>
				<span>Stable builds are integration builds that have been found to be stable enough for most people to use. They are promoted from integration build to stable build by the architecture team after they have been used for a few days and deemed reasonably stable. The latest stable build is the right build for people who want to stay up to date with what is going on in the latest development stream, and don't mind putting up with a few problems n in order to get the latest greatest features and bug fixes. The latest stable build is the one the development team likes people to be using, because of the valuable and timely feedback.<o:p></o:p></span>
		</p>
		<p class="MsoBodyTextIndent" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">
				<font face="宋体">比<span lang="EN-US">Release build</span>新一级的版本，经由<span lang="EN-US">Eclipse</span>开发团队测试，并认定它相当稳定。新功能通常会在此过渡版本出现。它的定位就跟商业软件的<span lang="EN-US">beta</span>版一样。</font>
		</p>
		<p class="MsoBodyText" style="MARGIN: 0cm 0cm 0pt 24pt; TEXT-INDENT: -24pt; mso-list: l0 level1 lfo1; tab-stops: list 24.0pt">
				<span>
						<span style="mso-list: Ignore">
								<span lang="EN-US" style="FONT-FAMILY: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings">
										<span style="mso-list: Ignore">n<span style="FONT: 7pt 'Times New Roman'"> </span></span>
								</span>
								<span style="FONT: 7pt 'Times New Roman'">     </span>
						</span>整合版</span>
				<span>(Stream Integration <span style="mso-spacerun: yes"> </span>builds)</span>
				<span>E.g., <a href="http://download.eclipse.org/eclipse/downloads/drops/I20060614-0843/index.php">I20060614-0843</a><o:p></o:p></span>
		</p>
		<p class="MsoBodyText" style="MARGIN: 0cm 0cm 0pt 24pt; TEXT-INDENT: -24pt; mso-list: l0 level1 lfo1; tab-stops: list 24.0pt">
				<span lang="EN-US" style="FONT-FAMILY: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings">
						<span style="mso-list: Ignore">
								<span style="FONT: 7pt 'Times New Roman'">
										<strong>
												<font face="Wingdings" size="3">  </font>
										</strong>    </span>
						</span>
				</span>
				<span>Periodically, component teams version off their work in what they believe is a stable, consistent state, and they update the build configuration to indicate that the next integration build should take this version of the component. Integration builds are built from these stable component versions that have been specified by each component team as the best version available. Integration builds may be promoted to stable builds after a few days of testing. Integration builds are built whenever new stable component versions are released into the build.<o:p></o:p></span>
		</p>
		<p class="MsoBodyTextIndent" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">
				<font face="宋体">此版本的各个独立的组件已经过<span lang="EN-US">Eclipse</span>开发团队认定具有稳定度，但不保证集成在一起没问题。若集成在一起 够稳定，它就有可能晋升成<span lang="EN-US">Stable build</span>。</font>
		</p>
		<p class="MsoBodyText" style="MARGIN: 0cm 0cm 0pt 24pt; TEXT-INDENT: -24pt; mso-list: l0 level1 lfo1; tab-stops: list 24.0pt">
				<span lang="EN-US" style="FONT-FAMILY: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings">
						<span style="mso-list: Ignore">n<span style="FONT: 7pt 'Times New Roman'">    </span></span>
				</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">当日最新版（</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">Stream Nightly </span>
				<span lang="EN-US">
						<span style="mso-spacerun: yes"> </span>builds)</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">E.g., <a href="http://download.eclipse.org/eclipse/downloads/drops/N20060617-0010/index.php">N20060617-0010</a></span>
				<span lang="EN-US" style="mso-fareast-font-family: DFKai-SB">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoBodyText" style="MARGIN: 0cm 0cm 0pt 24pt; TEXT-INDENT: -24pt; mso-list: l0 level1 lfo1; tab-stops: list 24.0pt">
				<span lang="EN-US" style="FONT-FAMILY: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings">
						<span style="mso-list: Ignore">
								<span style="FONT: 7pt 'Times New Roman'">                </span>
						</span>
				</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">Nightly builds are produced every night from whatever has been released into the HEAD stream of the CVS repository. They are completely untested and will almost always have major problems. Many will not work at all. These drops are normally only useful to developers actually working on the Eclipse Project.</span>
				<span lang="EN-US" style="mso-fareast-font-family: DFKai-SB">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoBodyTextIndent" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">
				<font face="宋体">此版本显然是从最新的原始码产生出来的。可想而知，此版本当然不保证它跑起来没问题，搞不好还有严重的<span lang="EN-US">bug</span>。</font>
		</p>
		<p class="MsoBodyText" style="MARGIN: 0cm 0cm 0pt 24pt; TEXT-INDENT: -24pt; mso-list: l0 level1 lfo1; tab-stops: list 24.0pt">
				<span>
						<span style="mso-list: Ignore">
								<span style="FONT: 7pt 'Times New Roman'"> <span lang="EN-US" style="FONT-FAMILY: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings"><span style="mso-list: Ignore"><strong><font size="3">n</font></strong><span style="FONT: 7pt 'Times New Roman'"> </span></span></span>  </span>
						</span>维护版</span>
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">(Stream Maintenance Build) E.g.,.<u><span style="COLOR: blue"> R2_1_maintenance</span></u></span>
				<u>
						<span style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">，</span>
				</u>
				<u>
						<span lang="EN-US" style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: Arial">R2.1 or R<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" /?><st1:chsdate year="1899" month="12" day="30" islunardate="False" isrocdate="False" w:st="on">2.1.2</st1:chsdate></span>
				</u>
				<span lang="EN-US" style="mso-fareast-font-family: DFKai-SB">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">Maintenance builds are produced periodically to incorporate fixes into an existing release. They are typically built from tagged plug-in and feature pojects in a maintenance stream of the CVS repository (i.e. R2_1_maintenance). Maintenance builds are promoted to a minor or service release (i.e. R2.1 or R<st1:chsdate year="1899" month="12" day="30" islunardate="False" isrocdate="False" w:st="on">2.1.2</st1:chsdate>) after development teams have deemed one to be stable following one or more test-fix pass cycles.<br /></span>
		</p>
<img src ="http://www.blogjava.net/Duffblog/aggbug/53621.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Duffblog/" target="_blank">追球者</a> 2006-06-18 19:18 <a href="http://www.blogjava.net/Duffblog/articles/53621.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>网络经典命令</title><link>http://www.blogjava.net/Duffblog/articles/53619.html</link><dc:creator>追球者</dc:creator><author>追球者</author><pubDate>Sun, 18 Jun 2006 11:11:00 GMT</pubDate><guid>http://www.blogjava.net/Duffblog/articles/53619.html</guid><wfw:comment>http://www.blogjava.net/Duffblog/comments/53619.html</wfw:comment><comments>http://www.blogjava.net/Duffblog/articles/53619.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Duffblog/comments/commentRss/53619.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Duffblog/services/trackbacks/53619.html</trackback:ping><description><![CDATA[
		<p>
				<font color="#ff0000">
						<b>1、测试物理网络</b>
				</font>
		</p>
		<p>命令：<font color="#0000ff">ping 192.168.0.8 －t</font> ，参数－t是等待用户去中断测试</p>
		<p>友情提示：这个是最基本，最常用的网络命令</p>
		<p>
				<font color="#ff0000">
						<b>2.查看DNS、IP、Mac等信息</b>
				</font>
		</p>
		<p>A.Win98：<font color="#0000ff">winipcfg</font></p>
		<p>B.Win2000以上：<font color="#0000ff">Ipconfig/all</font></p>
		<p>
				<font color="#ff0000">
						<b>3.网络信使</b>
				</font>
		</p>
		<p>命令：<font color="#0000ff">Net send 计算机名/IP</font>　* (广播) 传送内容，注意不能跨网段</p>
		<p>命令：<font color="#0000ff">net stop messenger </font>停止信使服务，也可以在面板－服务修改</p>
		<p>命令：<font color="#0000ff">net start messenger</font> 开始信使服务</p>
		<p>
				<b>
						<font color="#ff0000">4.探测对方计算机名，所在的组、域及当前用户名 （追捕的工作原理）</font>
				</b>
		</p>
		<p>命令：<font color="#0000ff">ping －a IP －t </font>，只显示NetBios名</p>
		<p>命令：<font color="#0000ff">nbtstat -a</font><font color="#0000ff">IP </font>比较全的</p>
		<p>
				<b>
						<font color="#ff0000">5.netstat -a 显示出你的计算机当前所开放的所有端口</font>
				</b>
		</p>
		<p>命令：<font color="#0000ff">netstat -s -e </font></p>
		<p>比较详细的显示你的网络资料，包括TCP、UDP、ICMP 和 IP的统计等</p>
		<p>
				<font color="#ff0000">
						<b>6.探测arp绑定（动态和静态）列表，显示所有连接了我的计算机，显示对方IP和MAC地址</b>
				</font>
		</p>
		<p>命令：<font color="#ff0000">arp -a<br /><br /></font></p>
		<p>
				<b>
						<font color="#ff0000">7.在代理服务器端</font>
				</b>
		</p>
		<p>捆绑IP和MAC地址，解决局域网内盗用IP！：</p>
		<p>命令：<font color="#0000ff">ARP －s 192.168.10.59 00 －50－ff－6c－08－75</font></p>
		<p>解除网卡的IP与MAC地址的绑定：</p>
		<p>命令：<font color="#0000ff">arp -d 网卡IP</font></p>
		<p>
				<b>
						<font color="#ff0000">8.在网络邻居上隐藏你的计算机</font>
				</b>
		</p>
		<p>命令：<font color="#0000ff">net config server /hidden:yes</font></p>
		<p>命令：<font color="#0000ff">net config server /hidden:no </font>则为开启</p>
		<p>
				<b>
						<font color="#ff0000">9.net命令</font>
				</b>
		</p>
		<p>A.显示当前工作组服务器列表<font color="#0000ff"> net view</font>，当不带选项使用本命令时，它就会显示当前域或网络上的计算机上的列表。</p>
		<p>比如：查看这个IP上的共享资源，就可以</p>
		<p>C:\&gt;<font color="#0000ff">net view 192.168.10.8</font></p>
		<p>在 192.168.10.8 的共享资源</p>
		<p>资源共享名 类型 用途 注释</p>
		<p>
		</p>
		<p>网站服务<font color="#0000ff"> Disk</font></p>
		<p>命令成功完成。</p>
		<p>B.查看计算机上的用户帐号列表 <font color="#0000ff">net user</font></p>
		<p>C.查看网络链接 <font color="#0000ff">net use</font></p>
		<p>例如：net use z: \192.168.10.8\movie 将这个IP的movie共享目录映射为本地的Z盘</p>
		<p>D.记录链接 <font color="#0000ff">net session</font></p>
		<p>例如: C:\&gt;net session</p>
		<p>计算机 用户名 客户类型 打开空闲时间</p>
		<p>
		</p>
		<p>\192.168.10.110 ROME Windows 2000 2195 0 00:03:12</p>
		<p>\192.168.10.51 ROME Windows 2000 2195 0 00:00:39</p>
		<p>命令成功完成。<br /><br /></p>
		<p>
				<b>
						<font color="#ff0000">10.路由跟踪命令</font>
				</b>
		</p>
		<p>A.tracert software.pchome.net</p>
		<p>B.pathping software.pchome.net 除了显示路由外，还提供325S的分析，计算丢失包的％</p>
		<p>
				<font color="#ff0000">
						<b>11.关于共享安全的几个命令</b>
				</font>
		</p>
		<p>A.查看你机器的共享资源 <font color="#0000ff">net share</font></p>
		<p>B.手工删除共享（可以编个bat文件，开机自运行，把共享都删了！）</p>
		<p>命令：net share c$ /d</p>
		<p>命令：net share d$ /d</p>
		<p>命令：net share ipc$ /d</p>
		<p>命令：net share admin$ /d</p>
		<p>注意$后有空格。</p>
		<p>C.增加一个共享：</p>
		<p>c:\net share mymovie=e:\downloads\movie /users:1</p>
		<p>
				<font color="#0000ff">mymovie </font>共享成功。</p>
		<p>同时限制链接用户数为1人。</p>
		<p>
				<b>
						<font color="#ff0000">12.在DOS行下设置静态IP</font>
				</b>
		</p>
		<p>
				<font color="#0000ff">A.设置静态IP</font>
		</p>
		<p>CMD</p>
		<p>netsh</p>
		<p>netsh&gt;int</p>
		<p>interface&gt;ip</p>
		<p>interface ip&gt;set add "本地链接" static IP地址 mask gateway</p>
		<p>
				<font color="#0000ff">B.查看IP设置</font>
		</p>
		<p>interface ip&gt;show address</p>
		<p>Arp</p>
		<p>显示和修改“地址解析协议 (ARP)”缓存中的项目。ARP 缓存中包含一个或多个表，它们用于存储 IP 地址及其经过解析的以太网或令牌环物理地址。计算机上安装的每一个以太网或令牌环网络适配器都有自己单独的表。如果在没有参数的情况下使用，则 arp 命令将显示帮助信息。</p>
<img src ="http://www.blogjava.net/Duffblog/aggbug/53619.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Duffblog/" target="_blank">追球者</a> 2006-06-18 19:11 <a href="http://www.blogjava.net/Duffblog/articles/53619.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>win XP命令集锦~~ </title><link>http://www.blogjava.net/Duffblog/articles/53609.html</link><dc:creator>追球者</dc:creator><author>追球者</author><pubDate>Sun, 18 Jun 2006 09:28:00 GMT</pubDate><guid>http://www.blogjava.net/Duffblog/articles/53609.html</guid><wfw:comment>http://www.blogjava.net/Duffblog/comments/53609.html</wfw:comment><comments>http://www.blogjava.net/Duffblog/articles/53609.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Duffblog/comments/commentRss/53609.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Duffblog/services/trackbacks/53609.html</trackback:ping><description><![CDATA[
		<p>近日收集了一些XP的命令，有些很有用，列出来共享~<br />我找了些，不知道有没有用处~~<br />winver---------检查Windows版本 <br />wmimgmt.msc----打开windows管理体系结构(WMI) <br />wupdmgr--------windows更新程序 <br />wscript--------windows脚本宿主设置 <br />write----------写字板 <br />winmsd---------系统信息 <br />wiaacmgr-------扫描仪和照相机向导 <br />winchat--------XP自带局域网聊天 <br />mem.exe--------显示内存使用情况 <br /><font color="#ff1493">Msconfig.exe---系统配置实用程序 </font><br />mplayer2-------简易widnows media player <br />mspaint--------画图板 <br />mstsc----------远程桌面连接 <br />mplayer2-------媒体播放机 <br />magnify--------放大镜实用程序 <br />mmc------------打开控制台 <br />mobsync--------同步命令 <br /><font color="#ff1493">dxdiag---------检查DirectX信息 </font><br /><font color="#ff1493">drwtsn32------ 系统医生 </font><br />devmgmt.msc--- 设备管理器 <br />dfrg.msc-------磁盘碎片整理程序 <br />diskmgmt.msc---磁盘管理实用程序 <br />dcomcnfg-------打开系统组件服务 <br />ddeshare-------打开DDE共享设置 <br />dvdplay--------DVD播放器 <br />net stop messenger-----停止信使服务 <br />net start messenger----开始信使服务 <br />notepad--------打开记事本 <br />nslookup-------网络管理的工具向导 <br />ntbackup-------系统备份和还原 <br />narrator-------屏幕“讲述人” <br />ntmsmgr.msc----移动存储管理器 <br />ntmsoprq.msc---移动存储管理员操作请求 <br />netstat -an----(TC)命令检查接口 <br />syncapp--------创建一个公文包 <br />sysedit--------系统配置编辑器 <br />sigverif-------文件签名验证程序 <br />sndrec32-------录音机 <br />shrpubw--------创建共享文件夹 <br />secpol.msc-----本地安全策略 <br /><font color="#ff1493">syskey---------系统加密，一旦加密就不能解开，保护windows xp系统的双重密码 </font><br /><font color="#ff1493">services.msc---本地服务设置 </font><br />Sndvol32-------音量控制程序 <br />sfc.exe--------系统文件检查器 <br />sfc /scannow---windows文件保护 <br />tsshutdn-------60秒倒计时关机命令 <br />tourstart------xp简介（安装完成后出现的漫游xp程序） <br />taskmgr--------任务管理器 <br />eventvwr-------事件查看器 <br />eudcedit-------造字程序 <br />explorer-------打开资源管理器 <br />packager-------对象包装程序 <br />perfmon.msc----计算机性能监测程序 <br />progman--------程序管理器 <br /><font color="#ff1493">regedit.exe----注册表 </font><br /><font color="#ff1493">rsop.msc-------组策略结果集 </font><br /><font color="#ff1493">regedt32-------注册表编辑器 </font><br />rononce -p ----15秒关机 <br />regsvr32 /u *.dll----停止dll文件运行 <br />regsvr32 /u zipfldr.dll------取消ZIP支持 <br />cmd.exe--------CMD命令提示符 <br />chkdsk.exe-----Chkdsk磁盘检查 <br />certmgr.msc----证书管理实用程序 <br />calc-----------启动计算器 <br />charmap--------启动字符映射表 <br />cliconfg-------SQL SERVER 客户端网络实用程序 <br />Clipbrd--------剪贴板查看器 <br />conf-----------启动netmeeting <br />compmgmt.msc---计算机管理 <br />cleanmgr-------垃圾整理 <br />ciadv.msc------索引服务程序 <br />osk------------打开屏幕键盘 <br />odbcad32-------ODBC数据源管理器 <br />oobe/msoobe /a----检查XP是否激活 <br />lusrmgr.msc----本机用户和组 <br />logoff---------注销命令 <br />iexpress-------木马捆绑工具，系统自带 <br /><font color="#ff1493">Nslookup-------IP地址侦测器 </font><br />fsmgmt.msc-----共享文件夹管理器 <br />utilman--------辅助工具管理器 <br /><font color="#ff1493">gpedit.msc-----组策略</font><br />上面彩色的是常用的（至少是我常用到的）..</p>
		<p>觉得有用,记得点收藏哦~~</p>
<img src ="http://www.blogjava.net/Duffblog/aggbug/53609.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Duffblog/" target="_blank">追球者</a> 2006-06-18 17:28 <a href="http://www.blogjava.net/Duffblog/articles/53609.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>cglib的应用 </title><link>http://www.blogjava.net/Duffblog/articles/53507.html</link><dc:creator>追球者</dc:creator><author>追球者</author><pubDate>Sat, 17 Jun 2006 12:30:00 GMT</pubDate><guid>http://www.blogjava.net/Duffblog/articles/53507.html</guid><wfw:comment>http://www.blogjava.net/Duffblog/comments/53507.html</wfw:comment><comments>http://www.blogjava.net/Duffblog/articles/53507.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Duffblog/comments/commentRss/53507.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Duffblog/services/trackbacks/53507.html</trackback:ping><description><![CDATA[反射、Proxy和元数据是Java最强的三个特征，再加上<a href="http://cglib.sf.net/"><font color="#366900">CGLib (Code Generation Library)</font></a>和ASM，使得Java虽然没有Ruby，Python般后生可畏，一样能做出强悍的框架。<br />   Proxy可以看作是微型的AOP，明白提供了在继承和委托之外的第三个代码封装途径，只要有足够的想象力，可以做得非常好玩，Spring的源码里用Proxy就用得很随便，看得我非常眼红。可惜Proxy必须基于接口。因此Spring的做法，基于接口的用proxy,否则就用cglib。AOP么，一般小事非compoent一级的就不麻烦AspectJ出手了。<br /><br />    cglib的Enhancer说起来神奇，用起来一页纸不到就讲完了。<br />    它的原理就是用Enhancer生成一个原有类的子类，并且设置好callback ， 则原有类的每个方法调用都会转成调用实现了MethodInterceptor接口的proxy的intercept() 函数：<br /><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> Object intercept(Object o,Method method,Object[] args,MethodProxy proxy)</span></div><br /> 在intercept()函数里，你可以在执行Object result=proxy.invokeSuper(o,args);来执行原有函数，在执行前后加入自己的东西，改变它的参数值，也可以瞒天过海，完全干别的。说白了，就是AOP中的around advice。 <br /><p>    AOP没有出现以前，该领域经典的设计模式是Decorator，像Java IO Stream的设计就是如此.不过，如果为每个DAO, 每个方法的写Decorator函数会写死人的，所以用上cglib的好处是一次过拦截所有方法。 <br /><br />     另外，cglib除了Enhancer之外，还有BulkBean和Transform，都是Hibernate持久化的基础，但文档贫乏，一时还没去看怎么用。<br /><br /><strong>1.AOP里讲了一百遍阿一百遍的log aspect在cglib是这样做的:<br /></strong></p><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000"><br />   </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> LogDAOProxy </span><span style="COLOR: #0000ff">implements</span><span style="COLOR: #000000"> MethodInterceptor<br />   {<br />       </span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000"> Logger log</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">Logger.getLogger(AOPInstrumenter.</span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">);<br />       </span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000"> Enhancer enhancer</span><span style="COLOR: #000000">=</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> Enhancer();<br />        </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">返回DAO的子类</span><span style="COLOR: #008000"><br /></span><span style="COLOR: #000000">       </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> Object getDAO(Class clz)<br />       {<br />           enhancer.setSuperclass(clz);<br />           enhancer.setCallback(</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">);<br />           </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> enhancer.create();<br />       }<br />       </span><span style="COLOR: #008000">//默认</span><span style="COLOR: #008000">的拦截方法</span><span style="COLOR: #008000"><br /></span><span style="COLOR: #000000">      </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> Object intercept(Object o,Method method,Object[] args,MethodProxy proxy) </span><span style="COLOR: #0000ff">throws</span><span style="COLOR: #000000"> Throwable<br />      {<br />           log.info(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">调用日志方法</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">method.getName());<br />           Object result</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">proxy.invokeSuper(o,args);<br />           </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> result;<br />      }<br />   }</span></div><br />    应用的代码:<br /><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000">    LogDAOProxy proxy </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> LogDAOProxy();<br />    GoodsDAO  dao </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> (GoodsDAO)proxy.getDAO(GoodsDAO.</span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">);<br />    dao.insert(goods);</span></div><br /><strong>2<font size="2">.而在Spring的管理下应该略加修改的高级Decorator</font><br /></strong>   上面的例子用<span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> enhancer.create();创建子类实例，但在Spring管理下，一些Bean的实例必须由Spring来创建和管理，而不由enhancer来创建的。所以我对上述用法略加修改，使它真正当一个Proxy的角色，请对比黑体字的部分<br /></span><br /><br /><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000">  </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> LogDAOProxy </span><span style="COLOR: #0000ff">implements</span><span style="COLOR: #000000"> MethodInterceptor<br />  {<br />       </span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000"> Logger log</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">Logger.getLogger(AOPInstrumenter.</span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">);<br />     <strong>  </strong></span><strong><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000"> Object dao</span><span style="COLOR: #000000">=</span><span style="COLOR: #0000ff">null</span></strong><span style="COLOR: #000000"><strong>;</strong><br />       </span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000"> Enhancer enhancer</span><span style="COLOR: #000000">=</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> Enhancer();<br />        </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">返回DAO的子类</span><span style="COLOR: #008000"><br /></span><span style="COLOR: #000000">       </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> Object getDAO(Class clz,Object dao)<br />       {<br />           </span><strong><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">.dao </span><span style="COLOR: #000000">=</span></strong><span style="COLOR: #000000"><strong> dao;<br /></strong>           enhancer.setSuperclass(clz);<br />           enhancer.setCallback(</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">);<br />           </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> enhancer.create();<br />       }      <br />       </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">默认的拦截方法</span><span style="COLOR: #008000"><br /></span><span style="COLOR: #000000">      </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> Object intercept(Object o,Method method,Object[] args,MethodProxy proxy) </span><span style="COLOR: #0000ff">throws</span><span style="COLOR: #000000"> Throwable<br />      {<br />           log.info(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">调用日志方法</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">method.getName());<br />           <strong>Object result</strong></span><span style="COLOR: #000000"><strong>=</strong></span><span style="COLOR: #000000"><strong>proxy.invoke(dao, args);</strong><br />           </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> result;<br />      }<br />  }</span></div><br />有点遗憾, intercept函数里MethodProxy的Signature是固定的 , 即客户如果调用foo(String),你不可以用proxy.invoke偷换成foo(String,String);<br /><img src ="http://www.blogjava.net/Duffblog/aggbug/53507.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Duffblog/" target="_blank">追球者</a> 2006-06-17 20:30 <a href="http://www.blogjava.net/Duffblog/articles/53507.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>