﻿<?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-JAVA学习之路-文章分类-Java语言</title><link>http://www.blogjava.net/joaquin25/category/27822.html</link><description /><language>zh-cn</language><lastBuildDate>Fri, 23 May 2008 09:27:39 GMT</lastBuildDate><pubDate>Fri, 23 May 2008 09:27:39 GMT</pubDate><ttl>60</ttl><item><title>使用FilenameFilter</title><link>http://www.blogjava.net/joaquin25/articles/202452.html</link><dc:creator>joaquin25</dc:creator><author>joaquin25</author><pubDate>Fri, 23 May 2008 09:23:00 GMT</pubDate><guid>http://www.blogjava.net/joaquin25/articles/202452.html</guid><wfw:comment>http://www.blogjava.net/joaquin25/comments/202452.html</wfw:comment><comments>http://www.blogjava.net/joaquin25/articles/202452.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/joaquin25/comments/commentRss/202452.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/joaquin25/services/trackbacks/202452.html</trackback:ping><description><![CDATA[
		<p class="MsoNormal" style="TEXT-ALIGN: left" align="left">
				<strong>
						<span style="FONT-SIZE: 10pt">转自：<a href="http://hi.baidu.com/j2ee_cn/blog/item/1b5e84098468c8216b60fb37.html">http://hi.baidu.com/j2ee_cn/blog/item/1b5e84098468c8216b60fb37.html</a><br /><br />package</span>
				</strong>
				<span style="FONT-SIZE: 10pt"> filter; <br /></span>
				<strong>
						<span style="FONT-SIZE: 10pt">import</span>
				</strong>
				<span style="FONT-SIZE: 10pt"> java.io.File;<br /></span>
				<strong>
						<span style="FONT-SIZE: 10pt">import</span>
				</strong>
				<span style="FONT-SIZE: 10pt"> java.io.FilenameFilter;</span>
				<span style="FONT-SIZE: 10pt">
						<br />
				</span>
				<strong>
						<span style="FONT-SIZE: 10pt">public</span>
				</strong>
				<span style="FONT-SIZE: 10pt">
				</span>
				<strong>
						<span style="FONT-SIZE: 10pt">class</span>
				</strong>
				<span style="FONT-SIZE: 10pt">
				</span>
				<span style="FONT-SIZE: 10pt">ImageFile </span>
				<strong>
						<span style="FONT-SIZE: 10pt">implements</span>
				</strong>
				<span style="FONT-SIZE: 10pt"> FilenameFilter {<br /></span>
				<strong>
						<span style="FONT-SIZE: 10pt">      private</span>
				</strong>
				<span style="FONT-SIZE: 10pt"> String </span>
				<span style="FONT-SIZE: 10pt">fileName</span>
				<span style="FONT-SIZE: 10pt">;<br /></span>
				<strong>
						<span style="FONT-SIZE: 10pt">      private</span>
				</strong>
				<span style="FONT-SIZE: 10pt"> String[] </span>
				<span style="FONT-SIZE: 10pt">imageFiles</span>
				<span style="FONT-SIZE: 10pt">={</span>
				<span style="FONT-SIZE: 10pt">".gif"</span>
				<span style="FONT-SIZE: 10pt">,</span>
				<span style="FONT-SIZE: 10pt">".jpg"</span>
				<span style="FONT-SIZE: 10pt">,</span>
				<span style="FONT-SIZE: 10pt">".bmp"</span>
				<span style="FONT-SIZE: 10pt">,</span>
				<span style="FONT-SIZE: 10pt">".png"</span>
				<span style="FONT-SIZE: 10pt">};<br /></span>
				<strong>
						<span style="FONT-SIZE: 10pt">      private</span>
				</strong>
				<span style="FONT-SIZE: 10pt">
				</span>
				<strong>
						<span style="FONT-SIZE: 10pt">boolean</span>
				</strong>
				<span style="FONT-SIZE: 10pt"> isImage()</span>
				<span style="FONT-SIZE: 10pt">{<br /></span>
				<strong>
						<span style="FONT-SIZE: 10pt">            boolean</span>
				</strong>
				<span style="FONT-SIZE: 10pt"> flag=</span>
				<strong>
						<span style="FONT-SIZE: 10pt">false</span>
				</strong>
				<span style="FONT-SIZE: 10pt">;<br /></span>
				<strong>
						<span style="FONT-SIZE: 10pt">            for</span>
				</strong>
				<span style="FONT-SIZE: 10pt">(String <span style="BACKGROUND: silver 0% 50%; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">file</span>: </span>
				<span style="FONT-SIZE: 10pt">imageFiles</span>
				<span style="FONT-SIZE: 10pt">)</span>
				<span style="FONT-SIZE: 10pt">{<br /></span>
				<strong>
						<span style="FONT-SIZE: 10pt">                  if</span>
				</strong>
				<span style="FONT-SIZE: 10pt">(</span>
				<span style="FONT-SIZE: 10pt">fileName</span>
				<span style="FONT-SIZE: 10pt">.endsWith(<span style="BACKGROUND: silver 0% 50%; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">file</span>))</span>
				<span style="FONT-SIZE: 10pt">{<br /></span>
				<span style="FONT-SIZE: 10pt">                        flag=</span>
				<strong>
						<span style="FONT-SIZE: 10pt">true</span>
				</strong>
				<span style="FONT-SIZE: 10pt">;<br /></span>
				<strong>
						<span style="FONT-SIZE: 10pt">                        break</span>
				</strong>
				<span style="FONT-SIZE: 10pt">;<br /></span>
				<span style="FONT-SIZE: 10pt">                  }<br /></span>
				<span style="FONT-SIZE: 10pt">            }<br /></span>
				<span style="FONT-SIZE: 10pt">
						<span>    </span>
				</span>
				<strong>
						<span style="FONT-SIZE: 10pt">return</span>
				</strong>
				<span style="FONT-SIZE: 10pt"> flag;<br /></span>
				<span style="FONT-SIZE: 10pt">
						<span>    </span>}<br /><br /></span>
				<span style="FONT-SIZE: 10pt">
						<span>    </span>
				</span>
				<span style="FONT-SIZE: 10pt">@Override<br /></span>
				<span style="FONT-SIZE: 10pt">
						<span>    </span>
				</span>
				<strong>
						<span style="FONT-SIZE: 10pt">public</span>
				</strong>
				<span style="FONT-SIZE: 10pt">
				</span>
				<strong>
						<span style="FONT-SIZE: 10pt">boolean</span>
				</strong>
				<span style="FONT-SIZE: 10pt"> accept(File dir, String fileName) {</span>
				<span style="FONT-SIZE: 10pt">
						<br />
				</span>
				<span style="FONT-SIZE: 10pt">
						<span>          </span>
				</span>
				<strong>
						<span style="FONT-SIZE: 10pt">this</span>
				</strong>
				<span style="FONT-SIZE: 10pt">.</span>
				<span style="FONT-SIZE: 10pt">fileName</span>
				<span style="FONT-SIZE: 10pt">=fileName.toLowerCase();<br /></span>
				<span style="FONT-SIZE: 10pt">
						<span>          </span>
				</span>
				<strong>
						<span style="FONT-SIZE: 10pt">return</span>
				</strong>
				<span style="FONT-SIZE: 10pt"> isImage();<br /></span>
				<span style="FONT-SIZE: 10pt">
						<span>    </span>}<br /></span>
				<span style="FONT-SIZE: 10pt">}<br /><br /></span>
				<strong>
						<span style="FONT-SIZE: 10pt">package</span>
				</strong>
				<span style="FONT-SIZE: 10pt"> filter; <br /></span>
				<strong>
						<span style="FONT-SIZE: 10pt">import</span>
				</strong>
				<span style="FONT-SIZE: 10pt"> java.io.*;<br /></span>
				<strong>
						<span style="FONT-SIZE: 10pt">public</span>
				</strong>
				<span style="FONT-SIZE: 10pt">
				</span>
				<strong>
						<span style="FONT-SIZE: 10pt">class</span>
				</strong>
				<span style="FONT-SIZE: 10pt">
				</span>
				<span style="FONT-SIZE: 10pt">FileListDemo </span>
				<span style="FONT-SIZE: 10pt">{<br /></span>
				<strong>
						<span style="FONT-SIZE: 10pt">public</span>
				</strong>
				<span style="FONT-SIZE: 10pt">
				</span>
				<strong>
						<span style="FONT-SIZE: 10pt">static</span>
				</strong>
				<span style="FONT-SIZE: 10pt">
				</span>
				<strong>
						<span style="FONT-SIZE: 10pt">void</span>
				</strong>
				<span style="FONT-SIZE: 10pt"> main(String[] args) {<br /></span>
				<span style="FONT-SIZE: 10pt">      File dir=</span>
				<strong>
						<span style="FONT-SIZE: 10pt">new</span>
				</strong>
				<span style="FONT-SIZE: 10pt"> File(</span>
				<span style="FONT-SIZE: 10pt">"D:/</span>
				<span style="FONT-SIZE: 10pt; COLOR: rgb(42,0,255)">小图</span>
				<span style="FONT-SIZE: 10pt">"</span>
				<span style="FONT-SIZE: 10pt">);<br /></span>
				<span style="FONT-SIZE: 10pt">      String[] imageFiles=dir.list(</span>
				<strong>
						<span style="FONT-SIZE: 10pt">new</span>
				</strong>
				<span style="FONT-SIZE: 10pt"> ImageFile());<br /></span>
				<strong>
						<span style="FONT-SIZE: 10pt">      for</span>
				</strong>
				<span style="FONT-SIZE: 10pt">(String file:imageFiles){<br /></span>
				<span style="FONT-SIZE: 10pt">      System.</span>
				<em>
						<span style="FONT-SIZE: 10pt">out</span>
				</em>
				<span style="FONT-SIZE: 10pt">.println(file);<br /></span>
				<span style="FONT-SIZE: 10pt">      }<br /></span>
				<span style="FONT-SIZE: 10pt">}</span>
		</p>
<img src ="http://www.blogjava.net/joaquin25/aggbug/202452.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/joaquin25/" target="_blank">joaquin25</a> 2008-05-23 17:23 <a href="http://www.blogjava.net/joaquin25/articles/202452.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JAXP 全面介绍，第 1 部分: XML 处理工具包使解析和验证变得更容易</title><link>http://www.blogjava.net/joaquin25/articles/200370.html</link><dc:creator>joaquin25</dc:creator><author>joaquin25</author><pubDate>Wed, 14 May 2008 03:28:00 GMT</pubDate><guid>http://www.blogjava.net/joaquin25/articles/200370.html</guid><wfw:comment>http://www.blogjava.net/joaquin25/comments/200370.html</wfw:comment><comments>http://www.blogjava.net/joaquin25/articles/200370.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/joaquin25/comments/commentRss/200370.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/joaquin25/services/trackbacks/200370.html</trackback:ping><description><![CDATA[
		<blockquote>转自：<a href="http://hi.baidu.com/coolbattier/blog/item/d55f94b4e15413778bd4b280.html">http://hi.baidu.com/coolbattier/blog/item/d55f94b4e15413778bd4b280.html</a><br /><br />Java API for XML Processing (JAXP) 允许使用几种不同的 API 来验证、解析和转换 XML。JAXP 既提供了使用方便性，又提供了开发商中立性。 本系列介绍 JAXP，由两部分组成。本文是第一部分，向您展示如何利用 API 的解析和验证特性。第二部分介绍使用 JAXP 进行 XSL 转换。</blockquote>Java 技术和 XML 无疑是最近五年来最重要的编程开发工具。因此，用于在 Java 语言中处理 XML 的 API 就发展起来了。两个最流行的 —— 文档对象模型 (DOM) 和 Simple API for XML (SAX) —— 已经产生巨大的影响，JDOM 和数据绑定 API 也随之产生了（参阅 <a href="http://www.ibm.com/developerworks/cn/xml/x-jaxp/#resources"><font color="#996699">参考资料</font></a>）。彻底理解其中一个或两个 API 是非常必要的；正确使用全部 API 会让您成为权威。但是，越来越多的 Java 开发人员发现他们不再需要广泛了解 SAX 和 DOM —— 这主要是由于 Sun Microsystems 的 JAXP 工具包。<strong>Java API for XML Processing (JAXP)</strong> 使得 XML 甚至对于 Java 初级开发人员也变得易于掌握，并大大提高了高级开发人员的能力。也就是说，即使使用 JAXP 的高级开发人员对于他们十分依赖的 API 也有误解。 
<p>本文假设您已基本了解 SAX 和 DOM。如果您完全不懂 XML 解析，那么可能需要首先阅读在线参考资料中有关 SAX 和 DOM 的信息，或者浏览我的书（参阅 <a href="http://www.ibm.com/developerworks/cn/xml/x-jaxp/#resources"><font color="#996699">参考资料</font></a>）。您不需要精通回调或 DOM <code><font face="新宋体">Node</font></code>，但必须至少了解是 SAX 和 DOM 在解析 API。本文还有助于基本了解它们之间的差别。如果您掌握了这些基本知识，本文将对您更有帮助。</p><p><a name="N10072"><span class="atitle">JAXP：是 API 还是抽象？</span></a></p><p>严格说来，JAXP 是 API，但更准确地说是<strong>抽象层</strong>。它没有提供解析 XML 的新方法，没有添加到 SAX 或 DOM，也没有为 Java 和 XML 处理提供新功能。（如果您还不相信这一点，那么阅读这篇文章算对了。）但是，JAXP 使得使用 DOM 和 SAX 来处理一些困难任务变得更容易。它还允许以开发商中立的方式处理一些在使用 DOM 和 SAX API 时可能遇到的特定于开发商的任务。</p><table cellspacing="0" cellpadding="0" width="45%" align="right" border="0"><tbody><tr><td width="10"><img height="1" 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="bigtime"><strong>逐渐晋级</strong></a><br /><p>在 Java 平台的早期版本中，JAXP 是核心平台中单独的下载。在 Java 5.0 中，JAXP 已经是 Java 语言的主要产品。如果已经有最新版本的 JDK（参阅 <a href="http://www.ibm.com/developerworks/cn/xml/x-jaxp/#resources"><font color="#996699">参考资料</font></a>），您就已经获得了 JAXP。</p></td></tr></tbody></table></td></tr></tbody></table><p>没有 SAX、DOM 或另一个 XML 解析 API，<em>则无法解析 XML</em>。我曾经看到过许多关于将 SAX、DOM、JDOM 和 dom4j 与 JAXP 进行比较的请求，但作这样的比较是不可能的，因为前面四个 API 与 JAXP 具有完全不同的用途。SAX、DOM、JDOM 和 dom4j 都解析 XML。JAXP 提供了一种到达这些解析器及其所涉及的数据的方法，但并未提供一种解析 XML 文档的新方法。如果您要正确使用 JAXP，则理解此差别是非常必要的。这还很有可能使您远远领先于您的 XML 开发同行。</p><p>如果仍有疑问，请确保您具有 JAXP 发行版（参阅 <a href="http://www.ibm.com/developerworks/cn/xml/x-jaxp/#bigtime"><font color="#996699">逐渐晋级</font></a>）。启动 Web 浏览器并加载 JAXP API 文档。导航至位于 <code><font face="新宋体">javax.xml.parsers</font></code> 软件包中的 API 的解析部分。令人奇怪的是，您将只找到六个类。这个 API 到底怎么回事？所有这些类都位于现有解析器的顶部。其中两个类仅用于错误处理。JAXP 比人们想像的要简单得多。那么为何会有混淆呢？</p><table cellspacing="0" cellpadding="0" width="45%" align="right" border="0"><tbody><tr><td width="10"><img height="1" 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="sitting"><strong>位于顶部</strong></a><br /><p>甚至 JDOM 和 dom4j（参阅 <a href="http://www.ibm.com/developerworks/cn/xml/x-jaxp/#resources"><font color="#996699">参考资料</font></a>）与 JAXP 一样都位于其他解析 API 的顶部。但这两个 API 都提供了从 SAX 或 DOM 中访问数据的不同模型，它们在内部使用 SAX（带有一些技巧和修改）来到达它们提供给用户的数据。</p></td></tr></tbody></table></td></tr></tbody></table><p><a name="N100B2"><span class="smalltitle"><strong><font size="3">Sun 的 JAXP 和 Sun 的解析器</font></strong></span></a></p><p>许多解析器/API 混淆来自于 Sun 软件包 JAXP 和该 JAXP 默认使用的解析器。在 JAXP 的早期版本中，Sun 包括 JAXP API（带有刚才提到的六个类和一些常用于转换的类）<em>和</em> 一个叫做 Crimson 的解析器。Crimson 是 <code><font face="新宋体">com.sun.xml</font></code> 软件包的一部分。<font color="#ff0000">在 JAXP 的新版本中 —— 包括在 JDK 中 —— Sun 已经重新包装了 Apache Xerces 解析器（参阅 </font><a href="http://www.ibm.com/developerworks/cn/xml/x-jaxp/#resources"><font color="#ff0000">参考资料</font></a><font color="#ff0000">）。在这两种情况下，虽然解析器是 JAXP 发行版的一部分，但不是 JAXP API 的一部分。</font></p><p>可以认为是 JDOM 附带了 Apache Xerces 解析器。该解析器不是 JDOM 的一部分，但由 JDOM 使用，所以包括它是为了确保 JDOM 可以即装即用。同一原则适用于 JAXP，但并未明确公布：JAXP 附带解析器是为了可以立即使用。但是，许多人将 Sun 的解析器中包括的类作为 JAXP API 本身的一部分。<a name="disc_xmldoc">例如，新闻组上的常见问题通常是</a>“我如何使用 JAXP 附带的 <code><font face="新宋体">XMLDocument</font></code> 类？它的作用是什么？”答案有些复杂。</p><table cellspacing="0" cellpadding="0" width="45%" align="right" border="0"><tbody><tr><td width="10"><img height="1" 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="N100D4"><strong>软件包名称中是什么？</strong></a><br /><p>当我第一次在 Java 1.5 中贸然打开源代码时，我惊奇于我所看到的 —— 或者更应该说是我<em>没有</em> 看到的。没有在正常中的软件包 <code><font face="新宋体">org.apache.xerces</font></code> 中找到 Xerces，因为 Sun 将 Xerces 类重新分配给了 <code><font face="新宋体">com.sun.org.apache.xerces.internal</font></code>。（我发现这有点不正常，但没有人问我。）在任何情况下，如果您在 JDK 中查找 Xerces，就能找到它。</p></td></tr></tbody></table></td></tr></tbody></table><p>首先，<code><font face="新宋体">com.sun.xml.tree.XMLDocument</font></code> 类不是 JAXP 的一部分。它是 Sun 的 Crimson 解析器的一部分，包装在 JAXP 的早期版本中。所以这个问题从一开始就令人误解。其次，<font color="#ff0000">JAXP 的主要用途是在处理解析器时提供开发商独立性。有了 JAXP，您可以用 Sun 的 XML 解析器、Apache 的 Xerces XML 解析器和 Oracle 的 XML 解析器来处理相同的代码。</font>因而使用特定于 Sun 的类会违反使用 JAXP 的要点。是否弄清楚了本主题是如何变得复杂起来的？JAXP 发行版中的 API 和解析器 已经组合在一起，一些开发人员误将解析器中的类和特性作为 API 的一部分，反之亦然。</p><p>既然弄清楚了所有的混淆，那么您就可以深入了解一些代码和概念了。</p><br /><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><td><img height="1" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br /><img height="6" 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" 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" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /></td><td valign="top" align="right"><a class="fbox" href="http://www.ibm.com/developerworks/cn/xml/x-jaxp/#main"><strong><font color="#996699">回页首</font></strong></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="N100F3"><span class="atitle">SAX 入门</span></a></p><p>SAX 是事件驱动的 XML 处理方法。它由许多回调组成。例如，<code><font face="新宋体">startElement()</font></code> 回调在每次 SAX 解析器遇到元素的起始标记时被调用。<code><font face="新宋体">characters()</font></code> 回调为字符数据所调用，然后 <code><font face="新宋体">endElement()</font></code> 为元素的结束标记所调用。许多回调用于文档处理、错误和其他词汇结构。您明白了。SAX 程序员实现一个 SAX 接口来定义这些回调。SAX 还提供一个叫做 <code><font face="新宋体">DefaultHandler</font></code> 的类（在 <code><font face="新宋体">org.xml.sax.helpers</font></code> 软件包中）来实现所有这些回调，并提供所有回调方法默认的空实现。（您将看到，这对于下一节 <a href="http://www.ibm.com/developerworks/cn/xml/x-jaxp/#dom"><font color="#996699">处理 DOM</font></a> 中讨论 DOM 是重点。）SAX 开发人员只需要继承该类，然后实现需要插入特定逻辑的方法。所以 SAX 中的关键是提供这些各种回调的代码，然后让解析器在适当的时候触发其中的一个。下面是典型的 SAX 例程：</p><ol><li>使用特定开发商的解析器实现来创建 <code><font face="新宋体">SAXParser</font></code> 实例。 
</li><li>注册回调实现（例如，通过使用继承 <code><font face="新宋体">DefaultHandler</font></code> 的类）。 
</li><li>开始解析并在回调实现启动时停止。 </li></ol><p></p><p>JAXP 的 SAX 组件提供了完成所有这些操作的简单方法。<font color="#ff0000">没有 JAXP，SAX 解析器实例要么必须从开发商类（比如 <code><font face="新宋体">org.apache.xerces.parsers.SAXParser</font></code>）中直接实例化，要么必须使用一个叫做 <code><font face="新宋体">XMLReaderFactory</font></code> 的 SAX 帮助类（也在 <code><font face="新宋体">org.xml.sax.helpers</font></code> 软件包中）。</font>第一种方法的问题很显然：它不是开发商中立的。第二种方法的问题在于，工厂需要使用解析器类的 <code><font face="新宋体">String</font></code> 名称作为参数（又是 Apache 类 <code><font face="新宋体">org.apache.xerces.parsers.SAXParser</font></code>）。可以通过传递不同的解析器类作为 <code><font face="新宋体">String</font></code> 而更改解析器。使用该方法，如果更改解析器名称，则不需要更改任何导入语句，但仍需要重新编译类。这显然不是最好的解决方案。如果能够不重新编译类而更改解析器就方便多了。</p><p><font color="#ff0000"><strong>JAXP 提供了更好的备选方法：</strong></font>它允许将解析器作为 Java 系统特性。当然，从 Sun 中下载发行版时，您能得到使用 Sun 的 Xerces 版本的 JAXP 实现。更改解析器（比如更改为 Oracle 的解析器）需要更改类路径设置，从一个解析器实现移动到另一个解析器实现。但<em>不</em> 需要重新编译代码。这就是 JAXP 的全部魔力 —— 抽象。</p><table cellspacing="0" cellpadding="0" width="45%" align="right" border="0"><tbody><tr><td width="10"><img height="1" 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="N1014D"><strong>诡异的 SAX 开发人员</strong></a><br /><p>稍叉开一下话题。使用巧妙一点的编码，可以使得 SAX 应用程序从系统特性或特性文件中选择要使用的解析器类。但是，JAXP 提供了相同的行为，且无需任何工作，所以大多数人更愿意走 JAXP 路线。</p></td></tr></tbody></table></td></tr></tbody></table><p><a name="N10157"><span class="smalltitle"><strong><font size="3">SAX 解析器工厂一览</font></strong></span></a></p><p>JAXP <code><font face="新宋体">SAXParserFactory</font></code> 类是能够轻易更改解析器实现的关键。必须创建该类的新实例（一会将用到它）。新实例创建之后，工厂提供一种方法用于获得具有 SAX 功能的解析器。实际上，JAXP 实现保护着开发商相关的代码，从而使您的代码完全不受污染。工厂还具有一些其他的有用特性。</p><p>除了创建 SAX 解析器实例的基本工作之外，工厂还允许设置配置选项。这些选项影响通过工厂获得的所有解析器实例。JAXP 1.3 中两个常用的选项是，用于设置名称空间意识的 <code><font face="新宋体">setNamespaceAware(boolean awareness)</font></code> 和用于打开 DTD 验证的 <code><font face="新宋体">setValidating(boolean validating)</font></code>。记住，一旦设置了这些选项，它们将影响在方法调用后从工厂获得的所有实例。</p><p>设置了工厂之后，调用 <code><font face="新宋体">newSAXParser()</font></code> 会返回 JAXP <code><font face="新宋体">SAXParser</font></code> 类立即可用的实例。<strong><font color="#ff0000">该类包装底层的 SAX 解析器（SAX 类 <code><font face="新宋体">org.xml.sax.XMLReader</font></code> 的实例）。</font></strong>它还防止您使用解析器类的任何特定于开发商的附加项。（是否记得上文中有关 <code><font face="新宋体">XmlDocument</font></code> 类的 <a href="http://www.ibm.com/developerworks/cn/xml/x-jaxp/#disc_xmldoc"><font color="#996699">讨论</font></a>？）该类允许启动实际的解析行为。清单 1 显示如何创建、配置和使用 SAX 工厂：</p><br /><a name="code1"><strong>清单 1. 使用 SAXParserFactory </strong></a><br /><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><td class="code-outline"><pre class="displaycode">import java.io.OutputStreamWriter;
import java.io.Writer;
// JAXP
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.parsers.SAXParser;
// SAX
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class TestSAXParsing {
    public static void main(String[] args) {
        try {
            if (args.length != 1) {
                System.err.println ("Usage: java TestSAXParsing [filename]");
                System.exit (1);
            }
            // Get SAX Parser Factory
            SAXParserFactory factory = SAXParserFactory.newInstance();
            // Turn on validation, and turn off namespaces
            factory.setValidating(true);
            factory.setNamespaceAware(false);
            SAXParser parser = factory.newSAXParser();
            parser.parse(new File(args[0]), new MyHandler());
        } catch (ParserConfigurationException e) {
            System.out.println("The underlying parser does not support " +
                               " the requested features.");
        } catch (FactoryConfigurationError e) {
            System.out.println("Error occurred obtaining SAX Parser Factory.");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
class MyHandler extends DefaultHandler {
    // SAX callback implementations from ContentHandler, ErrorHandler, etc.
}</pre></td></tr></tbody></table><br /><p>在 <a href="http://www.ibm.com/developerworks/cn/xml/x-jaxp/#code1"><font color="#996699">清单 1</font></a> 中，可以看到在使用工厂时出现两个特定于 JAXP 的问题：无法获得或配置 SAX 工厂，及无法配置 SAX 解析器。第一个问题由 <code><font face="新宋体">FactoryConfigurationError</font></code> 表示，通常发生在无法获得 JAXP 实现或系统特性中指定的解析器时。第二个问题由 <code><font face="新宋体">ParserConfigurationException</font></code> 表示，发生在请求的特性在所使用的解析器中不可用时。两个问题都易于处理，且不应在使用 JAXP 时造成任何困难。事实上，您可能想要编写代码，来尝试设置几个特征并巧妙处理某个特性不可用时的情况。</p><p><code><font face="新宋体">SAXParser</font></code> 实例是在获得工厂、关闭名称空间支持并打开验证时获得的；然后解析开始。SAX 解析器的 <code><font face="新宋体">parse()</font></code> 方法采用前面提到的 SAX <code><font face="新宋体">HandlerBase</font></code> 帮助类的一个实例，自定义处理器类继承自该类。请参阅代码发行版来查看该类的实现的完整 Java 清单（参阅 <a href="http://www.ibm.com/developerworks/cn/xml/x-jaxp/#download"><font color="#996699">下载</font></a>）。还传递 <code><font face="新宋体">File</font></code> 以进行解析。但是，<code><font face="新宋体">SAXParser</font></code> 类不只包含这一个方法。</p><p><a name="N101BF"><span class="smalltitle"><strong><font size="3">使用 SAX 解析器</font></strong></span></a></p><p>一旦具有 <code><font face="新宋体">SAXParser</font></code> 类的实例后，您可以做的远远不止于给它传递 <code><font face="新宋体">File</font></code> 来解析。由于大型应用程序中组件的通信方式，所以假设对象实例的创建者就是它的用户并不总是安全的。一个组件可能创建 <code><font face="新宋体">SAXParser</font></code> 实例，而另一个组件（可能由另一个开发人员编码）可能需要使用相同的实例。因此，JAXP 提供了确定解析器的设置的方法。例如，可以使用 <code><font face="新宋体">isValidating()</font></code> 来确定解析器是否将执行验证，使用 <code><font face="新宋体">isNamespaceAware()</font></code> 来查看解析器是否可以处理 XML 文档中的名称空间。这些方法可以为您提供关于解析器可以做什么的信息，但只带有 <code><font face="新宋体">SAXParser</font></code> 实例而非 <code><font face="新宋体">SAXParserFactory</font></code> 本身的用户无法更改这些特性。您必须在解析器工厂级别完成这一操作。</p><p>还有许多方法来请求文档的解析。并非只能接受 <code><font face="新宋体">File</font></code> 和 SAX <code><font face="新宋体">DefaultHandler</font></code> 实例，<code><font face="新宋体">SAXParser</font></code> 的 <code><font face="新宋体">parse()</font></code> 方法还可以接受字符串格式的 SAX <code><font face="新宋体">InputSource</font></code>、Java <code><font face="新宋体">InputStream</font></code> 或 <code><font face="新宋体">URL</font></code>，它们全部具有 <code><font face="新宋体">DefaultHandler</font></code> 实例。所以仍可以解析包装在各种格式中的文档。</p><p>最后，可以获得底层 SAX 解析器（<code><font face="新宋体">org.xml.sax.XMLReader</font></code> 的实例），并直接通过 <code><font face="新宋体">SAXParser</font></code> 的 <code><font face="新宋体">getXMLReader()</font></code> 方法来使用它。一旦获得该底层实例，一般的 SAX 方法都可用。清单 2 显示 JAXP 中的核心类 <code><font face="新宋体">SAXParser</font></code> 类在 SAX 解析中的各种用法的例子：</p><br /><a name="code2"><strong>清单 2. 使用 JAXP SAXParser 类</strong></a><br /><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><td class="code-outline"><pre class="displaycode">// Get a SAX Parser instance
SAXParser saxParser = saxFactory.newSAXParser();
// Find out if validation is supported
boolean isValidating = saxParser.isValidating();
// Find out if namespaces are supported
boolean isNamespaceAware = saxParser.isNamespaceAware();
// Parse, in a variety of ways
// Use a file and a SAX DefaultHandler instance
saxParser.parse(new File(args[0]), myDefaultHandlerInstance);
// Use a SAX InputSource and a SAX DefaultHandler instance
saxParser.parse(mySaxInputSource, myDefaultHandlerInstance);
// Use an InputStream and a SAX DefaultHandler instance
saxParser.parse(myInputStream, myDefaultHandlerInstance);
// Use a URI and a SAX DefaultHandler instance
saxParser.parse("http://www.newInstance.com/xml/doc.xml",
                myDefaultHandlerInstance);
// Get the underlying (wrapped) SAX parser
org.xml.sax.XMLReader parser = saxParser.getXMLReader();
// Use the underlying parser
parser.setContentHandler(myContentHandlerInstance);
parser.setErrorHandler(myErrorHandlerInstance);
parser.parse(new org.xml.sax.InputSource(args[0]));</pre></td></tr></tbody></table><br /><p>到此为止，已经针对 SAX 谈了许多，但还没有显示任何显著的或惊人的内容。JAXP 的附加功能相当小，尤其是涉及到 SAX 的地方。这个最小功能使得代码更易移植，让其他开发人员用任何 SAX 兼容的 XML 解析器来自由或商业地使用它。好了。使用 SAX 与 JAXP 再无其他内容。如果已经了解了 SAX，您已经成功了大约 98％。您只需要学习两个新类和一对 Java 异常，然后就可以开始行动了。如果从未用过 SAX，从现在开始也足够了。</p><br /><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><td><img height="1" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br /><img height="6" 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" 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" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /></td><td valign="top" align="right"><a class="fbox" href="http://www.ibm.com/developerworks/cn/xml/x-jaxp/#main"><strong><font color="#996699">回页首</font></strong></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="dom"><span class="atitle">处理 DOM</span></a></p><p>如果您认为需要休息一下来对付 DOM 的挑战，那么就休息一下吧。使用 DOM 与 JAXP 和使用 JAXP 与 SAX 几乎完全相同，惟一要做的就是更改类名和返回类型，这就足够了。如果理解 SAX 如何工作和 DOM 是什么，那就根本没有问题。</p><p>DOM 和 SAX 的主要差别是 API 本身的结构。SAX 由基于事件的回调集组成，而 DOM 具有内存树结构。在 SAX 中，决不会有需要处理的数据结构（除非开发人员手动创建一个）。因此，SAX 没有提供修改 XML 文档的能力。DOM 提供了此功能。<code><font face="新宋体">org.w3c.dom.Document</font></code> 类表示 XML 文档，由表示元素、属性和其他 XML 构造的 DOM 节点组成。所以 JAXP 不需要启动 SAX 回调；它只负责从解析中返回 DOM <code><font face="新宋体">Document</font></code> 对象。</p><p><a name="N10241"><span class="smalltitle"><strong><font size="3">DOM 解析器工厂一览</font></strong></span></a></p><p>基本了解了 DOM 以及 DOM 和 SAX 之间的差别之后，就不需要了解其他内容了。清单 3 看起来与 <a href="http://www.ibm.com/developerworks/cn/xml/x-jaxp/#code1"><font color="#996699">清单 1</font></a> 中的 SAX 代码十分相似。首先，获得 <code><font face="新宋体">DocumentBuilderFactory</font></code>（与清单 1 中获得 <code><font face="新宋体">SAXParserFactory</font></code> 的方法一样）。然后，配置工厂来处理验证和名称空间（与 SAX 中的方法一样）。其次，从工厂中检索与 <code><font face="新宋体">SAXParser</font></code> 类似的 <code><font face="新宋体">DocumentBuilder</font></code> 实例（与 SAX 中的方法一样）。 然后进行解析，得到的 DOM <code><font face="新宋体">Document</font></code> 对象传递给输出 DOM 树的方法：</p><br /><a name="code3"><strong>清单 3. 使用 DocumentBuilderFactory</strong></a><br /><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><td class="code-outline"><pre class="displaycode">import java.io.File;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
// JAXP
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
// DOM
import org.w3c.dom.Document;
import org.w3c.dom.DocumentType;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class TestDOMParsing {
    public static void main(String[] args) {
        try {
            if (args.length != 1) {
                System.err.println ("Usage: java TestDOMParsing " +
                                    "[filename]");
                System.exit (1);
            }
            // Get Document Builder Factory
            DocumentBuilderFactory factory = 
                DocumentBuilderFactory.newInstance();
            // Turn on validation, and turn off namespaces
            factory.setValidating(true);
            factory.setNamespaceAware(false);
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document doc = builder.parse(new File(args[0]));
            // Print the document from the DOM tree and
            //   feed it an initial indentation of nothing
            printNode(doc, "");
        } catch (ParserConfigurationException e) {
            System.out.println("The underlying parser does not " +
                               "support the requested features.");
        } catch (FactoryConfigurationError e) {
            System.out.println("Error occurred obtaining Document " +
                               "Builder Factory.");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    private static void printNode(Node node, String indent)  {
        // print the DOM tree
    }
}</pre></td></tr></tbody></table><br /><p>该代码可以出现两个问题（与 JAXP 中的 SAX 一样）：<code><font face="新宋体">FactoryConfigurationError</font></code> 和 <code><font face="新宋体">ParserConfigurationException</font></code>。每个问题的原因都于 SAX 中的一样。一个问题出现在实现类中（导致 <code><font face="新宋体">FactoryConfigurationError</font></code>），另一个问题是提供的解析器不支持请求的特性（导致 <code><font face="新宋体">ParserConfigurationException</font></code>）。在这方面，DOM 和 SAX 之间的惟一差别是，在 DOM 中用 <code><font face="新宋体">DocumentBuilderFactory</font></code> 替代 <code><font face="新宋体">SAXParserFactory</font></code>，用 <code><font face="新宋体">DocumentBuilder</font></code> 替代 <code><font face="新宋体">SAXParser</font></code>。 仅此一点。（可以查看完整的代码清单，其中包括用于输出 DOM 树的方法；请参阅 <a href="http://www.ibm.com/developerworks/cn/xml/x-jaxp/#download"><font color="#996699">下载</font></a>。）</p><p><a name="N10294"><span class="smalltitle"><strong><font size="3">使用 DOM 解析器</font></strong></span></a></p><p>一旦拥有 DOM 工厂后，就可以获得 <code><font face="新宋体">DocumentBuilder</font></code> 实例。可用于 <code><font face="新宋体">DocumentBuilder</font></code> 实例的方法与可用于对应 SAX 实例的方法非常相似。主要差别在于 <code><font face="新宋体">parse()</font></code> 方法的变种不接受 SAX <code><font face="新宋体">DefaultHandler</font></code> 类的实例。而是返回一个表示已解析的 XML 文档的 DOM <code><font face="新宋体">Document</font></code> 实例。其余的惟一差别就是两个方法提供了类似 SAX 的功能：</p><ul><li><code><font face="新宋体">setErrorHandler()</font></code>，执行 SAX <code><font face="新宋体">ErrorHandler</font></code> 实现来处理解析时可能出现的问题。 
</li><li><code><font face="新宋体">setEntityResolver()</font></code>，执行 SAX <code><font face="新宋体">EntityResolver</font></code> 实现来处理实体解析。 </li></ul><p>清单 4 显示这些方法的实际例子：</p><br /><a name="code4"><strong>清单 4. 使用 JAXP DocumentBuilder 类</strong></a><br /><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><td class="code-outline"><pre class="displaycode">// Get a DocumentBuilder instance
DocumentBuilder builder = builderFactory.newDocumentBuilder();
// Find out if validation is supported
boolean isValidating = builder.isValidating();
// Find out if namespaces are supported
boolean isNamespaceAware = builder.isNamespaceAware();
// Set a SAX ErrorHandler
builder.setErrorHandler(myErrorHandlerImpl);
// Set a SAX EntityResolver
builder.setEntityResolver(myEntityResolverImpl);
// Parse, in a variety of ways
// Use a file
Document doc = builder.parse(new File(args[0]));
// Use a SAX InputSource
Document doc = builder.parse(mySaxInputSource);
// Use an InputStream
Document doc = builder.parse(myInputStream, myDefaultHandlerInstance);
// Use a URI 
Document doc = builder.parse("http://www.newInstance.com/xml/doc.xml");</pre></td></tr></tbody></table><br /><p>如果您在阅读 DOM 这一节时感到一点乏味，那么您并不孤单；我在编写时也感到有些乏味，因为将已经学过的有关 SAX 的知识应用到 DOM 是如此简单。</p><br /><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><td><img height="1" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br /><img height="6" 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" 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" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /></td><td valign="top" align="right"><a class="fbox" href="http://www.ibm.com/developerworks/cn/xml/x-jaxp/#main"><strong><font color="#996699">回页首</font></strong></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="N102DF"><span class="atitle">执行验证</span></a></p><p>在 Java 5.0（和 JAXP 1.3 中），JAXP 引进一种新方法来验证文档。不是仅仅在 SAX 或 DOM 工厂上使用 <code><font face="新宋体">setValidating()</font></code> 方法，而是将验证划分到新 <code><font face="新宋体">javax.xml.validation</font></code> 软件包中的几个类中。由于篇幅所限，本文没有详细介绍验证的所有细微差别，包括 W3C XML Schema、DTD、RELAX NG 模式，以及其他约束模型，但如果已经具有一些约束，那么使用新验证模型并确保文档与约束相匹配则相当容易。</p><table cellspacing="0" cellpadding="0" width="45%" align="right" border="0"><tbody><tr><td width="10"><img height="1" 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="N102F3"><strong>冗余并非总是好事</strong></a><br /><p>您<em>不</em> 应该做的一件事是使用 <code><font face="新宋体">setValidating(true)</font></code> 和 <code><font face="新宋体">javax.xml.validation</font></code> 软件包。您将会得到一些严重错误，其中大多数错误难以解决。最好是养成从不调用 <code><font face="新宋体">setValidating()</font></code>（默认为假）的习惯，而是使用新的 JAXP 验证框架。</p></td></tr></tbody></table></td></tr></tbody></table><p>首先，将约束模型（可能是某个磁盘上的文件）转化为 JAXP 可以使用的格式。将此文件加载到 <code><font face="新宋体">Source</font></code> 实例中。（我将在第 2 部分更详细地介绍 <code><font face="新宋体">Source</font></code>；现在只要知道它表示磁盘某个位置的文档，可以是 DOM <code><font face="新宋体">Document</font></code> 或其他文档。）然后，使用 <code><font face="新宋体">SchemaFactory.newSchema(Source)</font></code> 创建 <code><font face="新宋体">SchemaFactory</font></code> 并加载模式，这将返回一个新 <code><font face="新宋体">Schema</font></code> 对象。最后，使用此 <code><font face="新宋体">Schema</font></code> 对象，用 <code><font face="新宋体">Schema.newValidator()</font></code> 方法创建一个新 <code><font face="新宋体">Validator</font></code> 对象。清单 5 清楚地显示了全部操作：</p><br /><a name="code5"><strong>清单 5. 使用 JAXP 验证框架</strong></a><br /><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><td class="code-outline"><pre class="displaycode">DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(new File(args[0]));
// Handle validation
SchemaFactory constraintFactory = 
    SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Source constraints = new StreamSource(new File(args[1]));
Schema schema = constraintFactory.newSchema(constraints);
Validator validator = schema.newValidator();
// Validate the DOM tree
try {
    validator.validate(new DOMSource(doc));
    System.out.println("Document validates fine.");
} catch (org.xml.sax.SAXException e) {
    System.out.println("Validation error: " + e.getMessage());
}</pre></td></tr></tbody></table><br /><p>一旦掌握之后，这一切十分简单。亲自输入此代码，或查看完整清单（参阅 <a href="http://www.ibm.com/developerworks/cn/xml/x-jaxp/#download"><font color="#996699">下载</font></a>）。</p><br /><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><td><img height="1" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br /><img height="6" 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" 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" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /></td><td valign="top" align="right"><a class="fbox" href="http://www.ibm.com/developerworks/cn/xml/x-jaxp/#main"><strong><font color="#996699">回页首</font></strong></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="N10345"><span class="atitle">更改解析器</span></a></p><p><strong><font color="#ff0000">更改 JAXP 工厂类使用的解析器很容易。更改解析器实际上意味着更改解析器工厂，因为所有 <code><font face="新宋体">SAXParser</font></code> 和 <code><font face="新宋体">DocumentBuilder</font></code> 实例都来自这些工厂。工厂确定加载哪个解析器，所以必须更改工厂</font></strong>。要更改 <code><font face="新宋体">SAXParserFactory</font></code> 接口的实现，请设置 Java 系统特性 <code><font face="新宋体">javax.xml.parsers.SAXParserFactory</font></code>。如果未定义此特性，则返回默认实现（不管开发商指定哪个解析器）。同一规则适用于所使用的 <code><font face="新宋体">DocumentBuilderFactory</font></code> 实现。在这种情况下，将会查询 <code><font face="新宋体">javax.xml.parsers.DocumentBuilderFactory</font></code> 系统特性。</p><br /><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><td><img height="1" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br /><img height="6" 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" 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" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /></td><td valign="top" align="right"><a class="fbox" href="http://www.ibm.com/developerworks/cn/xml/x-jaxp/#main"><strong><font color="#996699">回页首</font></strong></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="N10366"><span class="atitle">结束语</span></a></p><p>阅读完本文后，您差不多已经了解到 JAXP 的全部范围：</p><ul><li>提供到 SAX 的钩子 
</li><li>提供到 DOM 的钩子 
</li><li>允许容易地更改解析器 </li></ul>要理解 JAXP 的解析和验证特性，您需要阅读比较晦涩的资料。要使 JAXP 运行，最困难的部分是更改系统特性、通过工厂而非解析器或构建器来设置验证，和弄清楚 JAXP <em>不是</em> 什么。JAXP 为两种流行的 Java 和 XML API 提供了有用的插入层 (pluggability layer)。它使得代码具有开发商中立性，并允许进行解析器之间的更改，而无需重新编译解析代码。所以请下载 JAXP 并使用它！第 2 部分将介绍 JAXP 能够如何帮助转换 XML 文档。 <img src ="http://www.blogjava.net/joaquin25/aggbug/200370.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/joaquin25/" target="_blank">joaquin25</a> 2008-05-14 11:28 <a href="http://www.blogjava.net/joaquin25/articles/200370.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java遍历文件夹的两种方法</title><link>http://www.blogjava.net/joaquin25/articles/200138.html</link><dc:creator>joaquin25</dc:creator><author>joaquin25</author><pubDate>Tue, 13 May 2008 02:18:00 GMT</pubDate><guid>http://www.blogjava.net/joaquin25/articles/200138.html</guid><wfw:comment>http://www.blogjava.net/joaquin25/comments/200138.html</wfw:comment><comments>http://www.blogjava.net/joaquin25/articles/200138.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/joaquin25/comments/commentRss/200138.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/joaquin25/services/trackbacks/200138.html</trackback:ping><description><![CDATA[
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td valign="top" align="left" width="490" height="165">
										<p>转自：<a href="http://www.java3z.com/cwbwebhome/article/article5/5924.html?id=1838">http://www.java3z.com/cwbwebhome/article/article5/5924.html?id=1838</a><br /><br />Java遍历文件夹的2种方法：</p>
										<p>
												<strong>
														<font color="#0000ff">
																<span class="STYLE1">A.不使用递归：</span>
																<br />
														</font>
												</strong>
										</p>
										<pre>import java.io.File;
import java.util.LinkedList;
public class FileSystem {
    public static void main(String[] args) {
        
        long a = System.currentTimeMillis();
        
        LinkedList<file> list = new LinkedList<file>();
        File dir = new File("c:\\java\\");
        File file[] = dir.listFiles();
        for (int i = 0; i &lt; file.length; i++) {
            if (file[i].isDirectory())
                list.add(file[i]);
            else
                System.out.println(file[i].getAbsolutePath());
        }
        File tmp;
        while (!list.isEmpty()) {
            tmp = list.removeFirst();
            if (tmp.isDirectory()) {
                file = tmp.listFiles();
                if (file == null)
                    continue;
                for (int i = 0; i &lt; file.length; i++) {
                    if (file[i].isDirectory())
                        list.add(file[i]);
                    else
                        System.out.println(file[i].getAbsolutePath());
                }
            } else {
                System.out.println(tmp.getAbsolutePath());
            }
        }
        
        System.out.println(System.currentTimeMillis() - a);
    }
}
                      </file></file></pre>
								</td>
								<td valign="top" width="194">
										<div align="center">
												<script type="text/javascript">
														<!--
google_ad_client = "pub-1832179689702023";
google_ad_width = 160;
google_ad_height = 600;
google_ad_format = "160x600_as";
google_ad_type = "text_image";
google_ad_channel ="";
google_color_border = "FFFFFF";
google_color_bg = "FFFFFF";
google_color_link = "3366FF";
google_color_text = "000000";
google_color_url = "3D81EE";
//-->
												</script>
												<script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript">
												</script>
												<iframe name="google_ads_frame" marginwidth="0" marginheight="0" src="http://pagead2.googlesyndication.com/pagead/ads?client=ca-pub-1832179689702023&amp;dt=1210644587515&amp;lmt=1206589756&amp;format=160x600_as&amp;output=html&amp;correlator=1210644587500&amp;url=http%3A%2F%2Fwww.java3z.com%2Fcwbwebhome%2Farticle%2Farticle5%2F5924.html%3Fid%3D1838&amp;color_bg=FFFFFF&amp;color_text=000000&amp;color_link=3366FF&amp;color_url=3D81EE&amp;color_border=FFFFFF&amp;ad_type=text_image&amp;ref=http%3A%2F%2Fwww.baidu.com%2Fs%3Fwd%3Djava%2B%25B1%25E9%25C0%25FA%25CE%25C4%25BC%25FE%25BC%25D0%26lm%3D0%26si%3D%26rn%3D10%26ie%3Dgb2312%26ct%3D0%26cl%3D3%26f%3D1%26rsp%3D8&amp;frm=0&amp;cc=99&amp;ga_vid=37783050623617290.1210644588&amp;ga_sid=1210644588&amp;ga_hid=1569155488&amp;flash=9.0.115.0&amp;u_h=1024&amp;u_w=1280&amp;u_ah=964&amp;u_aw=1280&amp;u_cd=32&amp;u_tz=480&amp;u_java=true" frameborder="0" width="160" scrolling="no" height="600" allowtransparency="">
												</iframe>
										</div>
								</td>
						</tr>
				</tbody>
		</table>
		<span class="STYLE1">
				<strong>
						<font color="#0000ff">B.使用递归： </font>
				</strong>
		</span>
		<pre>       import java.io.File;
import java.util.ArrayList;
public class FileSystem1 {
    private static ArrayList<string> filelist = new ArrayList<string>(); 
    
    public static void main(String[] args) {
        
        long a = System.currentTimeMillis();
        refreshFileList("c:\\java");
        System.out.println(System.currentTimeMillis() - a);
    }
    public static void refreshFileList(String strPath) { 
        File dir = new File(strPath); 
        File[] files = dir.listFiles(); 
        
        if (files == null) 
            return; 
        for (int i = 0; i &lt; files.length; i++) { 
            if (files[i].isDirectory()) { 
                refreshFileList(files[i].getAbsolutePath()); 
            } else { 
                String strFileName = files[i].getAbsolutePath().toLowerCase();
                System.out.println("---"+strFileName);
                filelist.add(files[i].getAbsolutePath());                    
            } 
        } 
    }
}
<br />结论：经过测试，使用递归的方法B性能相对好一些</string></string></pre>
<img src ="http://www.blogjava.net/joaquin25/aggbug/200138.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/joaquin25/" target="_blank">joaquin25</a> 2008-05-13 10:18 <a href="http://www.blogjava.net/joaquin25/articles/200138.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java runtime.exec() 的编写</title><link>http://www.blogjava.net/joaquin25/articles/199444.html</link><dc:creator>joaquin25</dc:creator><author>joaquin25</author><pubDate>Fri, 09 May 2008 03:15:00 GMT</pubDate><guid>http://www.blogjava.net/joaquin25/articles/199444.html</guid><wfw:comment>http://www.blogjava.net/joaquin25/comments/199444.html</wfw:comment><comments>http://www.blogjava.net/joaquin25/articles/199444.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/joaquin25/comments/commentRss/199444.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/joaquin25/services/trackbacks/199444.html</trackback:ping><description><![CDATA[
		<p>
				<font size="2">转自：<a href="http://hi.baidu.com/qdyunyan/blog/item/fbcb8122353d72f3d7cae2a9.html">http://hi.baidu.com/qdyunyan/blog/item/fbcb8122353d72f3d7cae2a9.html</a><br /><font color="#ff0000">自己的一些评论：如果某些可执行程序如abc.bat在命令行可以执行，而在runtime中调用不可以执行！产生这种错误的原因就是没有处理runtime.exec()返回的process的输入输出流，这个process是必须自己handle输入输出流。</font><br /><br />那就首先说点Runtime类吧，他是一个与JVM运行时环境有关的类，这个类是Singleton的。我说几个自己觉得重要的地方。</font>
		</p>
		<p>
				<font size="2">1、Runtime.getRuntime()可以取得当前JVM的运行时环境，这也是在Java中唯一一个得到运行时环境的方法。</font>
		</p>
		<p>
				<font size="2">2、Runtime上其他大部分的方法都是实例方法，也就是说每次进行运行时调用时都要用到getRuntime方法。</font>
		</p>
		<p>
				<font size="2">3、Runtime中的exit方法是退出当前JVM的方法，估计也是唯一的一个吧，因为我看到System类中的exit实际上也是通过调用Runtime.exit()来退出JVM的，这里说明一下Java对Runtime返回值的一般规则（后边也提到了），0代表正常退出，非0代表异常中止，这只是Java的规则，在各个操作系统中总会发生一些小的混淆。</font>
		</p>
		<br />
		<p>
				<font size="2">4、Runtime.addShutdownHook()方法可以注册一个hook在JVM执行shutdown的过程中，方法的参数只要是一个初始化过但是没有执行的Thread实例就可以。（注意，Java中的Thread都是执行过了就不值钱的哦）</font>
		</p>
		<p>
				<font size="2">5、说到addShutdownHook这个方法就要说一下JVM运行环境是在什么情况下shutdown或者abort的。文档上是这样写的，当最后一个非精灵进程退出或者收到了一个用户中断信号、用户登出、系统shutdown、Runtime的exit方法被调用时JVM会启动shutdown的过程，在这个过程开始后，他会并行启动所有登记的shutdown hook（注意是并行启动，这就需要线程安全和防止死锁）。当shutdown过程启动后，只有通过调用halt方法才能中止shutdown的过程并退出JVM。</font>
		</p>
		<p>
				<font size="2">那什么时候JVM会abort退出那？首先说明一下，abort退出时JVM就是停止运行但并不一定进行shutdown。这只有JVM在遇到SIGKILL信号或者windows中止进程的信号、本地方法发生类似于访问非法地址一类的内部错误时会出现。这种情况下并不能保证shutdown hook是否被执行。</font>
		</p>
		<p>
				<br />
				<font size="2">现在开始看这篇文章，呵呵。</font>
		</p>
		<p>
				<br />
				<font size="2">首先讲的是Runtime.exec()方法的所有重载。这里要注意的有一点，就是public Process exec(String [] cmdArray, String [] envp);这个方法中cmdArray是一个执行的命令和参数的字符串数组，数组的第一个元素是要执行的命令往后依次都是命令的参数，envp我个人感觉应该和C中的execve中的环境变量是一样的，envp中使用的是name=value的方式。</font>
		</p>
		<p>
				<br />
				<font size="2">&lt;!--[if !supportLists]--&gt;1、 &lt;!--[endif]--&gt;一个很糟糕的调用程序，代码如下，这个程序用exec调用了一个外部命令之后马上使用exitValue就对其返回值进行检查，让我们看看会出现什么问题。</font>
		</p>
		<p>
				<br />
				<font size="2">import java.util.*;<br />import java.io.*;</font>
		</p>
		<p>
				<font size="2">public class BadExecJavac<br />{<br />public static void main(String args[])<br />{<br />try<br />{ <br />Runtime rt = Runtime.getRuntime();<br />Process proc = rt.exec("javac");<br />int exitVal = proc.exitValue();<br />System.out.println("Process exitValue: " + exitVal);<br />} catch (Throwable t)<br />{<br />t.printStackTrace();<br />}<br />}<br />}</font>
		</p>
		<p>
				<font size="2">A run of BadExecJavac produces: </font>
		</p>
		<p>
				<br />
				<font size="2">E:classescomjavaworldjpitfallsarticle2&gt;java BadExecJavac<br />java.lang.IllegalThreadStateException: process has not exited<br />at java.lang.Win32Process.exitValue(Native Method)<br />at BadExecJavac.main(BadExecJavac.java:13)</font>
		</p>
		<p>
				<br />
				<font size="2">这里看原文就可以了解，这里主要的问题就是错误的调用了exitValue来取得外部命令的返回值（呵呵，这个错误我也曾经犯过），因为exitValue这个方法是不阻塞的，程序在调用这个方法时外部命令并没有返回所以造成了异常的出现，这里是由另外的方法来等待外部命令执行完毕的，就是waitFor方法，这个方法会一直阻塞直到外部命令执行结束，然后返回外部命令执行的结果，作者在这里一顿批评设计者的思路有问题，呵呵，反正我是无所谓阿，能用就可以拉。但是作者在这里有一个说明，就是exitValue也是有好多用途的。因为当你在一个Process上调用waitFor方法时，当前线程是阻塞的，如果外部命令无法执行结束，那么你的线程就会一直阻塞下去，这种意外会影响我们程序的执行。所以在我们不能判断外部命令什么时候执行完毕而我们的程序还需要继续执行的情况下，我们就应该循环的使用exitValue来取得外部命令的返回状态，并在外部命令返回时作出相应的处理。</font>
		</p>
		<p>
				<br />
				<font size="2">2、对exitValue处改进了的程序</font>
		</p>
		<p>
				<font size="2">import java.util.*;<br />import java.io.*;</font>
		</p>
		<p>
				<font size="2">public class BadExecJavac2<br />{<br />public static void main(String args[])<br />{<br />try<br />{ <br />Runtime rt = Runtime.getRuntime();<br />Process proc = rt.exec("javac");<br />int exitVal = proc.waitFor();<br />System.out.println("Process exitValue: " + exitVal);<br />} catch (Throwable t)<br />{<br />t.printStackTrace();<br />}<br />}<br />}</font>
		</p>
		<p>
				<font size="2">不幸的是，这个程序也无法执行完成，它没有输出但却一直悬在那里，这是为什么那？</font>
		</p>
		<p>
				<br />
				<font size="2">JDK文档中对此有如此的解释：因为本地的系统对标准输入和输出所提供的缓冲池有效，所以错误的对标准输出快速的写入和从标准输入快速的读入都有可能造成子进程的锁，甚至死锁。</font>
		</p>
		<p>
				<br />
				<font size="2">文档引述完了，作者又开始批评了，他说JDK仅仅说明为什么问题会发生，却并没有说明这个问题怎么解决，这的确是个问题哈。紧接着作者说出自己的做法，就是在执行完外部命令后我们要控制好Process的所有输入和输出（视情况而定），在这个例子里边因为调用的是Javac，而他在没有参数的情况下会将提示信息输出到标准出错，所以在下面的程序中我们要对此进行处理。</font>
		</p>
		<p>
				<br />
				<font size="2">import java.util.*;<br />import java.io.*;</font>
		</p>
		<p>
				<font size="2">public class MediocreExecJavac<br />{<br />public static void main(String args[])<br />{<br />try<br />{ <br />Runtime rt = Runtime.getRuntime();<br />Process proc = rt.exec("javac");<br />InputStream stderr = proc.getErrorStream();<br />InputStreamReader isr = new InputStreamReader(stderr);<br />BufferedReader br = new BufferedReader(isr);<br />String line = null;<br />System.out.println("&lt;ERROR&gt;");<br />while ( (line = br.readLine()) != null)<br />System.out.println(line);<br />System.out.println("&lt;/ERROR&gt;");<br />int exitVal = proc.waitFor();<br />System.out.println("Process exitValue: " + exitVal);<br />} catch (Throwable t)<br />{<br />t.printStackTrace();<br />}<br />}<br />}</font>
		</p>
		<p>
				<br />
				<font size="2">程序的运行结果为</font>
		</p>
		<p>
				<font size="2">E:classescomjavaworldjpitfallsarticle2&gt;java MediocreExecJavac<br />&lt;ERROR&gt;<br />Usage: javac &lt;options&gt; &lt;source files&gt;</font>
		</p>
		<p>
				<font size="2">where &lt;options&gt; includes:<br />-g Generate all debugging info<br />-g:none Generate no debugging info<br />-g:{lines,vars,source} Generate only some debugging info<br />-O Optimize; may hinder debugging or enlarge class files<br />-nowarn Generate no warnings<br />-verbose Output messages about what the compiler is doing<br />-deprecation Output source locations where deprecated APIs are used<br />-classpath &lt;path&gt; Specify where to find user class files<br />-sourcepath &lt;path&gt; Specify where to find input source files<br />-bootclasspath &lt;path&gt; Override location of bootstrap class files<br />-extdirs &lt;dirs&gt; Override location of installed extensions<br />-d &lt;directory&gt; Specify where to place generated class files<br />-encoding &lt;encoding&gt; Specify character encoding used by source files<br />-target &lt;release&gt; Generate class files for specific VM version<br />&lt;/ERROR&gt;<br />Process exitValue: 2</font>
		</p>
		<p>
				<br />
				<font size="2">哎，不管怎么说还是出来了结果，作者作了一下总结，就是说，为了处理好外部命令大量输出的情况，你要确保你的程序处理好外部命令所需要的输入或者输出。</font>
		</p>
		<p>
				<br />
				<font size="2">下一个题目，当我们调用一个我们认为是可执行程序的时候容易发生的错误（今天晚上我刚刚犯这个错误，没事做这个练习时候发生的）</font>
		</p>
		<p>
				<font size="2">import java.util.*;<br />import java.io.*;</font>
		</p>
		<p>
				<font size="2">public class BadExecWinDir<br />{<br />public static void main(String args[])<br />{<br />try<br />{ <br />Runtime rt = Runtime.getRuntime();<br />Process proc = rt.exec("dir");<br />InputStream stdin = proc.getInputStream();<br />InputStreamReader isr = new InputStreamReader(stdin);<br />BufferedReader br = new BufferedReader(isr);<br />String line = null;<br />System.out.println("&lt;OUTPUT&gt;");<br />while ( (line = br.readLine()) != null)<br />System.out.println(line);<br />System.out.println("&lt;/OUTPUT&gt;");<br />int exitVal = proc.waitFor(); <br />System.out.println("Process exitValue: " + exitVal);<br />} catch (Throwable t)<br />{<br />t.printStackTrace();<br />}<br />}<br />}</font>
		</p>
		<p>
				<font size="2">A run of BadExecWinDir produces: </font>
		</p>
		<p>
				<br />
				<font size="2">E:classescomjavaworldjpitfallsarticle2&gt;java BadExecWinDir<br />java.io.IOException: CreateProcess: dir error=2<br />at java.lang.Win32Process.create(Native Method)<br />at java.lang.Win32Process.&lt;init&gt;(Unknown Source)<br />at java.lang.Runtime.execInternal(Native Method)<br />at java.lang.Runtime.exec(Unknown Source)<br />at java.lang.Runtime.exec(Unknown Source)<br />at java.lang.Runtime.exec(Unknown Source)<br />at java.lang.Runtime.exec(Unknown Source)<br />at BadExecWinDir.main(BadExecWinDir.java:12)</font>
		</p>
		<p>
				<br />
				<font size="2">说实在的，这个错误还真是让我摸不着头脑，我觉得在windows中返回2应该是没有找到这个文件的缘故，可能windows 2000中只有cmd命令，dir命令不是当前环境变量能够解释的吧。我也不知道了，慢慢往下看吧。</font>
		</p>
		<p>
				<font size="2">嘿，果然和作者想的一样，就是因为dir命令是由windows中的解释器解释的，直接执行dir时无法找到dir.exe这个命令，所以会出现文件未找到这个2的错误。如果我们要执行这样的命令，就要先根据操作系统的不同执行不同的解释程序command.com 或者cmd.exe。</font>
		</p>
		<p>
				<font size="2">作者对上边的程序进行了修改</font>
		</p>
		<p>
				<font size="2">import java.util.*;<br />import java.io.*;</font>
		</p>
		<p>
				<font size="2">class StreamGobbler extends Thread<br />{<br />InputStream is;<br />String type;</font>
		</p>
		<p>
				<font size="2">StreamGobbler(InputStream is, String type)<br />{<br />this.is = is;<br />this.type = type;<br />}</font>
		</p>
		<p>
				<font size="2">public void run()<br />{<br />try<br />{<br />InputStreamReader isr = new InputStreamReader(is);<br />BufferedReader br = new BufferedReader(isr);<br />String line=null;<br />while ( (line = br.readLine()) != null)<br />System.out.println(type + "&gt;" + line); <br />} catch (IOException ioe)<br />{<br />ioe.printStackTrace(); <br />}<br />}<br />}</font>
		</p>
		<p>
				<font size="2">public class GoodWindowsExec<br />{<br />public static void main(String args[])<br />{<br />if (args.length &lt; 1)<br />{<br />System.out.println("USAGE: java GoodWindowsExec &lt;cmd&gt;");<br />System.exit(1);<br />}</font>
		</p>
		<p>
				<font size="2">try<br />{ <br />String osName = System.getProperty("os.name" );<br />String[] cmd = new String[3];</font>
		</p>
		<p>
				<font size="2">if( osName.equals( "Windows NT" ) )<br />{<br />cmd[0] = "cmd.exe" ;<br />cmd[1] = "/C" ;<br />cmd[2] = args[0];<br />}<br />else if( osName.equals( "Windows 95" ) )<br />{<br />cmd[0] = "command.com" ;<br />cmd[1] = "/C" ;<br />cmd[2] = args[0];<br />}</font>
		</p>
		<p>
				<font size="2">Runtime rt = Runtime.getRuntime();<br />System.out.println("Execing " + cmd[0] + " " + cmd[1] <br />+ " " + cmd[2]);<br />Process proc = rt.exec(cmd);<br />// any error message?<br />StreamGobbler errorGobbler = new <br />StreamGobbler(proc.getErrorStream(), "ERROR"); </font>
		</p>
		<p>
				<font size="2">// any output?<br />StreamGobbler outputGobbler = new <br />StreamGobbler(proc.getInputStream(), "OUTPUT");</font>
		</p>
		<p>
				<font size="2">// kick them off<br />errorGobbler.start();<br />outputGobbler.start();</font>
		</p>
		<p>
				<font size="2">// any error???<br />int exitVal = proc.waitFor();<br />System.out.println("ExitValue: " + exitVal); <br />} catch (Throwable t)<br />{<br />t.printStackTrace();<br />}<br />}<br />}</font>
		</p>
		<p>
				<font size="2">Running GoodWindowsExec with the dir command generates: </font>
		</p>
		<p>
				<br />
				<font size="2">E:classescomjavaworldjpitfallsarticle2&gt;java GoodWindowsExec "dir *.java"<br />Execing cmd.exe /C dir *.java<br />OUTPUT&gt; Volume in drive E has no label.<br />OUTPUT&gt; Volume Serial Number is 5C5F-0CC9<br />OUTPUT&gt;<br />OUTPUT&gt; Directory of E:classescomjavaworldjpitfallsarticle2<br />OUTPUT&gt;<br />OUTPUT&gt;10/23/00 09:01p 805 BadExecBrowser.java<br />OUTPUT&gt;10/22/00 09:35a 770 BadExecBrowser1.java<br />OUTPUT&gt;10/24/00 08:45p 488 BadExecJavac.java<br />OUTPUT&gt;10/24/00 08:46p 519 BadExecJavac2.java<br />OUTPUT&gt;10/24/00 09:13p 930 BadExecWinDir.java<br />OUTPUT&gt;10/22/00 09:21a 2,282 BadURLPost.java<br />OUTPUT&gt;10/22/00 09:20a 2,273 BadURLPost1.java<br />... (some output omitted for brevity)<br />OUTPUT&gt;10/12/00 09:29p 151 SuperFrame.java<br />OUTPUT&gt;10/24/00 09:23p 1,814 TestExec.java<br />OUTPUT&gt;10/09/00 05:47p 23,543 TestStringReplace.java<br />OUTPUT&gt;10/12/00 08:55p 228 TopLevel.java<br />OUTPUT&gt; 22 File(s) 46,661 bytes<br />OUTPUT&gt; 19,678,420,992 bytes free<br />ExitValue: 0</font>
		</p>
		<p>
				<font size="2">这里作者教了一个windows中很有用的方法，呵呵，至少我是不知道的，就是cmd.exe /C +一个windows中注册了后缀的文档名，windows会自动地调用相关的程序来打开这个文档，我试了一下，的确很好用，但是好像文件路径中有空格的话就有点问题，我加上引号也无法解决。</font>
		</p>
		<p>
				<font size="2">这里作者强调了一下，不要假设你执行的程序是可执行的程序，要清楚自己的程序是单独可执行的还是被解释的，本章的结束作者会介绍一个命令行工具来帮助我们分析。</font>
		</p>
		<p>
				<font size="2">这里还有一点，就是得到process的输出的方式是getInputStream，这是因为我们要从Java 程序的角度来看，外部程序的输出对于Java来说就是输入，反之亦然。</font>
		</p>
		<p>
				<br />
				<font size="2">最后的一个漏洞的地方就是错误的认为exec方法会接受所有你在命令行或者Shell中输入并接受的字符串。这些错误主要出现在命令作为参数的情况下，程序员错误的将所有命令行中可以输入的参数命令加入到exec中（这段翻译的不好，凑合看吧）。下面的例子中就是一个程序员想重定向一个命令的输出。</font>
		</p>
		<p>
				<br />
				<font size="2">import java.util.*;<br />import java.io.*;</font>
		</p>
		<p>
				<font size="2">// StreamGobbler omitted for brevity</font>
		</p>
		<p>
				<font size="2">public class BadWinRedirect<br />{<br />public static void main(String args[])<br />{<br />try<br />{ <br />Runtime rt = Runtime.getRuntime();<br />Process proc = rt.exec("java jecho 'Hello World' &gt; test.txt");<br />// any error message?<br />StreamGobbler errorGobbler = new <br />StreamGobbler(proc.getErrorStream(), "ERROR"); </font>
		</p>
		<p>
				<font size="2">// any output?<br />StreamGobbler outputGobbler = new <br />StreamGobbler(proc.getInputStream(), "OUTPUT");</font>
		</p>
		<p>
				<font size="2">// kick them off<br />errorGobbler.start();<br />outputGobbler.start();</font>
		</p>
		<p>
				<font size="2">// any error???<br />int exitVal = proc.waitFor();<br />System.out.println("ExitValue: " + exitVal); <br />} catch (Throwable t)<br />{<br />t.printStackTrace();<br />}<br />}<br />}</font>
		</p>
		<p>
				<font size="2">Running BadWinRedirect produces: </font>
		</p>
		<p>
				<br />
				<font size="2">E:classescomjavaworldjpitfallsarticle2&gt;java BadWinRedirect<br />OUTPUT&gt;'Hello World' &gt; test.txt<br />ExitValue: 0</font>
		</p>
		<p>
				<font size="2">程序员的本意是将Hello World这个输入重订向到一个文本文件中，但是这个文件并没有生成，jecho仅仅是将命令行中的参数输出到标准输出中，用户觉得可以像dos中重定向一样将输出重定向到一个文件中，但这并不能实现，用户错误的将exec认为是一个shell解释器，但它并不是，如果你想将一个程序的输出重定向到其他的程序中，你必须用程序来实现他。可用java.io中的包。</font>
		</p>
		<p>
				<br />
				<font size="2">import java.util.*;<br />import java.io.*;</font>
		</p>
		<p>
				<font size="2">class StreamGobbler extends Thread<br />{<br />InputStream is;<br />String type;<br />OutputStream os;</font>
		</p>
		<p>
				<font size="2">StreamGobbler(InputStream is, String type)<br />{<br />this(is, type, null);<br />}</font>
		</p>
		<p>
				<font size="2">StreamGobbler(InputStream is, String type, OutputStream redirect)<br />{<br />this.is = is;<br />this.type = type;<br />this.os = redirect;<br />}</font>
		</p>
		<p>
				<font size="2">public void run()<br />{<br />try<br />{<br />PrintWriter pw = null;<br />if (os != null)<br />pw = new PrintWriter(os);</font>
		</p>
		<p>
				<font size="2">InputStreamReader isr = new InputStreamReader(is);<br />BufferedReader br = new BufferedReader(isr);<br />String line=null;<br />while ( (line = br.readLine()) != null)<br />{<br />if (pw != null)<br />pw.println(line);<br />System.out.println(type + "&gt;" + line); <br />}<br />if (pw != null)<br />pw.flush();<br />} catch (IOException ioe)<br />{<br />ioe.printStackTrace(); <br />}<br />}<br />}</font>
		</p>
		<p>
				<font size="2">public class GoodWinRedirect<br />{<br />public static void main(String args[])<br />{<br />if (args.length &lt; 1)<br />{<br />System.out.println("USAGE java GoodWinRedirect &lt;outputfile&gt;");<br />System.exit(1);<br />}</font>
		</p>
		<p>
				<font size="2">try<br />{ <br />FileOutputStream fos = new FileOutputStream(args[0]);<br />Runtime rt = Runtime.getRuntime();<br />Process proc = rt.exec("java jecho 'Hello World'");<br />// any error message?<br />StreamGobbler errorGobbler = new <br />StreamGobbler(proc.getErrorStream(), "ERROR"); </font>
		</p>
		<p>
				<font size="2">// any output?<br />StreamGobbler outputGobbler = new <br />StreamGobbler(proc.getInputStream(), "OUTPUT", fos);</font>
		</p>
		<p>
				<font size="2">// kick them off<br />errorGobbler.start();<br />outputGobbler.start();</font>
		</p>
		<p>
				<font size="2">// any error???<br />int exitVal = proc.waitFor();<br />System.out.println("ExitValue: " + exitVal);<br />fos.flush();<br />fos.close(); <br />} catch (Throwable t)<br />{<br />t.printStackTrace();<br />}<br />}<br />}</font>
		</p>
		<p>
				<font size="2">Running GoodWinRedirect produces: </font>
		</p>
		<p>
				<br />
				<font size="2">E:classescomjavaworldjpitfallsarticle2&gt;java GoodWinRedirect test.txt<br />OUTPUT&gt;'Hello World'<br />ExitValue: 0</font>
		</p>
		<p>
				<font size="2">这里就不多说了，看看就明白，紧接着作者给出了一个监测命令的小程序</font>
		</p>
		<p>
				<font size="2">import java.util.*;<br />import java.io.*;</font>
		</p>
		<p>
				<font size="2">// class StreamGobbler omitted for brevity</font>
		</p>
		<p>
				<font size="2">public class TestExec<br />{<br />public static void main(String args[])<br />{<br />if (args.length &lt; 1)<br />{<br />System.out.println("USAGE: java TestExec "cmd"");<br />System.exit(1);<br />}</font>
		</p>
		<p>
				<font size="2">try<br />{<br />String cmd = args[0];<br />Runtime rt = Runtime.getRuntime();<br />Process proc = rt.exec(cmd);</font>
		</p>
		<p>
				<font size="2">// any error message?<br />StreamGobbler errorGobbler = new <br />StreamGobbler(proc.getErrorStream(), "ERR"); </font>
		</p>
		<p>
				<font size="2">// any output?<br />StreamGobbler outputGobbler = new <br />StreamGobbler(proc.getInputStream(), "OUT");</font>
		</p>
		<p>
				<font size="2">// kick them off<br />errorGobbler.start();<br />outputGobbler.start();</font>
		</p>
		<p>
				<font size="2">// any error???<br />int exitVal = proc.waitFor();<br />System.out.println("ExitValue: " + exitVal);<br />} catch (Throwable t)<br />{<br />t.printStackTrace();<br />}<br />}<br />}</font>
		</p>
		<p>
				<font size="2">对这个程序进行运行: <br />E:classescomjavaworldjpitfallsarticle2&gt;java TestExec "e:javadocsindex.html"<br />java.io.IOException: CreateProcess: e:javadocsindex.html error=193<br />at java.lang.Win32Process.create(Native Method)<br />at java.lang.Win32Process.&lt;init&gt;(Unknown Source)<br />at java.lang.Runtime.execInternal(Native Method)<br />at java.lang.Runtime.exec(Unknown Source)<br />at java.lang.Runtime.exec(Unknown Source)<br />at java.lang.Runtime.exec(Unknown Source)<br />at java.lang.Runtime.exec(Unknown Source)<br />at TestExec.main(TestExec.java:45)</font>
		</p>
		<p>
				<font size="2">193在windows中是说这不是一个win32程序，这说明路径中找不到这个网页的关联程序，下面作者决定用一个绝对路径来试一下。</font>
		</p>
		<p>
				<font size="2">E:classescomjavaworldjpitfallsarticle2&gt;java TestExec <br />"e:program filesnetscapeprogramnetscape.exe e:javadocsindex.html"<br />ExitValue: 0</font>
		</p>
		<p>
				<br />
				<font size="2">好用了，这个我也试了一下，用的是IE。</font>
		</p>
		<p>
				<br />
				<font size="2">最后，作者总结了几条规则，防止我们在进行Runtime.exec()调用时出现错误。</font>
		</p>
		<p>
				<br />
				<font size="2">1、 在一个外部进程执行完之前你不能得到他的退出状态</font>
		</p>
		<p>
				<font size="2">2、 在你的外部程序开始执行的时候你必须马上控制输入、输出、出错这些流。</font>
		</p>
		<p>
				<font size="2">3、 你必须用Runtime.exec()去执行程序</font>
		</p>
		<p>
				<font size="2">4、你不能象命令行一样使用Runtime.exec()。</font>
		</p>
<img src ="http://www.blogjava.net/joaquin25/aggbug/199444.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/joaquin25/" target="_blank">joaquin25</a> 2008-05-09 11:15 <a href="http://www.blogjava.net/joaquin25/articles/199444.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JAVA 获得当前类的路径</title><link>http://www.blogjava.net/joaquin25/articles/199152.html</link><dc:creator>joaquin25</dc:creator><author>joaquin25</author><pubDate>Thu, 08 May 2008 02:21:00 GMT</pubDate><guid>http://www.blogjava.net/joaquin25/articles/199152.html</guid><wfw:comment>http://www.blogjava.net/joaquin25/comments/199152.html</wfw:comment><comments>http://www.blogjava.net/joaquin25/articles/199152.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/joaquin25/comments/commentRss/199152.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/joaquin25/services/trackbacks/199152.html</trackback:ping><description><![CDATA[
		<div>
				<font face="宋体" size="2">转自：<a href="http://hi.baidu.com/applesky/blog/item/16cd6c2760a77e01908f9d3c.html">http://hi.baidu.com/applesky/blog/item/16cd6c2760a77e01908f9d3c.html</a><br />Java中获得程序当前路径的4中方法:<br /><br />在Application中: <br /><br /><br /><br />import java.util.*;<br /><br />public class TestUserDir {<br /><br /><br /><br />/**<br /><br />* @param args<br /><br />*/<br /><br />public static void main(String[] args) {<br /><br />// TODO Auto-generated method stub<br /><br />Properties property = System.getProperties();<br /><br />String str = property.getProperty("user.dir");<br /><br />System.out.println(str);<br /><br />}<br /><br /><br /><br />}<br /><br /></font>
		</div>
		<div>
				<font face="宋体" size="2">或者：</font>
		</div>
		<font face="宋体" size="2">public class getPath<br />{<br />        public static void main(String[] args)<br />        {<br />            String s=System.getProperty("java.class.path");<br />            System.out.println(s);<br />        }<br />}<br /><br /><br /><br />输出：F:\code\ec\JavaDBStudy<br /><br /><br /><br />在Servlet中: <br /><br />ServletContext servletContext = config.getServletContext(); <br /><br />String rootPath = servletContext.getRealPath("/"); </font>
<img src ="http://www.blogjava.net/joaquin25/aggbug/199152.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/joaquin25/" target="_blank">joaquin25</a> 2008-05-08 10:21 <a href="http://www.blogjava.net/joaquin25/articles/199152.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java Annotation 高级应用</title><link>http://www.blogjava.net/joaquin25/articles/197456.html</link><dc:creator>joaquin25</dc:creator><author>joaquin25</author><pubDate>Wed, 30 Apr 2008 02:36:00 GMT</pubDate><guid>http://www.blogjava.net/joaquin25/articles/197456.html</guid><wfw:comment>http://www.blogjava.net/joaquin25/comments/197456.html</wfw:comment><comments>http://www.blogjava.net/joaquin25/articles/197456.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/joaquin25/comments/commentRss/197456.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/joaquin25/services/trackbacks/197456.html</trackback:ping><description><![CDATA[
		<p align="center">
				<span style="COLOR: red">
						<font color="#000000">
								<font size="6">
										<strong>Java Annotation 高级应用</strong>
								</font>
								<br />
						</font>
						<br />版权声明：本文可以自由转载，转载时请务必以超链接形式标明文章原始出处和作者信息及本声明</span>
				<br />作者:cleverpig(作者的Blog:<a href="http://blog.matrix.org.cn/page/cleverpig" target="_new"><font color="#002c99">http://blog.matrix.org.cn/page/cleverpig</font></a>)<br />原文:<a href="http://www.matrix.org.cn/resource/article/44/44062_Java+Annotation+Apt.html" target="_new"><font color="#002c99">http://www.matrix.org.cn/resource/article/44/44062_Java+Annotation+Apt.html</font></a><br />关键字:java,annotation,apt<br /><br /><span style="COLOR: blue">前言：</span><br />前不久在matrix上先后发表了<a href="http://www.matrix.org.cn/resource/article/44/44048_Java+Annotation.html" target="_new"><font color="#002c99">《java annotation 入门》</font></a>、<a href="http://www.matrix.org.cn/resource/article/44/44055_Java+Annotation+Reflect.html" target="_new"><font color="#002c99">《java annotation 手册》</font></a>两篇文章，比较全面的对java annotation的语法、原理、使用三方面进行了阐述。由于《入门》中的简单例程虽然简单明了的说明了annotation用法，但给大家的感觉可能是意犹未见，所以在此行文《java annotation高级应用》，具体实例化解释annotation和annotation processing tool（APT）的使用。望能对各位的有所帮助。<br /><br /><span style="COLOR: blue">一、摘要：</span><br />《java annotation高级应用》具体实例化解释annotation和annotation processing tool（APT）的使用。望能对各位的有所帮助。本文列举了用于演示annotation的BRFW演示框架、演示APT的apt代码实例，并对其进行较为深度的分析，希望大家多多提意见。<br /><br /><span style="COLOR: blue">二、annotation实例分析</span><br /><span style="COLOR: blue">1．BRFW（Beaninfo Runtime FrameWork）定义：</span><br />本人编写的一个annotation功能演示框架。顾名思义，BRFW就是在运行时取得bean信息的框架。<br /><br /><span style="COLOR: blue">2．BRFW的功能：</span><br /><span style="COLOR: green">A．源代码级annotation</span>：在bean的源代码中使用annotation定义bean的信息；<br /><span style="COLOR: green">B．运行时获取bean数据</span>：在运行时分析bean class中的annotation，并将当前bean class中field信息取出，功能类似xdoclet；<br /><span style="COLOR: green">C．运行时bean数据的xml绑定</span>：将获得的bean数据构造为xml文件格式展现。熟悉j2ee的朋友知道，这个功能类似jaxb。<br /><br /><span style="COLOR: blue">3．BRFW框架：</span><br />BRFW主要包含以下几个类：<br /><span style="COLOR: green">A．Persistent类</span>：定义了用于修饰类的固有类型成员变量的annotation。<br /><span style="COLOR: green">B．Exportable类</span>：定义了用于修饰Class的类型的annotation。<br /><span style="COLOR: green">C．ExportToXml类</span>：核心类，用于完成BRFW的主要功能：将具有Exportable Annotation的bean对象转换为xml格式文本。<br /><span style="COLOR: green">D．AddressForTest类</span>：被A和B修饰过的用于测试目的的地址bean类。其中包含了地址定义所必需的信息：国家、省级、城市、街道、门牌等。<br /><span style="COLOR: green">E．AddressListForTest类</span>：被A和B修饰过的友人通讯录bean类。其中包含了通讯录所必备的信息：友人姓名、年龄、电话、住址（成员为AddressForTest类型的ArrayList）、备注。需要说明的是电话这个bean成员变量是由字符串类型组成的ArrayList类型。由于朋友的住址可能不唯一，故这里的住址为由AddressForTest类型组成的ArrayList。<br />从上面的列表中，可以发现A、B用于修饰bean类和其类成员；C主要用于取出bean类的数据并将其作xml绑定，代码中使用了E作为测试类；E中可能包含着多个D。<br />在了解了这个简单框架后，我们来看一下BRFW的代码吧！<br /><br /><span style="COLOR: blue">4．BRFW源代码分析：</span><br /><span style="COLOR: green">A．Persistent类：</span><br /><b>清单1：</b><br /></p>
		<pre class="overflow">
				<br />package com.bjinfotech.practice.annotation.runtimeframework;<br /><br />import java.lang.annotation.*;<br /><br />/**<br /> * 用于修饰类的固有类型成员变量的annotation<br /> * @author cleverpig<br /> *<br /> */<br />@Retention(RetentionPolicy.RUNTIME)<br />@Target(ElementType.FIELD)<br />public @interface Persistent { <br />        String value() default "";<br />}<br /></pre>
		<br />
		<br />
		<span style="COLOR: green">B．Exportable类：</span>
		<br />
		<b>清单2：</b>
		<br />
		<pre class="overflow">
				<br />package com.bjinfotech.practice.annotation.runtimeframework;<br /><br />import java.lang.annotation.*;<br /><br />/**<br /> * 用于修饰类的类型的annotation<br /> * @author cleverpig<br /> *<br /> */<br />@Retention(RetentionPolicy.RUNTIME)<br />@Target(ElementType.TYPE)<br />public @interface Exportable {<br />        //名称<br />        String name() default "";<br />        //描述<br />        String description() default "";<br />        //省略name和description后，用来保存name值<br />        String value() default "";<br />        <br />}<br /></pre>
		<br />
		<br />
		<span style="COLOR: green">C．AddressForTest类：</span>
		<br />
		<b>清单3：</b>
		<br />
		<pre class="overflow">
				<br />package com.bjinfotech.practice.annotation.runtimeframework;<br /><br />/**<br /> * 用于测试的地址类<br /> * @author cleverpig<br /> *<br /> */<br />@Exportable("address")<br />public class AddressForTest {<br />        //国家<br />        @Persistent<br />        private String country=null;<br />        <br />        //省级<br />        @Persistent<br />        private String province=null;<br />        <br />        //城市<br />        @Persistent<br />        private String city=null;<br />        <br />        //街道<br />        @Persistent<br />        private String street=null;<br /><br />        //门牌<br />        @Persistent<br />        private String doorplate=null;<br />        <br />        public AddressForTest(String country,String province,<br />                        String city,String street,String doorplate){<br />                this.country=country;<br />                this.province=province;<br />                this.city=city;<br />                this.street=street;<br />                this.doorplate=doorplate;<br />        }<br />        <br />}<br /></pre>
		<br />
		<br />
		<span style="COLOR: green">D．AddressListForTest类：</span>
		<br />
		<b>清单4：</b>
		<br />
		<pre class="overflow">
				<br />package com.bjinfotech.practice.annotation.runtimeframework;<br /><br />import java.util.*;<br /><br />/**<br /> * 友人通讯录<br /> * 包含：姓名、年龄、电话、住址（多个）、备注<br /> * @author cleverpig<br /> *<br /> */<br />@Exportable(name="addresslist",description="address list")<br />public class AddressListForTest {<br />        //友人姓名<br />        @Persistent<br />        private String friendName=null;<br />        <br />        //友人年龄<br />        @Persistent<br />        private int age=0;<br />        <br />        //友人电话<br />        @Persistent<br />        private ArrayList&lt;String&gt; telephone=null;<br />        <br />        //友人住址：家庭、单位<br />        @Persistent<br />        private ArrayList&lt;AddressForTest&gt; AddressForText=null;<br />        <br />        //备注<br />        @Persistent<br />        private String note=null;<br />        <br />        public AddressListForTest(String name,int age,<br />                        ArrayList&lt;String&gt; telephoneList, <br />                        ArrayList&lt;AddressForTest&gt; addressList,<br />                        String note){<br />                this.friendName=name;<br />                this.age=age;<br />                this.telephone=new ArrayList&lt;String&gt;(telephoneList);<br />                this.AddressForText=new ArrayList&lt;AddressForTest&gt;(addressList);<br />                this.note=note;<br />                <br />        }<br />}<br /></pre>
		<br />
		<br />
		<span style="COLOR: green">E．ExportToXml类：</span>
		<br />
		<b>清单5：</b>
		<br />
		<pre class="overflow">
				<br />package com.bjinfotech.practice.annotation.runtimeframework;<br /><br />import java.lang.reflect.Field;<br />import java.util.Collection;<br />import java.util.Iterator;<br />import java.util.Map;<br />import java.util.ArrayList;<br /><br />/**<br /> * 将具有Exportable Annotation的对象转换为xml格式文本 <br /> * @author cleverpig<br /> *<br /> */<br />public class ExportToXml {<br />        /**<br />         * 返回对象的成员变量的值（字符串类型）<br />         * @param field 对象的成员变量<br />         * @param fieldTypeClass 对象的类型<br />         * @param obj 对象<br />         * @return 对象的成员变量的值（字符串类型）<br />         */<br />        private String getFieldValue(Field field,Class fieldTypeClass,Object obj){<br />                String value=null;<br />                <br />                try{<br />                        if (fieldTypeClass==String.class){<br />                                value=(String)field.get(obj);<br />                        }<br />                        else if (fieldTypeClass==int.class){<br />                                value=Integer.toString(field.getInt(obj));<br />                        }<br />                        else if (fieldTypeClass==long.class){<br />                                value=Long.toString(field.getLong(obj));<br />                        }<br />                        else if (fieldTypeClass==short.class){<br />                                value=Short.toString(field.getShort(obj));<br />                        }<br />                        else if (fieldTypeClass==float.class){<br />                                value=Float.toString(field.getFloat(obj));<br />                        }<br />                        else if (fieldTypeClass==double.class){<br />                                value=Double.toString(field.getDouble(obj));<br />                        }<br />                        else if (fieldTypeClass==byte.class){<br />                                value=Byte.toString(field.getByte(obj));<br />                        }<br />                        else if (fieldTypeClass==char.class){<br />                                value=Character.toString(field.getChar(obj));<br />                        }<br />                        else if (fieldTypeClass==boolean.class){<br />                                value=Boolean.toString(field.getBoolean(obj));<br />                        }<br />                }<br />                catch(Exception ex){<br />                        ex.printStackTrace();<br />                        value=null;<br />                }<br />                return value;<br />        }<br />        <br />        /**<br />         * 输出对象的字段，当对象的字段为Collection或者Map类型时，要调用exportObject方法继续处理<br />         * @param obj 被处理的对象<br />         * @throws Exception<br />         */<br />        public void exportFields(Object obj) throws Exception{<br />                Exportable exportable=obj.getClass().getAnnotation(Exportable.class);        <br />                if (exportable!=null){<br />                        if (exportable.value().length()&gt;0){<br />//                                System.out.println("Class annotation Name:"+exportable.value());<br />                        }<br />                        else{<br />//                                System.out.println("Class annotation Name:"+exportable.name());<br />                        }<br />                }<br />                else{<br />//                        System.out.println(obj.getClass()+"类不是使用Exportable标注过的");<br />                }<br />                <br />                //取出对象的成员变量<br />                Field[] fields=obj.getClass().getDeclaredFields();<br />                <br />                for(Field field:fields){<br />                        //获得成员变量的标注<br />                        Persistent fieldAnnotation=field.getAnnotation(Persistent.class);<br />                        if (fieldAnnotation==null){<br />                                continue;<br />                        }<br />                        //重要:避免java虚拟机检查对私有成员的访问权限<br />                        field.setAccessible(true);<br />                        Class typeClass=field.getType();<br />                        String name=field.getName();<br />                        String value=getFieldValue(field,typeClass,obj);<br />                        <br />                        //如果获得成员变量的值，则输出<br />                        if (value!=null){<br />                                System.out.println(getIndent()+"&lt;"+name+"&gt;\n"<br />                                                +getIndent()+"\t"+value+"\n"+getIndent()+"&lt;/"+name+"&gt;");<br />                        }<br />                        //处理成员变量中类型为Collection或Map<br />                        else if ((field.get(obj) instanceof Collection)||<br />                                        (field.get(obj) instanceof Map)){<br />                                exportObject(field.get(obj));<br />                        }<br />                        else{<br />                                exportObject(field.get(obj));<br />                        }<br />                        <br />                }<br />        }<br />        <br />        //缩进深度<br />        int levelDepth=0;<br />        //防止循环引用的检查者，循环引用现象如：a包含b，而b又包含a<br />        Collection&lt;Object&gt; cyclicChecker=new ArrayList&lt;Object&gt;();<br />        <br />        /**<br />         * 返回缩进字符串<br />         * @return<br />         */<br />        private String getIndent(){<br />                String s="";<br />                for(int i=0;i&lt;levelDepth;i++){<br />                        s+="\t";<br />                }<br />                return s;<br />        }<br />        /**<br />         * 输出对象，如果对象类型为Collection和Map类型，则需要递归调用exportObject进行处理<br />         * @param obj<br />         * @throws Exception<br />         */<br />        public void exportObject(Object obj) throws Exception{<br />                Exportable exportable=null;<br />                String elementName=null;<br />                <br />                //循环引用现象处理<br />                if (cyclicChecker.contains(obj)){<br />                        return;<br />                }<br />                <br />                cyclicChecker.add(obj);<br />                <br />                //首先处理Collection和Map类型<br />                if (obj instanceof Collection){<br />                        for(Iterator i=((Collection)obj).iterator();i.hasNext();){<br />                                exportObject(i.next());<br />                        }<br />                }<br />                else if (obj instanceof Map){<br />                        for(Iterator i=((Map)obj).keySet().iterator();i.hasNext();){<br />                                exportObject(i.next());<br />                        }<br />                }<br />                else{<br /><br />                        exportable=obj.getClass().getAnnotation(Exportable.class);<br />                        //如果obj已经被Exportable Annotation修饰过了（注意annotation是具有继承性的），<br />                        //则使用其name作为输出xml的元素name<br />                        if (exportable!=null){<br />                                if (exportable.value().length()&gt;0){<br />                                        elementName=exportable.value();<br />                                }<br />                                else{<br />                                        elementName=exportable.name();<br />                                }<br />                        }<br />                        //未被修饰或者Exportable Annotation的值为空字符串，<br />                        //则使用类名作为输出xml的元素name<br />                        if (exportable==null||elementName.length()==0){<br />                                elementName=obj.getClass().getSimpleName();<br />                        }<br />                        //输出xml元素头<br />                        System.out.println(getIndent()+"&lt;"+elementName+"&gt;");<br />                        levelDepth++;<br />                        //如果没有被修饰，则直接输出其toString()作为元素值<br />                        if (exportable==null){<br />                                System.out.println(getIndent()+obj.toString());<br />                        }<br />                        //否则将对象的成员变量导出为xml<br />                        else{<br />                                exportFields(obj);<br />                        }<br />                        levelDepth--;<br />                        //输出xml元素结尾<br />                        System.out.println(getIndent()+"&lt;/"+elementName+"&gt;");<br />                        <br />                }<br />                cyclicChecker.remove(obj);<br />        }<br />        <br />        public static void main(String[] argv){<br />                try{<br />                        AddressForTest ad=new AddressForTest("China","Beijing",<br />                                        "Beijing","winnerStreet","10");<br />                        <br />                        ExportToXml test=new ExportToXml();<br />                        <br />                        ArrayList&lt;String&gt; telephoneList=new ArrayList&lt;String&gt;();<br />                        telephoneList.add("66608888");<br />                        telephoneList.add("66608889");<br />                        <br />                        ArrayList&lt;AddressForTest&gt; adList=new ArrayList&lt;AddressForTest&gt;();<br />                        adList.add(ad);<br />                        <br />                        AddressListForTest adl=new AddressListForTest("coolBoy",<br />                                        18,telephoneList,adList,"some words");<br />                        <br />                        test.exportObject(adl);<br />                }<br />                catch(Exception ex){<br />                        ex.printStackTrace();<br />                }<br />        }<br />}<br /></pre>
		<br />
		<br />在ExportToXml类之前的类比较简单，这里必须说明一下ExportToXml类：此类的核心函数是exportObject和exportFields方法，前者输出对象的xml信息，后者输出对象成员变量的信息。由于对象类型和成员类型的多样性，所以采取了以下的逻辑：<br /><br />在exportObject方法中，当对象类型为Collection和Map类型时，则需要递归调用exportObject进行处理；<br />而如果对象类型不是Collection和Map类型的话，将判断对象类是否被Exportable annotation修饰过：<br />如果没有被修饰，则直接输出&lt;对象类名&gt;对象.toString()&lt;/对象类名&gt;作为xml绑定结果的一部分；<br />如果被修饰过，则需要调用exportFields方法对对象的成员变量进行xml绑定。<br /><br />在exportFields方法中，首先取出对象的所有成员，然后获得被Persisitent annotation修饰的成员。在其后的一句：field.setAccessible(true)是很重要的，因为bean类定义中的成员访问修饰都是private，所以为了避免java虚拟机检查对私有成员的访问权限，加上这一句是必需的。接着后面的语句便是输出&lt;成员名&gt;成员值&lt;/成员名&gt;这样的xml结构。像在exportObject方法中一般，仍然需要判断成员类型是否为Collection和Map类型，如果为上述两种类型之一，则要在exportFields中再次调用exportObject来处理这个成员。<br /><br />在main方法中，本人编写了一段演示代码：建立了一个由单个友人地址类（AddressForTest）组成的ArrayList作为通讯录类（AddressForTest）的成员的通讯录对象，并且输出这个对象的xml绑定，运行结果如下：<br /><br /><b>清单6：</b><br /><pre class="overflow"><br />&lt;addresslist&gt;<br />        &lt;friendName&gt;<br />                coolBoy<br />        &lt;/friendName&gt;<br />        &lt;age&gt;<br />                18<br />        &lt;/age&gt;<br />        &lt;String&gt;<br />                66608888<br />        &lt;/String&gt;<br />        &lt;String&gt;<br />                66608889<br />        &lt;/String&gt;<br />        &lt;address&gt;<br />                &lt;country&gt;<br />                        China<br />                &lt;/country&gt;<br />                &lt;province&gt;<br />                        Beijing<br />                &lt;/province&gt;<br />                &lt;city&gt;<br />                        Beijing<br />                &lt;/city&gt;<br />                &lt;street&gt;<br />                        winnerStreet<br />                &lt;/street&gt;<br />                &lt;doorplate&gt;<br />                        10<br />                &lt;/doorplate&gt;<br />        &lt;/address&gt;<br />        &lt;note&gt;<br />                some words<br />        &lt;/note&gt;<br />&lt;/addresslist&gt;<br /></pre><br /><br /><span style="COLOR: blue">三、APT实例分析：</span><br /><span style="COLOR: blue">1．何谓APT？</span><br />根据sun官方的解释，APT（annotation processing tool）是一个命令行工具，它对源代码文件进行检测找出其中的annotation后，使用annotation processors来处理annotation。而annotation processors使用了一套反射API并具备对JSR175规范的支持。<br />annotation processors处理annotation的基本过程如下：首先，APT运行annotation processors根据提供的源文件中的annotation生成源代码文件和其它的文件（文件具体内容由annotation processors的编写者决定），接着APT将生成的源代码文件和提供的源文件进行编译生成类文件。<br />简单的和前面所讲的annotation实例BRFW相比，APT就像一个在编译时处理annotation的javac。而且从sun开发者的blog中看到，java1.6 beta版中已将APT的功能写入到了javac中，这样只要执行带有特定参数的javac就能达到APT的功能。<br /><br /><span style="COLOR: blue">2．为何使用APT？</span><br />使用APT主要目的是简化开发者的工作量，因为APT可以在编译程序源代码的同时，生成一些附属文件（比如源文件、类文件、程序发布描述文字等），这些附属文件的内容也都是与源代码相关的。换句话说，使用APT就是代替了传统的对代码信息和附属文件的维护工作。使用过hibernate或者beehive等软件的朋友可能深有体会。APT可以在编译生成代码类的同时将相关的文件写好，比如在使用beehive时，在代码中使用annotation声明了许多struct要用到的配置信息，而在编译后，这些信息会被APT以struct配置文件的方式存放。<br /><br /><span style="COLOR: blue">3．如何定义processor？</span><br /><span style="COLOR: green">A．APT工作过程：</span><br />从整个过程来讲，首先APT检测在源代码文件中哪些annotation存在。然后APT将查找我们编写的annotation processor factories类，并且要求factories类提供处理源文件中所涉及的annotation的annotation processor。接下来，一个合适的annotation processors将被执行，如果在processors生成源代码文件时，该文件中含有annotation，则APT将重复上面的过程直到没有新文件生成。<br /><br /><span style="COLOR: green">B．编写annotation processors：</span><br />编写一个annotation processors需要使用java1.5 lib目录中的tools.jar提供的以下4个包：<br />com.sun.mirror.apt: 和APT交互的接口；<br />com.sun.mirror.declaration: 用于模式化类成员、类方法、类声明的接口；<br />com.sun.mirror.type: 用于模式化源代码中类型的接口； <br />com.sun.mirror.util: 提供了用于处理类型和声明的一些工具。 <br /><br />每个processor实现了在com.sun.mirror.apt包中的AnnotationProcessor接口，这个接口有一个名为“process”的方法，该方法是在APT调用processor时将被用到的。一个processor可以处理一种或者多种annotation类型。<br />一个processor实例被其相应的工厂返回，此工厂为AnnotationProcessorFactory接口的实现。APT将调用工厂类的getProcessorFor方法来获得processor。在调用过程中，APT将提供给工厂类一个AnnotationProcessorEnvironment 类型的processor环境类对象，在这个环境对象中，processor将找到其执行所需要的每件东西，包括对所操作的程序结构的参考，与APT通讯并合作一同完成新文件的建立和警告/错误信息的传输。<br /><br />提供工厂类有两个方式：通过APT的“-factory”命令行参数提供，或者让工厂类在APT的发现过程中被自动定位（关于发现过程详细介绍请看<a href="http://java.sun.com/j2se/1.5.0/docs/guide/apt/GettingStarted.html" target="_new"><font color="#002c99">http://java.sun.com/j2se/1.5.0/docs/guide/apt/GettingStarted.html</font></a>）。前者对于一个已知的factory来讲是一种主动而又简单的方式；而后者则是需要在jar文件的META-INF/services目录中提供一个特定的发现路径：<br />在包含factory类的jar文件中作以下的操作：在META-INF/services目录中建立一个名为com.sun.mirror.apt.AnnotationProcessorFactory 的UTF-8编码文件，在文件中写入所有要使用到的factory类全名，每个类为一个单独行。<br /><br /><span style="COLOR: blue">4．一个简单的APT实例分析：</span><br /><span style="COLOR: green">A．实例构成：</span><br />Review类：定义Review Annotation；<br />ReviewProcessorFactory类：生成ReviewProcessor的工厂类；<br />ReviewProcessor类：定义处理Review annotation的Processor；<br />ReviewDeclarationVisitor类：定义Review annotation声明访问者，ReviewProcessor将要使用之对Class进行访问。<br />runapt.bat：定义了使用自定义的ReviewProcessor对Review类源代码文件进行处理的APT命令行。<br /><br /><span style="COLOR: green">B．Review类：</span><br /><b>清单7：</b><br /><pre class="overflow"><br />package com.bjinfotech.practice.annotation.apt;<br /><br />/**<br /> * 定义Review Annotation<br /> * @author cleverpig<br /> *<br /> */<br />public @interface Review {<br />        public static enum TypeEnum{EXCELLENT,NICE,NORMAL,BAD};<br />        TypeEnum type();<br />        String name() default "Review";<br />}<br /></pre><br /><br /><span style="COLOR: green">C．ReviewProcessorFactory类：</span><br /><b>清单8：</b><br /><pre class="overflow"><br />package com.bjinfotech.practice.annotation.apt;<br /><br />import java.util.Collection;<br />import java.util.Set;<br />import java.util.Arrays;<br />import com.sun.mirror.apt.*;<br />import com.sun.mirror.declaration.AnnotationTypeDeclaration;<br />import com.sun.mirror.apt.AnnotationProcessorEnvironment;<br />//请注意为了方便，使用了静态import<br />import static java.util.Collections.unmodifiableCollection;<br />import static java.util.Collections.emptySet;<br /><br />/**<br /> * 生成ReviewProcessor的工厂类<br /> * @author cleverpig<br /> *<br /> */<br />public class ReviewProcessorFactory implements AnnotationProcessorFactory{<br />        /**<br />         * 获得针对某个（些）类型声明定义的Processor<br />         * @param atds 类型声明集合<br />         * @param env processor环境<br />         */<br />        public AnnotationProcessor getProcessorFor(<br />                        Set&lt;AnnotationTypeDeclaration&gt; atds, <br />                        AnnotationProcessorEnvironment env){<br />                return new ReviewProcessor(env);<br />        }<br />        /**<br />         * 定义processor所支持的annotation类型<br />         * @return processor所支持的annotation类型的集合<br />         */<br />        public Collection&lt;String&gt;         supportedAnnotationTypes(){<br />                //“*”表示支持所有的annotation类型<br />                //当然也可以修改为“foo.bar.*”、“foo.bar.Baz”，来对所支持的类型进行修饰<br />            return unmodifiableCollection(Arrays.asList("*"));<br />    }<br />        <br />        /**<br />         * 定义processor支持的选项<br />         * @return processor支持选项的集合<br />         */<br />        public Collection&lt;String&gt;         supportedOptions(){<br />                //返回空集合<br />            return emptySet();<br />    }<br />        <br />        public static void main(String[] argv){<br />                System.out.println("ok");<br />        }<br />}<br /></pre><br /><br /><span style="COLOR: green">D．ReviewProcessor类：</span><br /><b>清单9：</b><br /><pre class="overflow"><br />package com.bjinfotech.practice.annotation.apt;<br /><br />import com.sun.mirror.apt.AnnotationProcessor;<br />import com.sun.mirror.apt.AnnotationProcessorEnvironment;<br />import com.sun.mirror.declaration.TypeDeclaration;<br />import com.sun.mirror.util.DeclarationVisitors;<br />import com.sun.mirror.util.DeclarationVisitor;<br /><br />/**<br /> * 定义Review annotation的Processor<br /> * @author cleverpig<br /> *<br /> */<br />public class ReviewProcessor implements AnnotationProcessor{<br />        //Processor所工作的环境<br />        AnnotationProcessorEnvironment env=null;<br />        <br />        /**<br />         * 构造方法<br />         * @param env 传入processor环境<br />         */<br />        public ReviewProcessor(AnnotationProcessorEnvironment env){<br />                this.env=env;<br />        }<br />        <br />        /**<br />         * 处理方法：查询processor环境中的类型声明，<br />         */<br />        public void process(){<br />                //查询processor环境中的类型声明<br />                for(TypeDeclaration type:env.getSpecifiedTypeDeclarations()){<br />                        //返回对类进行扫描、访问其声明时使用的DeclarationVisitor，<br />                        //传入参数：new ReviewDeclarationVisitor()，为扫描开始前进行的对类声明的处理<br />                        //        DeclarationVisitors.NO_OP，表示在扫描完成时进行的对类声明不做任何处理<br />                        DeclarationVisitor visitor=DeclarationVisitors.getDeclarationScanner(<br />                                        new ReviewDeclarationVisitor(),DeclarationVisitors.NO_OP);<br />                        //应用DeclarationVisitor到类型<br />                        type.accept(visitor);<br />                }<br />        }<br />}<br /></pre><br /><br /><span style="COLOR: green">E．ReviewDeclarationVisitor类：</span><br /><b>清单10：</b><br /><pre class="overflow"><br />package com.bjinfotech.practice.annotation.apt;<br /><br />import com.sun.mirror.util.*;<br />import com.sun.mirror.declaration.*;<br /><br />/**<br /> * 定义Review annotation声明访问者<br /> * @author cleverpig<br /> *<br /> */<br />public class ReviewDeclarationVisitor extends SimpleDeclarationVisitor{<br />        /**<br />         * 定义访问类声明的方法：打印类声明的全名<br />         * @param cd 类声明对象<br />         */<br />        public void visitClassDeclaration(ClassDeclaration cd){<br />                System.out.println("获取Class声明:"+cd.getQualifiedName());<br />        }<br />        <br />        public void visitAnnotationTypeDeclaration(AnnotationTypeDeclaration atd){<br />                System.out.println("获取Annotation类型声明:"+atd.getSimpleName());<br />        }<br />        <br />        public void visitAnnotationTypeElementDeclaration(AnnotationTypeElementDeclaration aed){<br />                System.out.println("获取Annotation类型元素声明:"+aed.getSimpleName());<br />        }<br />}<br /></pre><br /><br /><span style="COLOR: green">F．runapt.bat文件内容如下：</span><br /><b>清单11：</b><br /><pre class="overflow"><br />E:<br />rem 项目根目录<br />set PROJECT_ROOT=E:\eclipse3.1RC3\workspace\tigerFeaturePractice<br />rem 包目录路径<br />set PACKAGEPATH=com\bjinfotech\practice\annotation\apt<br />rem 运行根路径<br />set RUN_ROOT=%PROJECT_ROOT%\build<br />rem 源文件所在目录路径<br />set SRC_ROOT=%PROJECT_ROOT%\test<br />rem 设置Classpath<br />set CLASSPATH=.;%JAVA_HOME%;%JAVA_HOME%/lib/tools.jar;%RUN_ROOT%<br /><br />cd %SRC_ROOT%\%PACKAGEPATH%<br />apt -nocompile -factory com.bjinfotech.practice.annotation.apt.ReviewProcessorFactory  ./*.java<br /></pre><br /><br /><span style="COLOR: blue">四、参考资源：</span><br /><a href="http://java.sun.com/j2se/1.5.0/docs/guide/apt/GettingStarted.html" target="_new"><font color="#002c99">http://java.sun.com/j2se/1.5.0/docs/guide/apt/GettingStarted.html</font></a><br />作者的Blog:<a href="http://blog.matrix.org.cn/page/cleverpig" target="_new"><font color="#002c99">http://blog.matrix.org.cn/page/cleverpig</font></a><br /><br /><br /><span style="COLOR: blue">五、源代码下载：</span><br /><div id="download"><a href="http://www.matrix.org.cn/resource/upload/forum/2005_12_21_001420_nPNcNUHcHB.rar"><font color="#002c99">Download File</font></a></div><img src ="http://www.blogjava.net/joaquin25/aggbug/197456.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/joaquin25/" target="_blank">joaquin25</a> 2008-04-30 10:36 <a href="http://www.blogjava.net/joaquin25/articles/197456.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java Annotation手册</title><link>http://www.blogjava.net/joaquin25/articles/197455.html</link><dc:creator>joaquin25</dc:creator><author>joaquin25</author><pubDate>Wed, 30 Apr 2008 02:34:00 GMT</pubDate><guid>http://www.blogjava.net/joaquin25/articles/197455.html</guid><wfw:comment>http://www.blogjava.net/joaquin25/comments/197455.html</wfw:comment><comments>http://www.blogjava.net/joaquin25/articles/197455.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/joaquin25/comments/commentRss/197455.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/joaquin25/services/trackbacks/197455.html</trackback:ping><description><![CDATA[
		<center>
				<span style="FONT-SIZE: 20px">
						<b>Java Annotation手册</b>
				</span>
		</center>
		<br />
		<center>作者：<a href="http://blog.matrix.org.cn/page/cleverpig" target="_new">cleverpig</a></center>
		<br />
		<br />
		<br />
		<br />
		<br />
		<span style="COLOR: red">版权声明：本文可以自由转载，转载时请务必以超链接形式标明文章原始出处和作者信息及本声明</span>
		<br />作者:cleverpig(作者的Blog:<a href="http://blog.matrix.org.cn/page/cleverpig" target="_new">http://blog.matrix.org.cn/page/cleverpig</a>)<br />原文:<a href="http://www.matrix.org.cn/resource/article/44/44055_Java+Annotation+Reflect.html" target="_new">http://www.matrix.org.cn/resource/article/44/44055_Java+Annotation+Reflect.html</a><br />关键字:java,annotation,reflect<br /><br /><span style="COLOR: blue">前言：</span><br />在上篇文章<a href="http://www.matrix.org.cn/resource/article/44/44048_Java+Annotation.html" target="_new">《Java Annotation入门》</a>中概要性的介绍了Annotation的定义、使用，范围涵盖较广，但是深度不够。所以作者在《Java Annotation入门》后，继续整理了Annotation的概念和知识点，与喜欢research的朋友们共享。<br /><br /><span style="COLOR: red">阅读提示：文中提到的程序成员或者程序元素是一个概念，指组成程序代码的单元：如类、方法、成员变量。</span><br /><br /><span style="COLOR: blue">一、Annotation究竟是什么？</span><br /><br />Annotation提供了一条与程序元素关联任何信息或者任何元数据（metadata）的途径。从某些方面看，annotation就像修饰符一样被使用，并应用于包、类型、构造方法、方法、成员变量、参数、本地变量的声明中。这些信息被存储在annotation的“name=value”结构对中。annotation类型是一种接口，能够通过java反射API的方式提供对其信息的访问。<br /><br />annotation能被用来为某个程序元素（类、方法、成员变量等）关联任何的信息。需要注意的是，这里存在着一个基本的潜规则：annotaion不能影响程序代码的执行，无论增加、删除annotation，代码都始终如一的执行。另外，尽管一些annotation通过java的反射api方法在运行时被访问，而java语言解释器在工作时忽略了这些annotation。正是由于java虚拟机忽略了annotation，导致了annotation类型在代码中是“不起作用”的；只有通过某种配套的工具才会对annotation类型中的信息进行访问和处理。本文中将涵盖标准的annotation和meta-annotation类型，陪伴这些annotation类型的工具是java编译器（当然要以某种特殊的方式处理它们）。<br /><br />由于上述原因，annotation在使用时十分简便。一个本地变量可以被一个以NonNull命名的annotation类型所标注，来作为对这个本地变量不能被赋予null值的断言。而我们可以编写与之配套的一个annotation代码分析工具，使用它来对具有前面变量的代码进行解析，并且尝试验证这个断言。当然这些代码并不必自己编写。在JDK安装后，在JDK/bin目录中可以找到名为“apt”的工具，它提供了处理annotation的框架：它启动后扫描源代码中的annotation，并调用我们定义好的annotation处理器完成我们所要完成的工作（比如验证前面例子中的断言）。说到这里，annotation的强大功能似乎可以替代XDoclet这类的工具了，随着我们的深入，大家会更加坚信这一点。<br />注：详细描述请参看jsr250规范：<br /><a href="http://www.jcp.org/aboutJava/communityprocess/pfd/jsr250/" target="_new">http://www.jcp.org/aboutJava/communityprocess/pfd/jsr250/</a><br /><br /><span style="COLOR: blue">二、Annotation的定义：</span><br /><br />这段文字开始介绍annotation相关技术。在此大家将看到java5.0的标准annotation类型，这种标准类型就是前文中所说的“内建”类型，它们可以直接被javac支持。可喜的是，在java6.0beta版中的javac已经加入了对自定义annotation的支持。<br /><br /><span style="COLOR: blue">1。Annotation的概念和语法：</span><br /><br />首先，关键的概念是理解annotation是与一个程序元素相关联信息或者元数据的标注。它从不影响java程序的执行，但是对例如编译器警告或者像文档生成器等辅助工具产生影响。<br /><br />下面是常用的annotation列表，我们应该注意在annotation和annotation类型之间的不同：<br /><br /><span style="COLOR: green">A.annotation：</span><br />annotation使用了在java5.0所带来的新语法，它的行为十分类似public、final这样的修饰符。每个annotation具有一个名字和成员个数&gt;=0。每个annotation的成员具有被称为name=value对的名字和值（就像javabean一样），name=value装载了annotation的信息。<br /><br /><span style="COLOR: green">B.annotation类型：</span><br />annotation类型定义了annotation的名字、类型、成员默认值。一个annotation类型可以说是一个特殊的java接口，它的成员变量是受限制的，而声明annotation类型时需要使用新语法。当我们通过java反射api访问annotation时，返回值将是一个实现了该annotation类型接口的对象，通过访问这个对象我们能方便的访问到其annotation成员。后面的章节将提到在java5.0的java.lang包里包含的3个标准annotation类型。<br /><br /><span style="COLOR: green">C.annotation成员：</span><br />annotation的成员在annotation类型中以无参数的方法的形式被声明。其方法名和返回值定义了该成员的名字和类型。在此有一个特定的默认语法：允许声明任何annotation成员的默认值：一个annotation可以将name=value对作为没有定义默认值的annotation成员的值，当然也可以使用name=value对来覆盖其它成员默认值。这一点有些近似类的继承特性，父类的构造函数可以作为子类的默认构造函数，但是也可以被子类覆盖。<br /><br /><span style="COLOR: green">D.marker annotation类型：</span><br />一个没有成员定义的annotation类型被称为marker annotation。这种annotation类型仅使用自身的存在与否来为我们提供信息。如后面要说的Override。<br /><br /><span style="COLOR: green">E.meta-annotation：</span><br />meta-annotation也称为元annotation，它是被用来声明annotation类型的annotation。Java5.0提供了一些标准的元-annotation类型。下面介绍的target、retention就是meta-annotation。<br /><br /><span style="COLOR: green">F.target：</span><br />annotation的target是一个被标注的程序元素。target说明了annotation所修饰的对象范围：annotation可被用于packages、types（类、接口、枚举、annotation类型）、类型成员（方法、构造方法、成员变量、枚举值）、方法参数和本地变量（如循环变量、catch参数）。在annotation类型的声明中使用了target可更加明晰其修饰的目标。<br /><br /><span style="COLOR: green">G.retention：</span><br />annotation的retention定义了该annotation被保留的时间长短：某些annotation仅出现在源代码中，而被编译器丢弃；而另一些却被编译在class文件中；编译在class文件中的annotation可能会被虚拟机忽略，而另一些在class被装载时将被读取（请注意并不影响class的执行，因为annotation与class在使用上是被分离的）。使用这个meta-annotation可以对annotation的“生命周期”限制。<br /><br /><span style="COLOR: green">H.metadata：</span><br />由于metadata被广泛使用于各种计算机开发过程中，所以当我们在这里谈论的metadata即元数据通常指被annotation装载的信息或者annotation本身。<br /><br /><span style="COLOR: blue">2。使用标准Annotation：</span><br />java5.0在java.lang包中定义了3种标准的annotation类型：<br /><br /><span style="COLOR: green">A.Override：</span><br />java.lang.Override是一个marker annotation类型，它被用作标注方法。它说明了被标注的方法重载了父类的方法，起到了断言的作用。如果我们使用了这种annotation在一个没有覆盖父类方法的方法时，java编译器将以一个编译错误来警示。<br />这个annotaton常常在我们试图覆盖父类方法而确又写错了方法名时发挥威力。<br /><br />使用方法极其简单：在使用此annotation时只要在被修饰的方法前面加上@Override。<br />下面的代码是一个使用@Override修饰一个企图重载父类的toString方法，而又存在拼写错误的sample：<br /><b>清单1：</b><br /><pre class="overflow"><br />@Override<br />public String toSting() {   // 注意方法名拼写错了<br />    return "[" + super.toString() + "]";<br />}<br /></pre><br /><br /><span style="COLOR: green">B.Deprecated：</span><br />同样Deprecated也是一个marker annotation。当一个类型或者类型成员使用@Deprecated修饰的话，编译器将不鼓励使用这个被标注的程序元素。而且这种修饰具有一定的“延续性”：如果我们在代码中通过继承或者覆盖的方式使用了这个过时的类型或者成员，虽然继承或者覆盖后的类型或者成员并不是被声明为@Deprecated，但编译器仍然要报警。<br />值得注意，@Deprecated这个annotation类型和javadoc中的@deprecated这个tag是有区别的：前者是java编译器识别的，而后者是被javadoc工具所识别用来生成文档（包含程序成员为什么已经过时、它应当如何被禁止或者替代的描述）。<br />在java5.0，java编译器仍然象其从前版本那样寻找@deprecated这个javadoc tag，并使用它们产生警告信息。但是这种状况将在后续版本中改变，我们应在现在就开始使用@Deprecated来修饰过时的方法而不是@deprecated javadoc tag。<br /><b>清单2：</b><br /><pre class="overflow"><br />下面是一段使用@Deprecated的代码：<br />/**<br /> * 这里是javadoc的@deprecated声明.<br /> * @deprecated No one has players for this format any more.  Use VHS instead.<br /> */<br />@Deprecated public class Betamax { ... }<br /></pre><br /><br /><span style="COLOR: green">C.SuppressWarnings：</span><br />@SuppressWarnings被用于有选择的关闭编译器对类、方法、成员变量、变量初始化的警告。在java5.0，sun提供的javac编译器为我们提供了-Xlint选项来使编译器对合法的程序代码提出警告，此种警告从某种程度上代表了程序错误。例如当我们使用一个generic collection类而又没有提供它的类型时，编译器将提示出"unchecked warning"的警告。<br /><br />通常当这种情况发生时，我们就需要查找引起警告的代码。如果它真的表示错误，我们就需要纠正它。例如如果警告信息表明我们代码中的switch语句没有覆盖所有可能的case，那么我们就应增加一个默认的case来避免这种警告。<br />相仿，有时我们无法避免这种警告，例如，我们使用必须和非generic的旧代码交互的generic collection类时，我们不能避免这个unchecked warning。此时@SuppressWarning就要派上用场了，在调用的方法前增加@SuppressWarnings修饰，告诉编译器停止对此方法的警告。<br />SuppressWarning不是一个marker annotation。它有一个类型为String[]的成员，这个成员的值为被禁止的警告名。对于javac编译器来讲，被-Xlint选项有效的警告名也同样对@SuppressWarings有效，同时编译器忽略掉无法识别的警告名。<br /><br />annotation语法允许在annotation名后跟括号，括号中是使用逗号分割的name=value对用于为annotation的成员赋值：<br /><b>清单3：</b><br /><pre class="overflow"><br />@SuppressWarnings(value={"unchecked","fallthrough"})<br />public void lintTrap() { /* sloppy method body omitted */ }<br /></pre><br /><br />在这个例子中SuppressWarnings annotation类型只定义了一个单一的成员，所以只有一个简单的value={...}作为name=value对。又由于成员值是一个数组，故使用大括号来声明数组值。<br /><br />注意：我们可以在下面的情况中缩写annotation：当annotation只有单一成员，并成员命名为"value="。这时可以省去"value="。比如将上面的SuppressWarnings annotation进行缩写：<br /><b>清单4：</b><br /><pre class="overflow"><br />@SuppressWarnings({"unchecked","fallthrough"})<br /></pre><br />如果SuppressWarnings所声明的被禁止警告个数为一个时，可以省去大括号：<br /><pre class="overflow"><br />@SuppressWarnings("unchecked")<br /></pre><br /><br /><span style="COLOR: blue">3。Annotation语法：</span><br /><br />在上一个章节中，我们看到书写marker annotation和单一成员annotation的语法。下面本人来介绍一下完整的语法：<br /><br />annotation由“@+annotation类型名称+(..逗号分割的name-value对...)”组成。其中成员可以按照任何的顺序。如果annotation类型定义了某个成员的默认值，则这个成员可以被省略。成员值必须为编译时常量、内嵌的annotation或者数组。<br /><br />下面我们将定义一个annotation类型名为Reviews，它有一个由@Review annotation数组构成的成员。这个@Review annotation类型有三个成员："reviewer"是一个字符串，"comment" 是一个具有默认值的可选的字符串，"grade"是一个Review.Grade枚举类型值。<br /><b>清单5：</b><br /><pre class="overflow"><br />@Reviews({  // Single-value annotation, so "value=" is omitted here<br />    @Review(grade=Review.Grade.EXCELLENT,<br />            reviewer="df"),<br />    @Review(grade=Review.Grade.UNSATISFACTORY,<br />            reviewer="eg",<br />            comment="This method needs an @Override annotation")<br />})<br /></pre><br />annotation语法的另一个重要规则是没有程序成员可以有多于一个的同一annotation实例。例如在一个类中简单的放置多个@Review annotation。这也是在上面代码中定义@Reviews annotation类型数组的原因。<br /><br /><span style="COLOR: blue">4。Annotation成员类型和值：</span><br /><br />annotation成员必须是非空的编译时常量表达式。可用的成员类型为：primitive类型、, String, Class, enumerated类型, annotation类型, 和前面类型的数组。<br /><br />下面我们定义了一个名为UncheckedExceptions 的annotation类型，它的成员是一个扩展了RuntimeException类的类数组。<br /><b>清单6：</b><br /><pre class="overflow"><br />@UncheckedExceptions({<br />    IllegalArgumentException.class, StringIndexOutOfBoundsException.class<br />})<br /></pre><br /><br /><span style="COLOR: blue">5。Annotation的目标：</span><br /><br />annotation通常被放在类型定义和成员定义的前面。然而它也出现在package、方法参数、本地变量的前面。下面，我们来讨论一下这些不大常用的写法：<br /><br />package annotation出现在package声明的前面。<br />下面的例子package-info.java中不包含任何的公共类型定义，却包含一个可选的javadoc注释。<br /><b>清单7：</b><br /><pre class="overflow"><br />/**<br /> * This package holds my custom annotation types.<br /> */<br />@com.davidflanagan.annotations.Author("David Flanagan")<br />package com.davidflanagan.annotations;<br /></pre><br />当package-info.java文件被编译时，它将产生名为包含annotation（特殊的接口）声明的package-info.class的类。这个接口没有成员，它的名字package-info不是一个合法的java标识，所以它不能用在java源代码中。这个接口的存在只是简单的被看作一个为package annotation准备的占位符。<br /><br />用于修饰方法参数、catch参数、本地变量的annotation只是简单的出现在这些程序成员的修饰符位置。java类文件格式没有为本地变量或者catch参数存储annotation作准备，所以这些annotation总是保留在源代码级别（source retention）；方法参数annotation能够保存在类文件中，也可以在保留到运行时。<br /><br />最后，请注意，枚举类型定义中不允许任何的修饰符修饰其枚举值。<br /><br /><span style="COLOR: blue">6。Annotation和默认值：</span><br />在Annotation中，没有默认值的成员必须有一个成员值。而如何理解默认值是如何被处理就是一个很重要的细节：annotation类型所定义的成员默认值被存储在class文件中，不被编译到annotation里面。如果我们修改一个annotation类型使其成员的默认值发生了改变，这个改变对于所有此类型的annotation中没有明确提供成员值的成员产生影响（即修改了该成员的成员值）。即使在annotation类型使其成员的默认值被改变后annotation从没被重新编译过，该类型的annotation(改变前已经被编译的)也受到影响。<br /><br /><span style="COLOR: blue">三、Annotation工作原理：</span><br /><br /><span style="COLOR: blue">Annotation与反射</span><br />在java5.0中Java.lang.reflect提供的反射API被扩充了读取运行时annotation的能力。让我们回顾一下前面所讲的：一个annotation类型被定义为runtime retention后，它才是在运行时可见，当class文件被装载时被保存在class文件中的annotation才会被虚拟机读取。那么reflect是如何帮助我们访问class中的annotation呢？<br /><br />下文将在java.lang.reflect用于annotation的新特性，其中java.lang.reflect.AnnotatedElement是重要的接口，它代表了提供查询annotation能力的程序成员。这个接口被java.lang.Package、java.lang.Class实现，并间接地被Method类、Constructor类、java.lang.reflect的Field类实现。而annotation中的方法参数可以通过Method类、Constructor类的getParameterAnnotations()方法获得。<br /><br />下面的代码使用了AnnotatedElement类的isAnnotationPresent()方法判断某个方法是否具有@Unstable annotation，从而断言此方法是否稳定：<br /><b>清单8：</b><br /><pre class="overflow"><br />import java.lang.reflect.*;<br /><br />Class c = WhizzBangClass.class;                           <br />Method m = c.getMethod("whizzy", int.class, int.class);  <br />boolean unstable = m.isAnnotationPresent(Unstable.class);<br /></pre><br />isAnnotationPresent()方法对于检查marker annotation是十分有用的，因为marker annotation没有成员变量，所以我们只要知道class的方法是否使用了annotation修饰就可以了。而当处理具有成员的annotation时，我们通过使用getAnnotation()方法来获得annotation的成员信息（成员名称、成员值）。这里我们看到了一套优美的java annotation系统：如果annotation存在，那么实现了相应的annotation类型接口的对象将被getAnnotation()方法返回，接着调用定义在annotation类型中的成员方法可以方便地获得任何成员值。<br /><br />回想一下，前面介绍的@Reviews annotation，如果这个annotation类型被声明为runtime retention的话，我们通过下面的代码来访问@Reviews annotation的成员值：<br /><b>清单9：</b><br /><pre class="overflow"><br />AnnotatedElement target = WhizzBangClass.class; //获得被查询的AnnotatedElement<br />// 查询AnnotatedElement的@Reviews annotation信息<br />Reviews annotation = target.getAnnotation(Reviews.class);<br />// 因为@Reviews annotation类型的成员为@Review annotation类型的数组，<br />// 所以下面声明了Review[] reviews保存@Reviews annotation类型的value成员值。<br />Review[] reviews = annotation.value();<br />// 查询每个@Review annotation的成员信息<br />for(Review r : reviews) {<br />    Review.Grade grade = r.grade();<br />    String reviewer = r.reviewer();<br />    String comment = r.comment();<br />    System.out.printf("%s assigned a grade of %s and comment '%s'%n",<br />                      reviewer, grade, comment);<br />}<br /></pre><br /><br /><span style="COLOR: blue">四、如何自定义Annotation？</span><br /><br /><span style="COLOR: blue">1．详解annotation与接口的异同：</span><br />因为annotation类型是一个非凡的接口，所以两者之间存在着某些差异：<br /><br /><span style="COLOR: green">A.Annotation类型使用关键字@interface而不是interface。</span><br />这个关键字声明隐含了一个信息：它是继承了java.lang.annotation.Annotation接口，并非声明了一个interface。<br /><br /><span style="COLOR: green">B.Annotation类型、方法定义是独特的、受限制的。</span><br />Annotation类型的方法必须声明为无参数、无异常抛出的。这些方法定义了annotation的成员：方法名成为了成员名，而方法返回值成为了成员的类型。而方法返回值类型必须为primitive类型、Class类型、枚举类型、annotation类型或者由前面类型之一作为元素的一维数组。方法的后面可以使用default和一个默认数值来声明成员的默认值，null不能作为成员默认值，这与我们在非annotation类型中定义方法有很大不同。<br />Annotation类型和它的方法不能使用annotation类型的参数、成员不能是generic。只有返回值类型是Class的方法可以在annotation类型中使用generic，因为此方法能够用类转换将各种类型转换为Class。<br /><br /><span style="COLOR: green">C.Annotation类型又与接口有着近似之处。</span><br />它们可以定义常量、静态成员类型（比如枚举类型定义）。Annotation类型也可以如接口一般被实现或者继承。<br /><br /><span style="COLOR: blue">2．实例：</span><br />下面，我们将看到如何定义annotation类型的example。它展示了annotation类型声明以及@interface与interface之间的不同：<br /><b>清单10：</b><br /><pre class="overflow"><br />package com.davidflanagan.annotations;<br />import java.lang.annotation.*;<br /><br />/**<br /> * 使用annotation来描述那些被标注的成员是不稳定的，需要更改<br />*/<br />@Retention(RetentionPolicy.RUNTIME)<br />public @interface Unstable {}<br /></pre><br /><br />下面的另一个example只定义了一个成员。并通过将这个成员命名为value，使我们可以方便的使用这种annotation的快捷声明方式：<br /><b>清单11：</b><br /><pre class="overflow"><br />/**<br /> * 使用Author这个annotation定义在程序中指出代码的作者<br /> */<br />public @interface Author {<br />    /** 返回作者名 */<br />    String value();<br />}<br /></pre><br /><br />以下的example更加复杂。Reviews annotation类型只有一个成员，但是这个成员的类型是复杂的：由Review annotation组成的数组。Review annotation类型有3个成员：枚举类型成员grade、表示Review名称的字符串类型成员Reviewer、具有默认值的字符串类型成员Comment。<br /><b>清单12：</b><br /><pre class="overflow"><br />import java.lang.annotation.*;<br />        <br />/**<br /> * Reviews annotation类型只有一个成员，<br /> * 但是这个成员的类型是复杂的：由Review annotation组成的数组<br /> */<br />@Retention(RetentionPolicy.RUNTIME)<br />public @interface Reviews {<br />    Review[] value();<br />}<br /><br />/**<br />* Review annotation类型有3个成员： <br />* 枚举类型成员grade、<br />  * 表示Review名称的字符串类型成员Reviewer、<br />  * 具有默认值的字符串类型成员Comment。<br /> */<br />public @interface Review {<br />    // 内嵌的枚举类型<br />    public static enum Grade { EXCELLENT, SATISFACTORY, UNSATISFACTORY };<br /><br />    // 下面的方法定义了annotation的成员<br />    Grade grade();                <br />    String reviewer();          <br />    String comment() default "";  <br />}<br /></pre><br /><br />最后，我们来定义一个annotation方法用于罗列出类运行中所有的unchecked异常（上文已经提到这种情况不一定是错误）。这个annotation类型将一个数组作为了唯一的成员。数组中的每个元素都是异常类。为了加强对未检查的异常（此类异常都是在运行时抛出）进行报告，我们可以在代码中对异常的类型进行限制：<br /><b>清单13：</b><br /><pre class="overflow"><br />public @interface UncheckedExceptions {<br />    Class&lt;? extends RuntimeException&gt;[] value();<br />}<br /></pre><br /><br /><span style="COLOR: blue">五、Meta-Annotation</span><br /><br />Annotation类型可以被它们自己所标注。Java5.0定义了4个标准的meta-annotation类型，它们被用来提供对其它annotation类型作说明。这些类型和它们所支持的类在java.lang.annotation包中可以找到。如果需要更详细的信息可以参考jdk5.0手册。<br /><br /><span style="COLOR: blue">1．再谈Target</span><br />作为meta-annotation类型的Target,它描述了annotation所修饰的程序成员的类型。当一个annotation类型没有Target时，它将被作为普通的annotation看待。当将它修饰一个特定的程序成员时，它将发挥其应用的作用，例如：Override用于修饰方法时，增加了@Target这个meta-annotation就使编译器对annotation作检查，从而去掉修饰错误类型的Override。<br /><br />Target meta-annotation类型有唯一的value作为成员。这个成员的类型是java.lang.annotation.ElementType[]类型的，ElementType类型是可以被标注的程序成员的枚举类型。<br /><br /><span style="COLOR: blue">2．Retention的用法</span><br />我们在文章的开头曾经提到过Retention，但是没有详细讲解。Retention描述了annotation是否被编译器丢弃或者保留在class文件；如果保留在class文件中，是否在class文件被装载时被虚拟机读取。默认情况下，annotation被保存在class文件中，但在运行时并不能被反射访问。Retention具有三个取值：source、class、runtime，这些取值来自java.lang.annotation.RetentionPolicy的枚举类型值。<br /><br />Retention meta-annotation类型有唯一的value作为成员，它的取值来自java.lang.annotation.RetentionPolicy的枚举类型值。<br /><br /><span style="COLOR: blue">3．Documented</span><br />Documented是一个meta-annotation类型，用于描述其它类型的annotation应该被作为被标注的程序成员的公共API，因此可以被例如javadoc此类的工具文档化。<br /><br />Documented是一个marker annotation，没有成员。<br /><br /><span style="COLOR: blue">4．Inherited</span><br />@Inherited meta-annotation也是一个marker annotation，它阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class，则这个annotation将被用于该class的子类。<br /><br />注意：@Inherited annotation类型是被标注过的class的子类所继承。类并不从它所实现的接口继承annotation，方法并不从它所重载的方法继承annotation。<br /><br />值得思考的是，当@Inherited annotation类型标注的annotation的Retention是RetentionPolicy.RUNTIME，则反射API增强了这种继承性。如果我们使用java.lang.reflect去查询一个@Inherited annotation类型的annotation时，反射代码检查将展开工作：检查class和其父类，直到发现指定的annotation类型被发现，或者到达类继承结构的顶层。<br /><br /><span style="COLOR: blue">六、总结：</span><br /><br />本文几乎覆盖了所有的Annotation的概念和知识点，从annotation的定义、语法到工作原理、如何自定义annotation，直至meta-annotation。其中也具有一些配套的代码片断可参考，虽然不是很多，但是可谓言简意赅、着其重点，本人认为用好annotation的关键还在于使用。希望本手册能够帮助大家用好annotation，这也是本人的最大快乐。<img src ="http://www.blogjava.net/joaquin25/aggbug/197455.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/joaquin25/" target="_blank">joaquin25</a> 2008-04-30 10:34 <a href="http://www.blogjava.net/joaquin25/articles/197455.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java Annotation入门</title><link>http://www.blogjava.net/joaquin25/articles/197341.html</link><dc:creator>joaquin25</dc:creator><author>joaquin25</author><pubDate>Tue, 29 Apr 2008 09:55:00 GMT</pubDate><guid>http://www.blogjava.net/joaquin25/articles/197341.html</guid><wfw:comment>http://www.blogjava.net/joaquin25/comments/197341.html</wfw:comment><comments>http://www.blogjava.net/joaquin25/articles/197341.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/joaquin25/comments/commentRss/197341.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/joaquin25/services/trackbacks/197341.html</trackback:ping><description><![CDATA[
		<span style="FONT-SIZE: 20px">
				<strong>
						<div align="center">
								<br />Java Annotation入门</div>
				</strong>
		</span>
		<br />
		<center>作者：<a href="http://blog.matrix.org.cn/page/cleverpig" target="_new"><font color="#000080">cleverpig</font></a></center>
		<br />
		<br />
		<br />
		<br />
		<br />
		<span style="COLOR: red">版权声明：本文可以自由转载，转载时请务必以超链接形式标明文章原始出处和作者信息及本声明</span>
		<br />作者:cleverpig(作者的Blog:<a href="http://blog.matrix.org.cn/page/cleverpig" target="_new"><font color="#000080">http://blog.matrix.org.cn/page/cleverpig</font></a>)<br />原文:[http://www.matrix.org.cn/resource/article/44/44048_Java+Annotation.html]http://www.matrix.org.cn/resource/article/44/44048_Java+Annotation.html[/url]<br />关键字:Java,annotation,标注<br /><br /><br /><span style="COLOR: blue">摘要：</span><br />本文针对java初学者或者annotation初次使用者全面地说明了annotation的使用方法、定义方式、分类。初学者可以通过以上的说明制作简单的annotation程序，但是对于一些高级的annotation应用（例如使用自定义annotation生成javabean映射xml文件）还需要进一步的研究和探讨。涉及到深入annotation的内容，作者将在后文《Java Annotation高级应用》中谈到。<br /><br />同时，annotation运行存在两种方式：运行时、编译时。上文中讨论的都是在运行时的annotation应用，但在编译时的annotation应用还没有涉及，<br /><br /><span style="COLOR: blue">一、为什么使用Annotation：</span><br /><br />在JAVA应用中，我们常遇到一些需要使用模版代码。例如，为了编写一个JAX-RPC web service，我们必须提供一对接口和实现作为模版代码。如果使用annotation对远程访问的方法代码进行修饰的话，这个模版就能够使用工具自动生成。<br />另外，一些API需要使用与程序代码同时维护的附属文件。例如，JavaBeans需要一个BeanInfo Class与一个Bean同时使用/维护，而EJB则同样需要一个部署描述符。此时在程序中使用annotation来维护这些附属文件的信息将十分便利而且减少了错误。<br /><br /><span style="COLOR: blue">二、Annotation工作方式：</span><br /><br />在5.0 版之前的Java平台已经具有了一些ad hoc annotation机制。比如，使用transient修饰符来标识一个成员变量在序列化子系统中应被忽略。而@deprecated这个 javadoc tag也是一个ad hoc annotation用来说明一个方法已过时。从Java5.0版发布以来，5.0平台提供了一个正式的annotation功能：允许开发者定义、使用自己的annoatation类型。此功能由一个定义annotation类型的语法和一个描述annotation声明的语法，读取annotaion 的API，一个使用annotation修饰的class文件，一个annotation处理工具（apt）组成。<br />annotation并不直接影响代码语义，但是它能够工作的方式被看作类似程序的工具或者类库，它会反过来对正在运行的程序语义有所影响。annotation可以从源文件、class文件或者以在运行时反射的多种方式被读取。<br />当然annotation在某种程度上使javadoc tag更加完整。一般情况下，如果这个标记对java文档产生影响或者用于生成java文档的话，它应该作为一个javadoc tag；否则将作为一个annotation。<br /><br /><span style="COLOR: blue">三、Annotation使用方法：</span><br /><br /><strong>1。类型声明方式：</strong><br />通常，应用程序并不是必须定义annotation类型，但是定义annotation类型并非难事。Annotation类型声明于一般的接口声明极为类似，区别只在于它在interface关键字前面使用“@”符号。<br />annotation 类型的每个方法声明定义了一个annotation类型成员，但方法声明不必有参数或者异常声明；方法返回值的类型被限制在以下的范围： primitives、String、Class、enums、annotation和前面类型的数组；方法可以有默认值。<br /><br />下面是一个简单的annotation类型声明：<br /><strong>清单1:</strong><br /><pre class="overflow" title="pre code"><br />    /**<br />     * Describes the Request-For-Enhancement(RFE) that led<br />     * to the presence of the annotated API element.<br />     */<br />    public @interface RequestForEnhancement {<br />        int    id();<br />        String synopsis();<br />        String engineer() default "[unassigned]"; <br />        String date();    default "[unimplemented]"; <br />    }<br /></pre><br />代码中只定义了一个annotation类型RequestForEnhancement。<br /><br /><strong>2。修饰方法的annotation声明方式：</strong><br />annotation 是一种修饰符，能够如其它修饰符（如public、static、final）一般使用。习惯用法是annotaions用在其它的修饰符前面。 annotations由“@+annotation类型+带有括号的成员-值列表”组成。这些成员的值必须是编译时常量（即在运行时不变）。<br /><br />A：下面是一个使用了RequestForEnhancement annotation的方法声明：<br /><strong>清单2:</strong><br /><pre class="overflow" title="pre code"><br />    @RequestForEnhancement(<br />        id       = 2868724,<br />        synopsis = "Enable time-travel",<br />        engineer = "Mr. Peabody",<br />        date     = "4/1/3007"<br />    )<br />    public static void travelThroughTime(Date destination) { ... }<br /></pre><br /><br />B：当声明一个没有成员的annotation类型声明时，可使用以下方式：<br /><strong>清单3:</strong><br /><pre class="overflow" title="pre code"><br />    /**<br />     * Indicates that the specification of the annotated API element<br />     * is preliminary and subject to change.<br />     */<br />    public @interface Preliminary { }<br /></pre><br /><br />作为上面没有成员的annotation类型声明的简写方式：<br /><strong>清单4:</strong><br /><pre class="overflow" title="pre code"><br />    @Preliminary public class TimeTravel { ... }<br /></pre><br /><br />C：如果在annotations中只有唯一一个成员，则该成员应命名为value：<br /><strong>清单5:</strong><br /><pre class="overflow" title="pre code"><br />    /**<br />     * Associates a copyright notice with the annotated API element.<br />     */<br />    public @interface Copyright {<br />        String value();<br />    }<br /></pre><br /><br />更为方便的是对于具有唯一成员且成员名为value的annotation（如上文），在其使用时可以忽略掉成员名和赋值号（=）：<br /><strong>清单6:</strong><br /><pre class="overflow" title="pre code"><br />    @Copyright("2002 Yoyodyne Propulsion Systems")<br />    public class OscillationOverthruster { ... }<br /></pre><br /><br /><strong>3。一个使用实例：</strong><br />结合上面所讲的，我们在这里建立一个简单的基于annotation测试框架。首先我们需要一个annotation类型来表示某个方法是一个应该被测试工具运行的测试方法。<br /><strong>清单7:</strong><br /><pre class="overflow" title="pre code"><br />    import java.lang.annotation.*;<br /><br />    /**<br />     * Indicates that the annotated method is a test method.<br />     * This annotation should be used only on parameterless static methods.<br />     */<br />    @Retention(RetentionPolicy.RUNTIME)<br />    @Target(ElementType.METHOD)<br />    public @interface Test { }<br /></pre><br /><br />值得注意的是annotaion类型声明是可以标注自己的，这样的annotation被称为“meta-annotations”。<br /><br />在上面的代码中，@Retention(RetentionPolicy.RUNTIME)这个meta-annotation表示了此类型的 annotation将被虚拟机保留使其能够在运行时通过反射被读取。而@Target(ElementType.METHOD)表示此类型的 annotation只能用于修饰方法声明。<br /><br />下面是一个简单的程序，其中部分方法被上面的annotation所标注：<br /><strong>清单8:</strong><br /><pre class="overflow" title="pre code"><br />    public class Foo {<br />        @Test public static void m1() { }<br />        public static void m2() { }<br />        @Test public static void m3() {<br />            throw new RuntimeException("Boom");<br />        }<br />        public static void m4() { }<br />        @Test public static void m5() { }<br />        public static void m6() { }<br />        @Test public static void m7() {<br />            throw new RuntimeException("Crash");<br />        }<br />        public static void m8() { }<br />    }<br /><br />Here is the testing tool:<br /><br />    import java.lang.reflect.*;<br /><br />    public class RunTests {<br />       public static void main(String[] args) throws Exception {<br />          int passed = 0, failed = 0;<br />          for (Method m : Class.forName(args[0]).getMethods()) {<br />             if (m.isAnnotationPresent(Test.class)) {<br />                try {<br />                   m.invoke(null);<br />                   passed++;<br />                } catch (Throwable ex) {<br />                   System.out.printf("Test %s failed: %s %n", m, ex.getCause());<br />                   failed++;<br />                }<br />             }<br />          }<br />          System.out.printf("Passed: %d, Failed %d%n", passed, failed);<br />       }<br />    }<br /></pre><br /><br />这个程序从命令行参数中取出类名，并且遍历此类的所有方法，尝试调用其中被上面的测试annotation类型标注过的方法。在此过程中为了找出哪些方法被 annotation类型标注过，需要使用反射的方式执行此查询。如果在调用方法时抛出异常，此方法被认为已经失败，并打印一个失败报告。最后，打印运行通过/失败的方法数量。<br />下面文字表示了如何运行这个基于annotation的测试工具：<br /><br /><strong>清单9:</strong><br /><pre class="overflow" title="pre code"><br />    $ java RunTests Foo<br />    Test public static void Foo.m3() failed: java.lang.RuntimeException: Boom <br />    Test public static void Foo.m7() failed: java.lang.RuntimeException: Crash <br />    Passed: 2, Failed 2<br /></pre><br /><br /><span style="COLOR: blue">四、Annotation分类：</span><br /><br />根据annotation的使用方法和用途主要分为以下几类：<br /><br /><strong>1。内建Annotation——Java5.0版在java语法中经常用到的内建Annotation：</strong><br />@Deprecated用于修饰已经过时的方法；<br />@Override用于修饰此方法覆盖了父类的方法（而非重载）；<br />@SuppressWarnings用于通知java编译器禁止特定的编译警告。<br /><br />下面代码展示了内建Annotation类型的用法：<br /><strong>清单10:</strong><br /><pre class="overflow" title="pre code"><br />package com.bjinfotech.practice.annotation;<br /><br />/**<br /> * 演示如何使用java5内建的annotation<br /> * 参考资料：<br /> * http://java.sun.com/docs/books/tutorial/java/javaOO/annotations.html<br /> * http://java.sun.com/j2se/1.5.0/docs/guide/language/annotations.html<br /> * http://mindprod.com/jgloss/annotations.html<br /> * @author cleverpig<br /> *<br /> */<br />import java.util.List;<br /><br />public class UsingBuiltInAnnotation {<br />        //食物类<br />        class Food{}<br />        //干草类<br />        class Hay extends Food{}<br />        //动物类<br />        class Animal{<br />                Food getFood(){<br />                        return null;<br />                }<br />                //使用Annotation声明Deprecated方法<br />                @Deprecated<br />                void deprecatedMethod(){<br />                }<br />        }<br />        //马类-继承动物类<br />        class Horse extends Animal{<br />                //使用Annotation声明覆盖方法<br />                @Override<br />                Hay getFood(){<br />                        return new Hay();<br />                }<br />                //使用Annotation声明禁止警告<br />                @SuppressWarnings({"deprecation","unchecked"})<br />                void callDeprecatedMethod(List horseGroup){<br />                        Animal an=new Animal();<br />                        an.deprecatedMethod();<br />                        horseGroup.add(an);<br />                }<br />        }<br />}<br /></pre><br /><br /><strong>2。开发者自定义Annotation：由开发者自定义Annotation类型。</strong><br />下面是一个使用annotation进行方法测试的sample：<br /><br />AnnotationDefineForTestFunction类型定义如下：<br /><strong>清单11:</strong><br /><pre class="overflow" title="pre code"><br />package com.bjinfotech.practice.annotation;<br /><br />import java.lang.annotation.*;<br />/**<br /> * 定义annotation<br /> * @author cleverpig<br /> *<br /> */<br />//加载在VM中，在运行时进行映射<br />@Retention(RetentionPolicy.RUNTIME)<br />//限定此annotation只能标示方法<br />@Target(ElementType.METHOD)<br />public @interface AnnotationDefineForTestFunction{}<br /></pre><br /><br />测试annotation的代码如下：<br /><br /><strong>清单12:</strong><br /><pre class="overflow" title="pre code"><br />package com.bjinfotech.practice.annotation;<br /><br />import java.lang.reflect.*;<br /><br />/**<br /> * 一个实例程序应用前面定义的Annotation：AnnotationDefineForTestFunction<br /> * @author cleverpig<br /> *<br /> */<br />public class UsingAnnotation {<br />        @AnnotationDefineForTestFunction public static void method01(){}<br />        <br />        public static void method02(){}<br />        <br />        @AnnotationDefineForTestFunction public static void method03(){<br />                throw new RuntimeException("method03");<br />        }<br />        <br />        public static void method04(){<br />                throw new RuntimeException("method04");<br />        }<br />        <br />        public static void main(String[] argv) throws Exception{<br />                int passed = 0, failed = 0;<br />                //被检测的类名<br />                String className="com.bjinfotech.practice.annotation.UsingAnnotation";<br />                //逐个检查此类的方法，当其方法使用annotation声明时调用此方法<br />            for (Method m : Class.forName(className).getMethods()) {<br />               if (m.isAnnotationPresent(AnnotationDefineForTestFunction.class)) {<br />                  try {<br />                     m.invoke(null);<br />                     passed++;<br />                  } catch (Throwable ex) {<br />                     System.out.printf("测试 %s 失败: %s %n", m, ex.getCause());<br />                     failed++;<br />                  }<br />               }<br />            }<br />            System.out.printf("测试结果： 通过: %d, 失败： %d%n", passed, failed);<br />        }<br />}<br /></pre><br /><br /><strong>3。使用第三方开发的Annotation类型</strong><br />这也是开发人员所常常用到的一种方式。比如我们在使用Hibernate3.0时就可以利用Annotation生成数据表映射配置文件，而不必使用Xdoclet。<br /><br /><span style="COLOR: blue">五、总结：</span><br /><br />1。前面的文字说明了annotation的使用方法、定义方式、分类。初学者可以通过以上的说明制作简单的annotation程序，但是对于一些高级的 annotation应用（例如使用自定义annotation生成javabean映射xml文件）还需要进一步的研究和探讨。<br /><br />2。同时，annotation运行存在两种方式：运行时、编译时。上文中讨论的都是在运行时的annotation应用，但在编译时的annotation应用还没有涉及，因为编译时的annotation要使用annotation processing tool。<br /><br />涉及以上2方面的深入内容，作者将在后文《Java Annotation高级应用》中谈到。<br /><br /><span style="COLOR: blue">六、参考资源：</span><br />·Matrix-Java开发者社区:<a href="http://www.matrix.org.cn/" target="_new"><font color="#000080">http://www.matrix.org.cn</font></a><br />·<a href="http://java.sun.com/docs/books/tutorial/java/javaOO/annotations.html" target="_new"><font color="#000080">http://java.sun.com/docs/books/tutorial/java/javaOO/annotations.html</font></a><br />·<a href="http://java.sun.com/j2se/1.5.0/docs/guide/apt/GettingStarted.html" target="_new"><font color="#000080">http://java.sun.com/j2se/1.5.0/docs/guide/apt/GettingStarted.html</font></a><br />·<a href="http://www.javaworld.com/javaworld/jw-03-2005/jw-0321-toolbox.html" target="_new"><font color="#000080">http://java.sun.com/j2se/1.5.0/docs/guide/apt/GettingStarted.html</font></a><br />·<a href="http://java.sun.com/j2se/1.5.0/docs/guide/language/annotations.html" target="_new"><font color="#000080">http://java.sun.com/j2se/1.5.0/docs/guide/apt/GettingStarted.html</font></a><br />·作者的Blog:<a href="http://blog.matrix.org.cn/page/cleverpig" target="_new"><font color="#000080">http://blog.matrix.org.cn/page/cleverpig</font></a><img src ="http://www.blogjava.net/joaquin25/aggbug/197341.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/joaquin25/" target="_blank">joaquin25</a> 2008-04-29 17:55 <a href="http://www.blogjava.net/joaquin25/articles/197341.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java中的path，classpath，package和jar的概念</title><link>http://www.blogjava.net/joaquin25/articles/193683.html</link><dc:creator>joaquin25</dc:creator><author>joaquin25</author><pubDate>Thu, 17 Apr 2008 03:18:00 GMT</pubDate><guid>http://www.blogjava.net/joaquin25/articles/193683.html</guid><wfw:comment>http://www.blogjava.net/joaquin25/comments/193683.html</wfw:comment><comments>http://www.blogjava.net/joaquin25/articles/193683.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/joaquin25/comments/commentRss/193683.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/joaquin25/services/trackbacks/193683.html</trackback:ping><description><![CDATA[<font size="2">转自：http://blogcup.com/user1/6366/archives/2005/52153.shtml<br />
<br />
一,&nbsp;类路径&nbsp;(class&nbsp;path)<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;当你满怀着希望安装好了&nbsp;java,&nbsp;然后兴冲冲地写了个&nbsp;hello&nbsp;world,然后编译,<br />
运行,&nbsp;就等着那两个美好的单词出现在眼前,&nbsp;可是不幸的是,&nbsp;只看到了&nbsp;Can't&nbsp;find<br />
class&nbsp;HelloWorld&nbsp;或者&nbsp;Exception&nbsp;in&nbsp;thread&nbsp;"main"&nbsp;java.lang.NoSuchMethodError:&nbsp;ma<br />
in.<br />
为什么呢?&nbsp;编译好的&nbsp;class&nbsp;明明在呀.<br />
&nbsp;&nbsp;&nbsp;&nbsp;我们一起来看一看&nbsp;java&nbsp;程序的运行过程.&nbsp;我们已经知道&nbsp;java&nbsp;是通过&nbsp;java<br />
<br />
<br />
发信人:&nbsp;SuperMMX&nbsp;(笑天子),&nbsp;信区:&nbsp;Java<br />
标&nbsp;&nbsp;题:&nbsp;[整理]&nbsp;Java&nbsp;的&nbsp;Class&nbsp;Path&nbsp;和&nbsp;Package<br />
发信站:&nbsp;BBS&nbsp;水木清华站&nbsp;(Mon&nbsp;Apr&nbsp;&nbsp;9&nbsp;08:15:01&nbsp;2001)<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Java&nbsp;中的&nbsp;ClassPath&nbsp;和&nbsp;Package<br />
&nbsp;<br />
前言:<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;由于这两个问题新手问得较多,&nbsp;且回答比较零散,&nbsp;很难统一整理,&nbsp;所<br />
以就直接写了一篇,&nbsp;还请大家见谅.<br />
&nbsp;<br />
&nbsp;<br />
正文:<br />
&nbsp;<br />
一,&nbsp;类路径&nbsp;(class&nbsp;path)<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;当你满怀着希望安装好了&nbsp;java,&nbsp;然后兴冲冲地写了个&nbsp;hello&nbsp;world,然后编译,<br />
运行,&nbsp;就等着那两个美好的单词出现在眼前,&nbsp;可是不幸的是,&nbsp;只看到了&nbsp;Can't&nbsp;find<br />
class&nbsp;HelloWorld&nbsp;或者&nbsp;Exception&nbsp;in&nbsp;thread&nbsp;"main"&nbsp;java.lang.NoSuchMethodError:&nbsp;ma<br />
in.<br />
为什么呢?&nbsp;编译好的&nbsp;class&nbsp;明明在呀.<br />
&nbsp;&nbsp;&nbsp;&nbsp;我们一起来看一看&nbsp;java&nbsp;程序的运行过程.&nbsp;我们已经知道&nbsp;java&nbsp;是通过&nbsp;java<br />
<br />
<br />
虚拟机来解释运行的,&nbsp;也就是通过&nbsp;java&nbsp;命令,&nbsp;javac&nbsp;编译生成的&nbsp;.class<br />
文件就是虚拟机要执行的代码,&nbsp;称之为字节码(bytecode),&nbsp;虚拟机通过&nbsp;classloader<br />
来装载这些字节码,&nbsp;也就是通常意义上的类.&nbsp;这里就有一个问题,&nbsp;classloader&nbsp;从<br />
哪里知道&nbsp;java&nbsp;本身的类库及用户自己的类在什么地方呢?&nbsp;或者有着缺省值(当前路径).<br />
或者要有一个用户指定的变量来表明,&nbsp;这个变量就是类路径(classpath),&nbsp;或者在运行<br />
的时候传参数给虚拟机.&nbsp;这也就是指明&nbsp;classpath&nbsp;的三个方法.&nbsp;编译的过程和运行<br />
的过程大同小异,&nbsp;只是一个是找出来编译,&nbsp;另一个是找出来装载.<br />
&nbsp;&nbsp;&nbsp;&nbsp;实际上&nbsp;java&nbsp;虚拟机是由&nbsp;java&nbsp;luncher&nbsp;初始化的,&nbsp;也就是&nbsp;java&nbsp;(或&nbsp;java.exe)<br />
这个程序来做的.&nbsp;虚拟机按以下顺序搜索并装载所有需要的类:<br />
&nbsp;&nbsp;&nbsp;&nbsp;1,&nbsp;引导类:&nbsp;组成&nbsp;java&nbsp;平台的类,&nbsp;包含&nbsp;rt.jar&nbsp;和&nbsp;i18n.jar&nbsp;中的类.<br />
&nbsp;&nbsp;&nbsp;&nbsp;2,&nbsp;扩展类:&nbsp;使用&nbsp;java&nbsp;扩展机制的类,&nbsp;都是位于扩展目录($JAVA_HOME/jre/lib/ext)<br />
中的&nbsp;.jar&nbsp;档案包.<br />
&nbsp;&nbsp;&nbsp;&nbsp;3,&nbsp;用户类:&nbsp;开发者定义的类或者没有使用&nbsp;java&nbsp;扩展机制的第三方产品.&nbsp;你必须在<br />
命令行中使用&nbsp;-classpath&nbsp;选项或者使用&nbsp;CLASSPATH&nbsp;环境变量来确定这些类的位置.&nbsp;我<br />
们在上面所说的用户自己的类就是特指这些类.<br />
&nbsp;&nbsp;&nbsp;&nbsp;这样,&nbsp;一般来说,&nbsp;用户只需指定用户类的位置,&nbsp;引导类和扩展类是"自动"寻找的.<br />
&nbsp;&nbsp;&nbsp;&nbsp;那么到底该怎么做呢?&nbsp;用户类路径就是一些包含类文件的目录,&nbsp;.jar,&nbsp;.zip&nbsp;文件的<br />
列表,&nbsp;至于类具体怎么找,&nbsp;因为牵扯到&nbsp;package&nbsp;的问题,&nbsp;下面将会说到,&nbsp;暂时可认为<br />
只要包含了这个类就算找到了这个类.&nbsp;根据平台的不同分隔符略有不同,&nbsp;类&nbsp;unix&nbsp;的系<br />
统基本上都是&nbsp;":",&nbsp;windows&nbsp;多是&nbsp;";".&nbsp;其可能的来源是:<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;".",&nbsp;即当前目录,&nbsp;这个是缺省值.<br />
<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;CLASSPATH&nbsp;环境变量,&nbsp;一旦设置,&nbsp;将缺省值覆盖.<br />
&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;命令行参数&nbsp;-cp&nbsp;或者&nbsp;-classpath,&nbsp;一旦指定,&nbsp;将上两者覆盖.<br />
&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;由&nbsp;-jar&nbsp;参数指定的&nbsp;.jar&nbsp;档案包,&nbsp;就把所有其他的值覆盖,&nbsp;所有的类都来自这个指<br />
定的档案包中.&nbsp;由于生成可执行的&nbsp;.jar&nbsp;文件,&nbsp;还需要其他一些知识,&nbsp;比如&nbsp;package,&nbsp;还有<br />
特定的配置文件,&nbsp;本文的最后会提到.&nbsp;可先看看&nbsp;jdk&nbsp;自带的一些例子.<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;我们举个&nbsp;HelloWorld&nbsp;的例子来说明.&nbsp;先做以下假设:<br />
&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;当前目录是&nbsp;/HelloWorld&nbsp;(或&nbsp;c:\HelloWorld,&nbsp;以后都使用前一个)<br />
&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;jdk&nbsp;版本为&nbsp;1.2.2&nbsp;(linux&nbsp;下的)<br />
&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;PATH&nbsp;环境变量设置正确.&nbsp;(这样可以在任何目录下都可以使用工具)<br />
&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;文件是&nbsp;HelloWorld.java,&nbsp;内容是:<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;class&nbsp;HelloWorld<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("Hello&nbsp;World!\n");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.exit(0);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;首先这个文件一定要写对,&nbsp;如果对&nbsp;c&nbsp;熟悉的话,&nbsp;很有可能写成这样:<br />
<br />
<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(int&nbsp;argc,&nbsp;String[]&nbsp;argv)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;....<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;这样是不对的,&nbsp;不信可以试一试.&nbsp;由于手头没有&nbsp;java&nbsp;的规范,&nbsp;所以<br />
作如下猜想:&nbsp;java&nbsp;的&nbsp;application&nbsp;程序,&nbsp;必须以&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String[])<br />
开始,&nbsp;其他不一样的都不行.<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;到现在为止,&nbsp;我们设置方面只设置了&nbsp;PATH.<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;1,&nbsp;当前路径就是指你的&nbsp;.class&nbsp;文件在当前目录下,<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[HelloWorld]$&nbsp;javac&nbsp;HelloWorld.java&nbsp;&nbsp;//这一步不会有多大问题,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[HelloWorld]$&nbsp;java&nbsp;HelloWorld&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;这一步可能就会有问题.<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;如果出了象开头那样的问题,&nbsp;首先确定不是由于敲错命令而出错.&nbsp;如果没有敲错命令,<br />
那么接着做:<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[HelloWorld]$&nbsp;echo&nbsp;$CLASSPATH<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;或者<br />
<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c:\HelloWorld&gt;echo&nbsp;%CLASSPATH%<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;看看&nbsp;CLASSPATH&nbsp;环境变量是否设置了,&nbsp;如果设置了,&nbsp;那么用以下命令:<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[HelloWorld]$&nbsp;CLASSPATH=<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;或者<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c:\HelloWorld&gt;&nbsp;set&nbsp;CLASSPATH=<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;来使它为空,&nbsp;然后重新运行.&nbsp;这次用户类路径缺省的是&nbsp;".",&nbsp;所以应该不会有相<br />
同的问题了.&nbsp;还有一个方法就是把&nbsp;"."&nbsp;加入到&nbsp;CLASSPATH&nbsp;中.<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[/]$&nbsp;CLASSPATH=$CLASSPATH:.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;或者<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c:\HelloWorld&gt;&nbsp;set&nbsp;CLASSPATH=%CLASSPATH%;.<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;同样也可以成功.&nbsp;Good&nbsp;Luck.<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;2,&nbsp;当你的程序需要第三方的类库支持,&nbsp;而且比较常用,&nbsp;就可以采用此种方法.比如常<br />
用的数据库驱动程序,&nbsp;写&nbsp;servlet&nbsp;需要的&nbsp;servlet&nbsp;包等等.&nbsp;设置方法就是在环境变量中<br />
加入&nbsp;CLASSPATH.&nbsp;然后就可以直接编译运行了.&nbsp;还是以&nbsp;HelloWorld&nbsp;为例,&nbsp;比如你想在根<br />
目录中运行它,&nbsp;那么你直接在根目录下执行<br />
&nbsp;<br />
<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$&nbsp;java&nbsp;HelloWorld<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;或者<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c:\&gt;java&nbsp;HelloWorld<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;这样肯定会出错,&nbsp;如果你的&nbsp;CLASSPATH&nbsp;没有改动的话.&nbsp;我想大家应该知道为什么错了<br />
吧,&nbsp;那么怎么改呢?&nbsp;前面说过,&nbsp;用户类路径就是一些包含你所需要的类的目录,&nbsp;.jar&nbsp;档案<br />
包,&nbsp;.zip&nbsp;包.&nbsp;现在没有生成包,&nbsp;所以只好把&nbsp;HelloWorld.class&nbsp;所在的目录加到&nbsp;CLASSPAT<br />
H<br />
了,&nbsp;根据前面的做法,&nbsp;再运行一次,&nbsp;看看,&nbsp;呵呵,&nbsp;成功了,&nbsp;换个路径,&nbsp;又成功了!!&nbsp;不仅仅<br />
可<br />
以直接运行其中的类,&nbsp;当你要&nbsp;import&nbsp;其中的某些类时,&nbsp;同样处理.<br />
&nbsp;&nbsp;&nbsp;&nbsp;不知道你想到没有,&nbsp;随着你的系统的不断的扩充,&nbsp;(当然了,&nbsp;都是一些需要&nbsp;java&nbsp;的东<br />
西)<br />
如果都加到这个环境变量里,&nbsp;那这个变量会越来越臃肿,&nbsp;虽然环境变量空间可以开很大,&nbsp;总<br />
觉得有些不舒服.&nbsp;看看下面一个方法.<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;3,&nbsp;在命令行参数中指明&nbsp;classpath.<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;还是和上面相同的目标,&nbsp;在任何目录下执行&nbsp;HelloWorld,&nbsp;用这个方法怎么实现呢?<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[/]$&nbsp;java&nbsp;-cp&nbsp;/HelloWorld&nbsp;HelloWorld<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;或者<br />
<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c:\&gt;java&nbsp;-cp&nbsp;c:\HelloWorld&nbsp;HelloWorld<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;就可以了.&nbsp;这是这种方法的最简单的应用了.&nbsp;当你使用了另外的包的时候,&nbsp;还可以采用<br />
这<br />
种方法.&nbsp;例如:<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$&nbsp;javac&nbsp;-classpath&nbsp;aPath/aPackage.jar:.&nbsp;myJava.java<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$&nbsp;java&nbsp;&nbsp;-cp&nbsp;aPath/aPackage.jar:.&nbsp;myJava<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;或者<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c:\&gt;&nbsp;javac&nbsp;-classpath&nbsp;aPath\aPackage.jar;.&nbsp;myJava.java<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c:\&gt;&nbsp;java&nbsp;&nbsp;-cp&nbsp;aPath\aPackage.jar;.&nbsp;myJava<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;这种方法也有一个不方便的的地方就是当第三方包所在的路径较长或者需要两个以上包<br />
的<br />
时候,&nbsp;每次编译运行都要写很长,&nbsp;非常不方便,&nbsp;这时候可以写脚本来解决.&nbsp;比如一个例子:<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;compile&nbsp;&nbsp;&nbsp;(文件,&nbsp;权限改为可执行,&nbsp;当前目录)<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$&nbsp;cat&nbsp;compile<br />
---------------------------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#!/bin/bash<br />
&nbsp;<br />
<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;javac&nbsp;-classpath&nbsp;aPath\aPackage.jar:anotherPath\anotherPackage.jar:.&nbsp;myJav<br />
a.java<br />
---------------------------<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;run&nbsp;(文件,&nbsp;权限改为可执行,&nbsp;当前目录)<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$cat&nbsp;run<br />
---------------------------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#!/bin/bash<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;java&nbsp;-cp&nbsp;aPath\aPackage.jar:anotherPath\anotherPackage.jar:.&nbsp;myJava<br />
---------------------------<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;或者:<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;compile.bat<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c:\HelloWorld&gt;&nbsp;type&nbsp;compile.bat<br />
-------------------------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;javac&nbsp;-classpath&nbsp;aPath\aPackage.jar:anotherPath\anotherPackage.jar:.&nbsp;myJav<br />
a.java<br />
-------------------------<br />
<br />
<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;run.bat<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c:\HelloWorld&gt;&nbsp;type&nbsp;run.bat<br />
------------------------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;java&nbsp;-cp&nbsp;aPath\aPackage.jar:anotherPath\anotherPackage.jar:.&nbsp;myJava<br />
------------------------<br />
&nbsp;&nbsp;&nbsp;&nbsp;就可以了.&nbsp;试试看.<br />
&nbsp;&nbsp;&nbsp;&nbsp;前面提到了扩展类,&nbsp;扩展类是什么呢?&nbsp;java&nbsp;的扩展类就是应用程序开发者用来<br />
扩展核心平台功能的&nbsp;java&nbsp;类的包(或者是&nbsp;native&nbsp;code).&nbsp;虚拟机能像使用系统类一<br />
样使用这些扩展类.&nbsp;有人建议可以把包放入扩展目录里,&nbsp;这样,&nbsp;CLASSPATH&nbsp;也不用设了,<br />
也不用指定了,&nbsp;岂不是很方便?&nbsp;确实可以正确运行,&nbsp;但是个人认为这样不好,&nbsp;不能什么<br />
东西都往里搁,&nbsp;一些标准的扩展包可以,&nbsp;比如,&nbsp;JavaServlet,&nbsp;Java3D&nbsp;等等.&nbsp;可以提个<br />
建议,&nbsp;加一个环境变量,&nbsp;比如叫&nbsp;JARPATH,&nbsp;指定一个目录,&nbsp;专门存放用户的&nbsp;jar&nbsp;zip<br />
等包,&nbsp;这个要等&nbsp;SUN&nbsp;公司来做了.<br />
&nbsp;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;windows98&nbsp;下,&nbsp;我原来安装的时候,&nbsp;一直装不上,&nbsp;总是死机,&nbsp;好不容易装上了,&nbsp;缺<br />
省的是不能运行正确的,&nbsp;然后把&nbsp;tool.jar&nbsp;放入&nbsp;CLASSPATH&nbsp;后工作正常.&nbsp;现在作测试,<br />
去掉仍然是正确的.&nbsp;经过多次测试,&nbsp;发现如果原来曾装过&nbsp;jdk&nbsp;的都很好,&nbsp;没有装过的<br />
装的时候会死机,&nbsp;多装几次就可以了.&nbsp;如果你发现正确安装后,&nbsp;不能正常工作,&nbsp;就把<br />
tools.jar&nbsp;加入&nbsp;CLASSPATH,&nbsp;试一下.<br />
<br />
<br />
&nbsp;<br />
&nbsp;<br />
二,&nbsp;包&nbsp;(package)<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;Java&nbsp;中的&nbsp;"包"&nbsp;是一个比较重要的概念,&nbsp;package&nbsp;是这样定义的:<br />
&nbsp;<br />
Definition:&nbsp;A&nbsp;package&nbsp;is&nbsp;a&nbsp;collection&nbsp;of&nbsp;related&nbsp;classes&nbsp;and&nbsp;interfaces<br />
that&nbsp;provides&nbsp;access&nbsp;protection&nbsp;and&nbsp;namespace&nbsp;management.<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;也就是:&nbsp;一个包就是一些提供访问保护和命名空间管理的相关类与接口的集合.<br />
&nbsp;&nbsp;&nbsp;&nbsp;使用包的目的就是使类容易查找使用,&nbsp;防止命名冲突,&nbsp;以及控制访问.<br />
&nbsp;&nbsp;&nbsp;&nbsp;这里我们不讨论关于包的过多的东西,&nbsp;只讨论和编译,&nbsp;运行,&nbsp;类路径相关的东西.<br />
至于包的其他内容,&nbsp;请自己查阅相关文档.<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;简单一点来说,&nbsp;包就是一个目录,&nbsp;下面的子包就是子目录,&nbsp;这个包里的类就是<br />
这个目录下的文件.&nbsp;我们用一个例子来说明.<br />
&nbsp;&nbsp;&nbsp;&nbsp;首先建目录结构如下:&nbsp;PackageTest/source/,&nbsp;以后根目录指的是&nbsp;PackageTest<br />
目录,&nbsp;我们的源程序放在&nbsp;source&nbsp;目录下.&nbsp;源程序如下:<br />
&nbsp;<br />
PackageTest.java<br />
&nbsp;<br />
package&nbsp;pktest;<br />
<br />
<br />
&nbsp;<br />
import&nbsp;pktest.subpk.*;<br />
&nbsp;<br />
public&nbsp;class&nbsp;PackageTest<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;String&nbsp;value;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;PackageTest(String&nbsp;s)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;value&nbsp;=&nbsp;s;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;printvalue()<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("value&nbsp;of&nbsp;PackageTest&nbsp;is&nbsp;"&nbsp;+&nbsp;value);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PackageTest&nbsp;test&nbsp;=&nbsp;new&nbsp;PackageTest("This&nbsp;is&nbsp;a&nbsp;Test&nbsp;Package");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;test.printvalue();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PackageSecond&nbsp;second&nbsp;=&nbsp;new&nbsp;PackageSecond("I&nbsp;am&nbsp;in&nbsp;PackageTest");<br />
<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;second.printvalue();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PackageSub&nbsp;sub&nbsp;=&nbsp;new&nbsp;PackageSub("I&nbsp;am&nbsp;in&nbsp;PackageTest");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sub.printvalue();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.exit(0);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}<br />
&nbsp;<br />
PackageSecond.java<br />
&nbsp;<br />
package&nbsp;pktest;<br />
&nbsp;<br />
public&nbsp;class&nbsp;PackageSecond<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;String&nbsp;value;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;PackageSecond(String&nbsp;s)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;value&nbsp;=&nbsp;s;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;printvalue()<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("value&nbsp;of&nbsp;PackageSecond&nbsp;is&nbsp;"&nbsp;+&nbsp;value);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}<br />
&nbsp;<br />
PackageSub.java<br />
&nbsp;<br />
package&nbsp;pktest.subpk;<br />
&nbsp;<br />
import&nbsp;pktest.*;<br />
&nbsp;<br />
public&nbsp;class&nbsp;PackageSub<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;String&nbsp;value;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;PackageSub(String&nbsp;s)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;value&nbsp;=&nbsp;s;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;printvalue()<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PackageSecond&nbsp;second&nbsp;=&nbsp;new&nbsp;PackageSecond("I&nbsp;am&nbsp;in&nbsp;subpackage.");<br />
<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;second.printvalue();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("value&nbsp;of&nbsp;PackageSub&nbsp;is&nbsp;"&nbsp;+&nbsp;value);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;<br />
}<br />
&nbsp;<br />
Main.java<br />
&nbsp;<br />
import&nbsp;pktest.*;<br />
import&nbsp;pktest.subpk.*;<br />
&nbsp;<br />
public&nbsp;class&nbsp;Main()<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main()<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PackageSecond&nbsp;second&nbsp;=&nbsp;new&nbsp;PackageSecond("I&nbsp;am&nbsp;in&nbsp;Main");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;second.printvalue();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PackageSub&nbsp;sub&nbsp;=&nbsp;new&nbsp;PackageSub("I&nbsp;am&nbsp;in&nbsp;Main");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sub.printvalue();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.exit(0);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}<br />
<br />
<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;其中,&nbsp;Main.java&nbsp;是包之外的一个程序,&nbsp;用来测试包外的程序访问包内的类,<br />
PackageTest.java&nbsp;属于&nbsp;pktest&nbsp;这个包,&nbsp;也是主程序.&nbsp;PackageSecond.java&nbsp;也<br />
属于&nbsp;pktest,&nbsp;PackageSub&nbsp;属于&nbsp;pktest&nbsp;下的&nbsp;subpk&nbsp;包,&nbsp;也就是&nbsp;pktest.subpk.<br />
详细使用情况,&nbsp;请参看源程序.<br />
&nbsp;&nbsp;&nbsp;&nbsp;好了,&nbsp;先把源程序都放在&nbsp;source&nbsp;目录下,&nbsp;使&nbsp;source&nbsp;成为当前目录,&nbsp;然后编<br />
译一下,&nbsp;呵呵,&nbsp;出错了,<br />
&nbsp;<br />
Main.java:1:&nbsp;Package&nbsp;pktest&nbsp;not&nbsp;found&nbsp;in&nbsp;import.<br />
import&nbsp;pktest.*;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;这里涉及到类路径中包是怎么查找的,&nbsp;前面我们做了一点假设:&nbsp;"只要包含了<br />
这个类就算找到了这个类",&nbsp;现在就有问题了.&nbsp;其实&nbsp;jdk&nbsp;的&nbsp;工具&nbsp;javac&nbsp;java<br />
javadoc&nbsp;都需要查找类,&nbsp;看见目录,&nbsp;就认为是包的名字,&nbsp;对于&nbsp;import&nbsp;语句来说,<br />
一个包对应一个目录.&nbsp;这个例子中,&nbsp;import&nbsp;pktest.*,&nbsp;我们知道类路径可以包<br />
含一个目录,&nbsp;那么就以那个目录为根,&nbsp;比如有个目录&nbsp;/myclass,&nbsp;那么就会在查找<br />
/myclass/pktest&nbsp;目录及其下的类.&nbsp;所有的都找遍,&nbsp;如果没有就会报错.&nbsp;由于现在<br />
的类路径只有当前目录,&nbsp;而当前目录下没有&nbsp;pktest&nbsp;目录,&nbsp;所以就会出错.&nbsp;类路径<br />
还可以包含&nbsp;.jar&nbsp;.zip&nbsp;文件,&nbsp;这些就是可以带目录的压缩包,&nbsp;可以把&nbsp;.jar&nbsp;.zip<br />
文件看做一个虚拟的目录,&nbsp;然后就和目录一样对待了.<br />
&nbsp;&nbsp;&nbsp;&nbsp;好了,&nbsp;应该知道怎么做了吧,&nbsp;修改后的目录结构如下:<br />
&nbsp;<br />
<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;PackageTest<br />
&nbsp;&nbsp;&nbsp;&nbsp;|<br />
&nbsp;&nbsp;&nbsp;&nbsp;|__source&nbsp;&nbsp;&nbsp;Main.java<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|__pktest&nbsp;&nbsp;&nbsp;PackageTest.java&nbsp;&nbsp;&nbsp;PackageSecond.java<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|__subpk&nbsp;&nbsp;PackageSub.java<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;然后重新编译,&nbsp;运行,&nbsp;哈哈,&nbsp;通过了.&nbsp;我们再来运行一下&nbsp;PackageTest.<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;[source]$&nbsp;java&nbsp;pktest/PackageTest<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;怎么又出错了?<br />
&nbsp;<br />
Exception&nbsp;in&nbsp;thread&nbsp;"main"&nbsp;java.lang.NoClassDefFoundError:&nbsp;pktest/PackageTest<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;是这样的,&nbsp;java&nbsp;所要运行的是一个类的名字,&nbsp;它可不管你的类在什么地方,&nbsp;就象<br />
我们前面所讨论的一样来查找这个类,&nbsp;所以它把&nbsp;pktest/PackageTest&nbsp;看成是一个类的<br />
名字了,&nbsp;当然会出错了,&nbsp;应该这么做,<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;[source]$&nbsp;java&nbsp;pktest.PackageTest<br />
&nbsp;<br />
<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;大家应该明白道理吧,&nbsp;我就不多说了.&nbsp;注意&nbsp;javac&nbsp;不一样,&nbsp;是可以指明源文件路径<br />
的,&nbsp;javac&nbsp;只编译,&nbsp;不运行,&nbsp;查找类也只有在源文件中碰到&nbsp;import&nbsp;时才会做,&nbsp;与源文件<br />
所在的包没有关系.<br />
&nbsp;&nbsp;&nbsp;&nbsp;似乎还又些不好的地方,&nbsp;怎么生成的&nbsp;.class&nbsp;文件这么分散呀,&nbsp;看着真别扭.&nbsp;别急,<br />
javac&nbsp;有一个&nbsp;-d&nbsp;命令行参数,&nbsp;可以指定一个目录,&nbsp;把生成的&nbsp;.class&nbsp;文件按照包给你<br />
好好地搁在这个目录里面.<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;[source]$&nbsp;mkdir&nbsp;classes<br />
&nbsp;&nbsp;&nbsp;&nbsp;[source]$&nbsp;javac&nbsp;-d&nbsp;classes&nbsp;pktest/PackageTest.java<br />
&nbsp;&nbsp;&nbsp;&nbsp;[source]$&nbsp;javac&nbsp;-d&nbsp;classes&nbsp;Main.java<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;那么运行怎么运行呢?<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;[source]$&nbsp;cd&nbsp;classes<br />
&nbsp;&nbsp;&nbsp;&nbsp;[classes]$&nbsp;java&nbsp;pktest.PackageTest<br />
&nbsp;&nbsp;&nbsp;&nbsp;[classes]$&nbsp;java&nbsp;Main<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;就可以了.&nbsp;其实&nbsp;jdk&nbsp;的这一套工具小巧简单,&nbsp;功能强大,&nbsp;不会用或者用错其<br />
实不关工具的事,&nbsp;关键是明白工具背后的一些原理和必要的知识.&nbsp;集成环境是很好,<br />
但是它屏蔽了很多底层的知识,&nbsp;不出错还好,&nbsp;一旦出错,&nbsp;如果没有这些必要的知识<br />
就很难办,&nbsp;只好上&nbsp;bbs&nbsp;问,&nbsp;别人只告诉了你解决的具体方法,&nbsp;下一次遇到稍微变化<br />
一点的问题又不懂了.&nbsp;所以不要拘泥于工具,&nbsp;java&nbsp;的这一套工具组合起来使用,&nbsp;中<br />
<br />
<br />
小型工程(五六十个类),&nbsp;还是应付得下来的.<br />
&nbsp;<br />
&nbsp;<br />
三,&nbsp;jar&nbsp;文件<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;以下把&nbsp;.jar&nbsp;.zip&nbsp;都看做是&nbsp;.jar&nbsp;文件.<br />
&nbsp;<br />
&nbsp;<br />
1,&nbsp;&nbsp;从前面我们可以看出来&nbsp;jar&nbsp;文件在&nbsp;java&nbsp;中非常重要,&nbsp;极大地方便了用户的<br />
使用.&nbsp;我们也可以做自己的&nbsp;.jar&nbsp;包.<br />
&nbsp;&nbsp;&nbsp;&nbsp;还是使用前面那个例子,&nbsp;Main.java&nbsp;是包之外的东西,&nbsp;用了&nbsp;pktest&nbsp;包中的类,<br />
我们现在就是要把&nbsp;pktest&nbsp;做成一个&nbsp;.jar&nbsp;包,&nbsp;很简单,&nbsp;刚才我们已经把&nbsp;pktest<br />
中的&nbsp;.class&nbsp;都集中起来了,<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;[classes]$&nbsp;jar&nbsp;-cvf&nbsp;mypackage.jar&nbsp;pktest<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;就会生成&nbsp;mypackage.jar&nbsp;文件,&nbsp;测试一下,&nbsp;刚才我们生成的&nbsp;Main.class&nbsp;就在<br />
&nbsp;&nbsp;&nbsp;&nbsp;classes&nbsp;目录下,&nbsp;所以,&nbsp;从前面可以知道:<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;[classes]$&nbsp;java&nbsp;-cp&nbsp;mypackage.jar:.&nbsp;Main<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;就可以运行了.<br />
<br />
<br />
&nbsp;<br />
2,&nbsp;&nbsp;如果你看过&nbsp;jdk&nbsp;所带的例子,&nbsp;你就会知道,&nbsp;.jar&nbsp;还可以直接运行,<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;[/demo]$&nbsp;java&nbsp;-jar&nbsp;aJar.jar<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;那好,&nbsp;就那我们的试一试,<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;[classes]$&nbsp;java&nbsp;-jar&nbsp;mypackage.jar<br />
&nbsp;&nbsp;&nbsp;&nbsp;Failed&nbsp;to&nbsp;load&nbsp;Main-Class&nbsp;manifest&nbsp;attribute&nbsp;from<br />
&nbsp;&nbsp;&nbsp;&nbsp;mypackage.jar<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;看来我们的&nbsp;jar&nbsp;和它的&nbsp;jar&nbsp;还不一样,&nbsp;有什么不一样呢?&nbsp;拿它一个例子出来,<br />
重新编译,&nbsp;生成&nbsp;.jar&nbsp;文件,&nbsp;比较后发现,&nbsp;是&nbsp;.jar&nbsp;压缩包中&nbsp;META-INF/MANIFEST.MF<br />
文件不一样,&nbsp;多了一行,&nbsp;Main-Class:&nbsp;xxxxx,&nbsp;再看看出错信息,&nbsp;原来是没有指定<br />
Main-Class,&nbsp;看看&nbsp;jar&nbsp;命令,&nbsp;发现有一个参数&nbsp;-m,<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;-m&nbsp;&nbsp;include&nbsp;manifest&nbsp;information&nbsp;from&nbsp;specified&nbsp;manifest&nbsp;file<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;和出错信息有点关系,&nbsp;看来它要读一个配制文件.&nbsp;只好照猫画虎写一个了.<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;[classes]$&nbsp;cat&nbsp;myManifest<br />
&nbsp;&nbsp;&nbsp;&nbsp;Manifest-Version:&nbsp;1.0<br />
<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Main-Class:&nbsp;pktest.PackageTest<br />
&nbsp;&nbsp;&nbsp;&nbsp;Created-By:&nbsp;1.2.2&nbsp;(Sun&nbsp;Microsystems&nbsp;Inc.)<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;[classes]$&nbsp;jar&nbsp;cvfm&nbsp;mypackage.jar&nbsp;myManifest&nbsp;pktest<br />
&nbsp;&nbsp;&nbsp;&nbsp;added&nbsp;manifest<br />
&nbsp;&nbsp;&nbsp;&nbsp;adding:&nbsp;pktest/(in&nbsp;=&nbsp;0)&nbsp;(out=&nbsp;0)(stored&nbsp;0%)<br />
&nbsp;&nbsp;&nbsp;&nbsp;adding:&nbsp;pktest/PackageSecond.class(in&nbsp;=&nbsp;659)&nbsp;(out=&nbsp;395)(deflated&nbsp;40%)<br />
&nbsp;&nbsp;&nbsp;&nbsp;adding:&nbsp;pktest/subpk/(in&nbsp;=&nbsp;0)&nbsp;(out=&nbsp;0)(stored&nbsp;0%)<br />
&nbsp;&nbsp;&nbsp;&nbsp;adding:&nbsp;pktest/subpk/PackageSub.class(in&nbsp;=&nbsp;744)&nbsp;(out=&nbsp;454)(deflated&nbsp;38%)<br />
&nbsp;&nbsp;&nbsp;&nbsp;adding:&nbsp;pktest/PackageTest.class(in&nbsp;=&nbsp;1041)&nbsp;(out=&nbsp;602)(deflated&nbsp;42%)<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;[classes]$&nbsp;java&nbsp;-jar&nbsp;mypackage.jar<br />
&nbsp;&nbsp;&nbsp;&nbsp;value&nbsp;of&nbsp;PackageTest&nbsp;is&nbsp;This&nbsp;is&nbsp;a&nbsp;Test&nbsp;Package<br />
&nbsp;&nbsp;&nbsp;&nbsp;value&nbsp;of&nbsp;PackageSecond&nbsp;is&nbsp;I&nbsp;am&nbsp;in&nbsp;PackageTest<br />
&nbsp;&nbsp;&nbsp;&nbsp;value&nbsp;of&nbsp;PackageSecond&nbsp;is&nbsp;I&nbsp;am&nbsp;in&nbsp;subpackage.<br />
&nbsp;&nbsp;&nbsp;&nbsp;value&nbsp;of&nbsp;PackageSub&nbsp;is&nbsp;I&nbsp;am&nbsp;in&nbsp;PackageTest<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;好了,&nbsp;成功了,&nbsp;这样就做好了一个可以直接执行的&nbsp;.jar&nbsp;文件.&nbsp;大家可以自己试一试<br />
做一个以&nbsp;Main&nbsp;为主程序的可执行的&nbsp;jar.<br />
&nbsp;<br />
&nbsp;<br />
小结:<br />
<br />
<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;这篇文章中,&nbsp;我们讨论了&nbsp;java&nbsp;中的&nbsp;class&nbsp;path,&nbsp;package,&nbsp;jar&nbsp;等基本但比较<br />
重要的东西,&nbsp;主要是&nbsp;class&nbsp;path.&nbsp;并不是简单的一份&nbsp;CLASSPATH&nbsp;的完全功略,&nbsp;而是<br />
试图让读者明白其原理,&nbsp;自己思考,&nbsp;自己动手.&nbsp;其实大多数东西都在&nbsp;sun&nbsp;的&nbsp;java&nbsp;doc<br />
中都有,&nbsp;我只不过结合例子稍微谈了一下,&nbsp;希望能有所帮助.&nbsp;由于条件所限,&nbsp;只测试了<br />
jdk1.2.2&nbsp;在&nbsp;98&nbsp;及&nbsp;linux&nbsp;的情况,&nbsp;其他版本的&nbsp;jdk&nbsp;和平台请大家自己测试,&nbsp;错误在<br />
所难免,&nbsp;还请指正.<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;下面是一些需要注意的问题:<br />
&nbsp;<br />
1,&nbsp;如果类路径中需要用到&nbsp;.jar&nbsp;文件,&nbsp;必须把&nbsp;jar&nbsp;文件的文件名放入类路径,&nbsp;而不是<br />
其所在的目录.<br />
2,&nbsp;在任何时候,&nbsp;类名必须带有完全的包名,<br />
3,&nbsp;"."&nbsp;当前目录最好在你的类路径中.<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;下面是一些常见的编译和运行的模式.<br />
&nbsp;<br />
4.&nbsp;To&nbsp;compile&nbsp;HelloWorld.java&nbsp;app&nbsp;in&nbsp;the&nbsp;default&nbsp;package&nbsp;in&nbsp;C:\MyDir,&nbsp;use<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CD&nbsp;\MyDir<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;C:\jdk1.3\bin\Javac.exe&nbsp;-classpath&nbsp;.&nbsp;HelloWorld.java<br />
5.&nbsp;To&nbsp;run&nbsp;a&nbsp;HelloWorld.class&nbsp;app,&nbsp;in&nbsp;the&nbsp;default&nbsp;package&nbsp;in&nbsp;C:\MyDir,&nbsp;use<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CD&nbsp;\MyDir<br />
<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;C:\jdk1.3\bin\Java.exe&nbsp;-classpath&nbsp;.&nbsp;HelloWorld<br />
6.&nbsp;To&nbsp;run&nbsp;a&nbsp;HelloWorld.class&nbsp;app,&nbsp;in&nbsp;the&nbsp;default&nbsp;package&nbsp;in&nbsp;a&nbsp;jar&nbsp;in&nbsp;C:\MyDir,&nbsp;u<br />
se<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CD&nbsp;\MyDir<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;C:\jdk1.3\bin\Java.exe&nbsp;-classpath&nbsp;HelloWorld.jar&nbsp;HelloWorld<br />
7.&nbsp;To&nbsp;compile&nbsp;a&nbsp;HelloWorld.java&nbsp;app&nbsp;in&nbsp;C:\MyPackage,&nbsp;in&nbsp;package&nbsp;MyPackage,&nbsp;use<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CD&nbsp;\<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;C:\jdk1.3\bin\Javac.exe&nbsp;-classpath&nbsp;.&nbsp;MyPackage\HelloWorld.java<br />
8.&nbsp;To&nbsp;run&nbsp;a&nbsp;HelloWorld.class&nbsp;app&nbsp;in&nbsp;C:\MyPackage,&nbsp;in&nbsp;package&nbsp;MyPackage,&nbsp;use<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CD&nbsp;\<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;C:\jdk1.3\bin\Java.exe&nbsp;-classpath&nbsp;.&nbsp;MyPackage.HelloWorld<br />
9.&nbsp;To&nbsp;run&nbsp;a&nbsp;HelloWorld.class&nbsp;app&nbsp;in&nbsp;C:\MyPackage,&nbsp;in&nbsp;a&nbsp;jar&nbsp;in&nbsp;package&nbsp;MyPackage,<br />
&nbsp;use<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CD&nbsp;\MyDir<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;C:\jdk1.3\bin\Java.exe&nbsp;-classpath&nbsp;HelloWorld.jar&nbsp;MyPackage.HelloWorl<br />
d<br />
&nbsp;<br />
(注:&nbsp;default&nbsp;package&nbsp;指的是在程序中不指定任何包).<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;最后一个小小的建议,&nbsp;把&nbsp;sun&nbsp;的&nbsp;jdk&nbsp;tools&nbsp;document．tion&nbsp;好好地看一看,<br />
把&nbsp;jdk&nbsp;的那些工具&nbsp;java&nbsp;javac&nbsp;javadoc&nbsp;jar&nbsp;javap&nbsp;jdb......好好用一用,&nbsp;会<br />
有好处的.&nbsp;The&nbsp;Simplest&nbsp;Is&nbsp;The&nbsp;Best.<br />
</font>
<img src ="http://www.blogjava.net/joaquin25/aggbug/193683.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/joaquin25/" target="_blank">joaquin25</a> 2008-04-17 11:18 <a href="http://www.blogjava.net/joaquin25/articles/193683.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>path和classpath</title><link>http://www.blogjava.net/joaquin25/articles/193678.html</link><dc:creator>joaquin25</dc:creator><author>joaquin25</author><pubDate>Thu, 17 Apr 2008 03:10:00 GMT</pubDate><guid>http://www.blogjava.net/joaquin25/articles/193678.html</guid><wfw:comment>http://www.blogjava.net/joaquin25/comments/193678.html</wfw:comment><comments>http://www.blogjava.net/joaquin25/articles/193678.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/joaquin25/comments/commentRss/193678.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/joaquin25/services/trackbacks/193678.html</trackback:ping><description><![CDATA[<span style="font-size: 10pt"><strong>PATH：</strong>指定一个路径列表，用于搜索可执行文件的。执行一个可执行文件时，如果该文件不能在当前路径下找到，则依次寻找 PATH 中的每一个路径，直至找到。或者找完 PATH 中的路径也不能找到，则报错。Java 的编译命令 (javac)，执行命令 (java) 和一些工具命令 (javadoc, jdb 等) 都在其安装路径下的 bin 目录中。因此我们应该将该路径添加到 PATH 变量中。 </span>
<p><span style="font-size: 10pt"><strong>CLASSPATH</strong>：也指定一个路径列表，是用于搜索 Java 编译或者运行时需要用到的类。在 CLASSPATH 列表中除了可以包含路径外，还可以包含 .jar 文件。Java 查找类时会把这个 .jar 文件当作一个目录来进行查找。通常，我们需要把 JDK 安装路径下的 jre\lib\rt.jar (Linux: jre/lib/rt.jar) 包含在 CLASSPATH 中。</span></p>
<img src ="http://www.blogjava.net/joaquin25/aggbug/193678.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/joaquin25/" target="_blank">joaquin25</a> 2008-04-17 11:10 <a href="http://www.blogjava.net/joaquin25/articles/193678.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>String和BufferString</title><link>http://www.blogjava.net/joaquin25/articles/172211.html</link><dc:creator>joaquin25</dc:creator><author>joaquin25</author><pubDate>Wed, 02 Jan 2008 07:16:00 GMT</pubDate><guid>http://www.blogjava.net/joaquin25/articles/172211.html</guid><wfw:comment>http://www.blogjava.net/joaquin25/comments/172211.html</wfw:comment><comments>http://www.blogjava.net/joaquin25/articles/172211.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/joaquin25/comments/commentRss/172211.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/joaquin25/services/trackbacks/172211.html</trackback:ping><description><![CDATA[<font color="#555576">转自：http://hi.baidu.com/answer512/blog/item/429776d1755865399b50278c.html<br />
<br />
String类用来表示那些创建后就不会再改变的字符串，它是immutable的。<br />
StringBuffer类用来表示内容可变的字符串，并提供了修改底层字符串的方法。<br />
&nbsp;&nbsp;&nbsp; 当我们进行字符拼接时，请使用StringBuffer类而非String类，因为前者将比后者快上百倍。<br />
的确，在程序的太多场合我们都会进行字符串拼接工作，简单的代码示例如下：<br />
String str="You are nice.";<br />
str+="I love you so much.";<br />
如果用StringBuffer类的话，代码如下：<br />
StringBuffer str= new StringBuffer("You are nice.");<br />
str.append("I love you so much.");<br />
&nbsp;&nbsp;&nbsp;&nbsp; 从表面看来String类只用一个加号（+）便完成了字符串的拼接，而StringBuffer类却要调用一个append()方法，是否实现起来更简洁，更单纯呢？其实不然，让我们了解一下程序运行内部发生了哪些事情：<br />
&nbsp;&nbsp;&nbsp;&nbsp; 经编译后程序的bytecode（字节码）展示出了实质： 在用String类对象直接拼接时，JVM会创建一个临时的StringBuffer类对象，并调用其append()方法完成字符串的拼接，这是因为 String类是不可变的，拼接操作不得不使用StringBuffer类（并且－－JVM会将"You are nice."和"I love you so much."创建为两个新的String对象）。之后，再将这个临时StringBuffer对象转型为一个String，代价不菲！可见，在这一个简单的一次拼接过程中，我们让程序创建了四个对象：两个待拼接的String，一个临时StringBuffer，和最后将StringBuffer转型成为的String－－它当然不是最初的str了，这个引用的名称没变，但它指向了新的String对象。<br />
&nbsp;&nbsp;&nbsp;&nbsp; 而如果直接使用StringBuffer类，程序将只产生两个对象：最初的StringBuffer和拼接时的String（"I love you so much."），也不再需要创建临时的StringBuffer类对象而后还得将其转换回String对象。<br />
&nbsp;&nbsp;&nbsp;&nbsp; 可以想象，当我们的字符串要被循环拼接若干段时，用String类直接操作会带来多少额外的系统开销，生成多少无用的临时StringBuffer对象，并处理多少次无谓的强制类型转换哪。</font><br />
<img src ="http://www.blogjava.net/joaquin25/aggbug/172211.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/joaquin25/" target="_blank">joaquin25</a> 2008-01-02 15:16 <a href="http://www.blogjava.net/joaquin25/articles/172211.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>FileWriter和FileReader</title><link>http://www.blogjava.net/joaquin25/articles/172210.html</link><dc:creator>joaquin25</dc:creator><author>joaquin25</author><pubDate>Wed, 02 Jan 2008 07:15:00 GMT</pubDate><guid>http://www.blogjava.net/joaquin25/articles/172210.html</guid><wfw:comment>http://www.blogjava.net/joaquin25/comments/172210.html</wfw:comment><comments>http://www.blogjava.net/joaquin25/articles/172210.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/joaquin25/comments/commentRss/172210.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/joaquin25/services/trackbacks/172210.html</trackback:ping><description><![CDATA[<p>转自：<a href="http://epasser.aydc.com.cn/article/adp/2/content14979.html">http://epasser.aydc.com.cn/article/adp/2/content14979.html</a><br />
<br />
写入文件</p>
<p>&nbsp;&nbsp;&nbsp; try{ <br />
&nbsp;&nbsp;&nbsp; FileWriter fw=new FileWriter(SystemConfig.getRealPath()+"WEB-INF/url.txt");<br />
&nbsp;&nbsp;&nbsp; fw.write("movie"+name);<br />
&nbsp;&nbsp;&nbsp; fw.close();<br />
&nbsp;&nbsp; }catch(IOException e){<br />
&nbsp;&nbsp; e.printStackTrace();<br />
&nbsp;&nbsp; }</p>
<p>读文件中内容</p>
<p>&nbsp;&nbsp; try{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FileReader fr = null;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;fr = new FileReader(SystemConfig.getRealPath()+"WEB-INF/url.txt");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;BufferedReader br=new BufferedReader(fr);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;String Line = null;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;String s = null；&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Line = br.readLine();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while(Line!=null){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; s+=Line;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Line=null;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; br.close();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fr.close();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }catch(IOException e1){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e1.printStackTrace();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>上传文件</p>
<p>&nbsp;&nbsp;&nbsp; try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; InputStream stream = getUpFile().getInputStream();//把文件读入<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OutputStream bos = new FileOutputStream(filePath + "movie" +name);//建立一个上传文件的输出流<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int bytesRead = 0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; byte[] buffer = new byte[1026];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while ( (bytesRead = stream.read(buffer, 0, 1026)) != -1) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bos.write(buffer, 0, bytesRead);//将文件写入服务器<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bos.close();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; stream.close();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }catch(Exception e){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.err.print(e);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
<br />
<code><strong><a href="file:///F:/资料/文字资料/j2sdk-1_4_2-doc/docs/api/java/io/FileWriter.html#FileWriter(java.io.File, boolean)"><font size="3">FileWriter</font></a></strong><font size="3">(</font><a title="class in java.io" href="file:///F:/资料/文字资料/j2sdk-1_4_2-doc/docs/api/java/io/File.html"><font size="3">File</font></a><font size="3">&nbsp;file, boolean&nbsp;append)</font></code><font size="3"> <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Constructs a FileWriter object given a File object. 构建一个给定File对象的FileWriter对象,append指明是否覆盖以前内容。</font></p>
<img src ="http://www.blogjava.net/joaquin25/aggbug/172210.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/joaquin25/" target="_blank">joaquin25</a> 2008-01-02 15:15 <a href="http://www.blogjava.net/joaquin25/articles/172210.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java变量类型间的相互转换</title><link>http://www.blogjava.net/joaquin25/articles/165215.html</link><dc:creator>joaquin25</dc:creator><author>joaquin25</author><pubDate>Tue, 04 Dec 2007 07:30:00 GMT</pubDate><guid>http://www.blogjava.net/joaquin25/articles/165215.html</guid><wfw:comment>http://www.blogjava.net/joaquin25/comments/165215.html</wfw:comment><comments>http://www.blogjava.net/joaquin25/articles/165215.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/joaquin25/comments/commentRss/165215.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/joaquin25/services/trackbacks/165215.html</trackback:ping><description><![CDATA[<p>[转载]<br />
<br />
我们知道，Java的数据类型分为三大类，即布尔型、字符型和数值型，而其中数值型又分为整型和浮点型；相对于数据类型，Java的变量类型为布尔型boolean；字符型char；整型byte、short、int、long；浮点型float、double。其中四种整型变量和两种浮点型变量分别对应于不同的精度和范围。此外，我们还经常用到两种类变量，即String和Date。对于这些变量类型之间的相互转换在我们编程中经常要用到，在我们今天的这篇文章中，我们将来看看如何实现这些转换。&nbsp; </p>
<p>一、 整型、实型、字符型变量中的相互转换&nbsp; </p>
<p>在Java中整型、实型、字符型被视为同一类数据，这些类型由低级到高级分别为(byte，short，char)——int——long——float——double，低级变量可以直接转换为高级变量，例如，下面的语句可以在Java中直接通过：&nbsp; </p>
<p>byte b;&nbsp; </p>
<p>int i=b;&nbsp; </p>
<p>而将高级变量转换为低级变量时，情况会复杂一些，你可以使用强制类型转换。即你必须采用下面这种语句格式：&nbsp; </p>
<p>int i;&nbsp; </p>
<p>byte b=(byte)i;&nbsp; </p>
<p>可以想象，这种转换肯定可能会导致溢出或精度的下降，因此我们并不推荐使用这种转换。&nbsp; </p>
<p>二、Java的包装类&nbsp; </p>
<p>在我们讨论其它变量类型之间的相互转换时，我们需要了解一下Java的包装类，所谓包装类，就是可以直接将简单类型的变量表示为一个类，在执行变量类型的相互转换时，我们会大量使用这些包装类。Java共有六个包装类，分别是Boolean、Character、Integer、Long、Float和Double，从字面上我们就可以看出它们分别对应于 boolean、char、int、long、float和double。而String和Date本身就是类。所以也就不存在什么包装类的概念了。&nbsp; </p>
<p>三、简单类型变量和包装类之间的相互转换&nbsp; </p>
<p>简单类型的变量转换为相应的包装类，可以利用包装类的构造函数。即： Boolean(boolean value)、Character(char value)、Integer(int value)、Long(long value)、Float(float value)、Double(double value) 而在各个包装类中，总有形为&#215;&#215;Value()的方法，来得到其对应的简单类型数据。利用这种方法，也可以实现不同数值型变量间的转换，例如，对于一个双精度实型类，intValue()可以得到其对应的整型变量，而doubleValue()可以得到其对应的双精度实型变量。&nbsp; </p>
<p>四、String类和其它数据类型的相互转换&nbsp; </p>
<p>对于上面的这些包装类，除了Character以外，都有可以直接使用字符串参数的构造函数，这也就使得我们将String类转换为这些数据类型变得相当之简单，即： Boolean(String s)、Integer(String s)、Long(String s)、Float(String s)、Double(String s) 而将String类转换为Date类也可以使用这样的构造函数：Date(String s) 现在我们还剩下一个字符型变量，事实上String类可以理解为一个char型数组，因此我们可以在String类中找到这样的方法来实现这种转换：charAt(int index)可以得到String类中某一位置上的字符，toCharArray()更可以将整个String类转换成一个char的数组。 对于所有的包装类都存在一个名为toString()的方法可以将其转换成对应的String类，而对于整型类和长整型类，还可以使用toBinaryString(int i)、toHexString(int i)、toOctalString(int i)分别以二进制、十六进制和八进制的形式进行到String类的转换。&nbsp; </p>
<p>五、将字符型直接做为数值转换为其它数据类型&nbsp; </p>
<p>将字符型变量转换为数值型变量实际上有两种对应关系，在我们在第一部分所说的那种转换中，实际上是将其转换成对应的ASCII码，但是我们有时还需要另一种转换关系，例如，&#8216;1'就是指的数值1，而不是其ASCII码，对于这种转换，我们可以使用Character的getNumericValue(char ch)方法。&nbsp; </p>
<p>六、Date类与其它数据类型的相互转换&nbsp; </p>
<p>整型和Date类之间并不存在直接的对应关系，只是你可以使用int型为分别表示年、月、日、时、分、秒，这样就在两者之间建立了一个对应关系，在作这种转换时，你可以使用Date类构造函数的三种形式：&nbsp; </p>
<p>Date(int year, int month, int date)：以int型表示年、月、日&nbsp; </p>
<p>Date(int year, int month, int date, int hrs, int min)：以int型表示年、月、日、时、分&nbsp; </p>
<p>Date(int year, int month, int date, int hrs, int min, int sec)：以int型表示年、月、日、时、分、秒&nbsp; </p>
<p>在长整型和Date类之间有一个很有趣的对应关系，就是将一个时间表示为距离格林尼治标准时间 </p>
<p>1970年1月1日0时0分0秒的毫秒数。对于这种对应关系，Date类也有其相应的构造函数：Date(long date) 获取Date类中的年、月、日、时、分、秒以及星期你可以使用Date类的getYear()、getMonth()、getDate()、getHours()、getMinutes()、getSeconds()、getDay()方法，你也可以将其理解为将Date类转换成int。而Date类的getTime()方法可以得到我们前面所说的一个时间对应的长整型数，与包装类一样，Date类也有一个toString()方法可以将其转换为String类。 </p>
<p>&nbsp;</p>
<p><br />
nsm8415 发表于 &gt;2006-6-15 20:44:44&nbsp;&nbsp; [全文] [评论] [引用] [推荐] [档案] [推给好友] [收藏到网摘] </p>
<p>&nbsp;</p>
<p>2006-6-15</p>
<p>java数据类型转换[转] </p>
<p><br />
一些初学JAVA的朋友可能会遇到JAVA的数据类型之间转换的苦恼，例如，整数和float,double型之间的转换，整数和String类型之间的转换，以及处理、显示时间方面的问题等。下面笔者就开发中的一些体会介绍给大家。 </p>
<p><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我们知道，Java的数据类型分为三大类，即布尔型、字符型和数值型，而其中数值型又分为整型和浮点型；相对于数据类型，Java的变量类型为布尔型boolean；字符型char；整型byte、short、int、long；浮点型float、double。其中四种整型变量和两种浮点型变量分别对应于不同的精度和范围。此外，我们还经常用到两种类变量，即String和Date。对于这些变量类型之间的相互转换在我们编程中经常要用到，在下面的论述中，我们将阐述如何实现这些转换。 </p>
<p><br />
1 数据类型转换的种类 </p>
<p>&nbsp;&nbsp;&nbsp; java数据类型的转换一般分三种,分别是: </p>
<p>&nbsp;&nbsp;&nbsp; (1). 简单数据类型之间的转换&nbsp; </p>
<p>&nbsp;&nbsp;&nbsp; (2). 字符串与其它数据类型的转换&nbsp; </p>
<p>&nbsp;&nbsp;&nbsp; (3). 其它实用数据类型转换 </p>
<p>&nbsp;&nbsp;&nbsp; 下面我们对这三种类型转换分别进行论述。 </p>
<p>2 简单数据类型之间的转换 </p>
<p>&nbsp;&nbsp;&nbsp; 在Java中整型、实型、字符型被视为简单数据类型，这些类型由低级到高级分别为 </p>
<p>(byte，short，char)--int--long--float--double </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 简单数据类型之间的转换又可以分为： </p>
<p>&nbsp;&nbsp;&nbsp; ●低级到高级的自动类型转换 </p>
<p>&nbsp;&nbsp;&nbsp; ●高级到低级的强制类型转换 </p>
<p>&nbsp;&nbsp;&nbsp; ●包装类过渡类型能够转换 </p>
<p><br />
2.1自动类型转换 </p>
<p>&nbsp;&nbsp;&nbsp; 低级变量可以直接转换为高级变量，笔者称之为自动类型转换,例如，下面的语句可以在Java中直接通过： </p>
<p><br />
byte b; </p>
<p>int i=b; </p>
<p>long l=b; </p>
<p>float f=b; </p>
<p>double d=b; </p>
<p><br />
&nbsp;&nbsp;&nbsp;&nbsp; 如果低级类型为char型，向高级类型（整型）转换时，会转换为对应ASCII码值，例如 </p>
<p><br />
&nbsp;&nbsp;&nbsp; char c='c';&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int i=c;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("output:"+i); </p>
<p><br />
输出：output:99; </p>
<p>对于byte,short,char三种类型而言，他们是平级的，因此不能相互自动转换，可以使用下述的强制类型转换。 </p>
<p><br />
short i=99 ; </p>
<p>char c=(char)i; </p>
<p>System.out.println("output:"+c); </p>
<p><br />
输出：output:c; </p>
<p>但根据笔者的经验，byte,short,int三种类型都是整型，因此如果操作整型数据时，最好统一使用int型。 </p>
<p><br />
2.2强制类型转换&nbsp; </p>
<p>&nbsp;&nbsp; 将高级变量转换为低级变量时，情况会复杂一些，你可以使用强制类型转换。即你必须采用下面这种语句格式： </p>
<p><br />
int i=99; </p>
<p>byte b=(byte)i; </p>
<p>char c=(char)i; </p>
<p>float f=(float)i; </p>
<p><br />
&nbsp;&nbsp;&nbsp;&nbsp; 可以想象，这种转换肯定可能会导致溢出或精度的下降，因此笔者并不推荐使用这种转换。 </p>
<p><br />
&nbsp;&nbsp; 2.3包装类过渡类型转换 </p>
<p>&nbsp;&nbsp;&nbsp; 在我们讨论其它变量类型之间的相互转换时，我们需要了解一下Java的包装类，所谓包装类，就是可以直接将简单类型的变量表示为一个类，在执行变量类型的相互转换时，我们会大量使用这些包装类。Java共有六个包装类，分别是Boolean、Character、Integer、Long、Float和Double，从字面上我们就可以看出它们分别对应于 boolean、char、int、long、float和double。而String和Date本身就是类。所以也就不存在什么包装类的概念了。 </p>
<p><br />
&nbsp;&nbsp;&nbsp; 在进行简单数据类型之间的转换（自动转换或强制转换）时，我们总是可以利用包装类进行中间过渡。 </p>
<p>&nbsp;&nbsp;&nbsp; 一般情况下，我们首先声明一个变量，然后生成一个对应的包装类，就可以利用包装类的各种方法进行类型转换了。例如： </p>
<p>&nbsp;&nbsp; 例1，当希望把float型转换为double型时： </p>
<p><br />
&nbsp;&nbsp; float f1=100.00f;&nbsp; </p>
<p>&nbsp;&nbsp; Float F1=new Float(f1);&nbsp; </p>
<p>&nbsp;&nbsp; double d1=F1.doubleValue();//F1.doubleValue()为Float类的返回double值型的方法 </p>
<p><br />
&nbsp;&nbsp;&nbsp; 当希望把double型转换为int型时： </p>
<p><br />
&nbsp;&nbsp;&nbsp; double d1=100.00; </p>
<p>&nbsp;&nbsp;&nbsp; Double D1=new Double(d1); </p>
<p>&nbsp;&nbsp;&nbsp; int i1=D1.intValue(); </p>
<p><br />
&nbsp;&nbsp;&nbsp; 当希望把int型转换为double型时，自动转换： </p>
<p><br />
&nbsp;&nbsp;&nbsp;&nbsp; int i1=200;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; double d1=i1; </p>
<p><br />
&nbsp;&nbsp;&nbsp;&nbsp; 简单类型的变量转换为相应的包装类，可以利用包装类的构造函数。即： </p>
<p>Boolean(boolean value)、Character(char value)、Integer(int value)、Long(long value)、Float(float value)、Double(double value) </p>
<p>而在各个包装类中，总有形为&#215;&#215;Value()的方法，来得到其对应的简单类型数据。利用这种方法，也可以实现不同数值型变量间的转换，例如，对于一个双精度实型类，intValue()可以得到其对应的整型变量，而doubleValue()可以得到其对应的双精度实型变量。 </p>
<p>&nbsp;&nbsp; 3 字符串型与其它数据类型的转换&nbsp; </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 通过查阅类库中各个类提供的成员方法可以看到，几乎从java.lang.Object类派生的所有类提供了toString()方法，即将该类转换为字符串。例如：Characrer,Integer,Float,Double,Boolean,Short等类的toString()方法toString()方法用于将字符、整数、浮点数、双精度数、逻辑数、短整型等类转换为字符串。如下所示： </p>
<p><br />
int i1=10; </p>
<p>float f1=3.14f </p>
<p>;double d1=3.1415926; </p>
<p><br />
Integer I1=new Integer(i1);//生成Integer类 </p>
<p>Float F1=new Float(f1); //生成Float类 </p>
<p>Double D1=new Double(d1); //生成Double类 </p>
<p><br />
//分别调用包装类的toString()方法转换为字符串 </p>
<p>String si1=I1.toString(); </p>
<p>String sf1=F1.toString(); </p>
<p>String sd1=D1.toString(); </p>
<p><br />
Sysytem.out.println("si1"+si1); </p>
<p>Sysytem.out.println("sf1"+sf1); </p>
<p>Sysytem.out.println("sd1"+sd1); </p>
<p><br />
五、将字符型直接做为数值转换为其它数据类型 </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 将字符型变量转换为数值型变量实际上有两种对应关系，在我们在第一部分所说的那种转换中，实际上是将其转换成对应的ASCII码，但是我们有时还需要另一种转换关系，例如，'1'就是指的数值1，而不是其ASCII码，对于这种转换，我们可以使用Character的getNumericValue(char ch)方法。 </p>
<p><br />
六、Date类与其它数据类型的相互转换 </p>
<p>&nbsp;&nbsp; 整型和Date类之间并不存在直接的对应关系，只是你可以使用int型为分别表示年、月、日、时、分、秒，这样就在两者之间建立了一个对应关系，在作这种转换时，你可以使用Date类构造函数的三种形式： </p>
<p>Date(int year, int month, int date)：以int型表示年、月、日 </p>
<p>Date(int year, int month, int date, int hrs, int min)：以int型表示年、月、日、时、分 </p>
<p>Date(int year, int month, int date, int hrs, int min, int sec)：以int型表示年、月、日、时、分、秒 </p>
<p><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在长整型和Date类之间有一个很有趣的对应关系，就是将一个时间表示为距离格林尼治标准时间1970年1月1日0时0分0秒的毫秒数。对于这种对应关系，Date类也有其相应的构造函数：Date(long date) </p>
<p>获取Date类中的年、月、日、时、分、秒以及星期你可以使用Date类的getYear()、getMonth()、getDate()、getHours()、getMinutes()、getSeconds()、getDay()方法，你也可以将其理解为将Date类转换成int。 </p>
<p>而Date类的getTime()方法可以得到我们前面所说的一个时间对应的长整型数，与包装类一样，Date类也有一个toString()方法可以将其转换为String类。 </p>
<p>有时我们希望得到Date的特定格式，例如20020324，我们可以使用以下方法，首先在文件开始引入， </p>
<p><br />
import java.text.SimpleDateFormat; </p>
<p>import java.util.*; </p>
<p>java.util.Date date = new java.util.Date(); </p>
<p><br />
//如果希望得到YYYYMMDD的格式 </p>
<p>SimpleDateFormat sy1=new SimpleDateFormat("yyyyMMDD"; </p>
<p>String dateFormat=sy1.format(date); </p>
<p><br />
//如果希望分开得到年，月，日 </p>
<p>SimpleDateFormat sy=new SimpleDateFormat("yyyy"; </p>
<p>SimpleDateFormat sm=new SimpleDateFormat("MM"; </p>
<p>SimpleDateFormat sd=new SimpleDateFormat("dd"; </p>
<p>String syear=sy.format(date); </p>
<p>String smon=sm.format(date); </p>
<p>String sday=sd.format(date); <br />
&nbsp;<br />
</p>
<img src ="http://www.blogjava.net/joaquin25/aggbug/165215.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/joaquin25/" target="_blank">joaquin25</a> 2007-12-04 15:30 <a href="http://www.blogjava.net/joaquin25/articles/165215.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>