﻿<?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-nbtymm-随笔分类-Java2SE相关</title><link>http://www.blogjava.net/nbtymm/category/11242.html</link><description>&lt;/br&gt;&lt;a href="http://www.fastonlineusers.com"&gt;&lt;b&gt;&lt;font color=red&gt;共有&lt;script src=http://fastonlineusers.com/online.php?d=bluedavy.blogjava.net&gt;&lt;/script&gt;人在同时阅读此Blog&lt;/font&gt;&lt;/b&gt;&lt;/a&gt;</description><language>zh-cn</language><lastBuildDate>Fri, 02 Mar 2007 06:44:41 GMT</lastBuildDate><pubDate>Fri, 02 Mar 2007 06:44:41 GMT</pubDate><ttl>60</ttl><item><title>解决运行eclipse内存不足的问题</title><link>http://www.blogjava.net/nbtymm/archive/2007/03/02/101440.html</link><dc:creator>nbt</dc:creator><author>nbt</author><pubDate>Fri, 02 Mar 2007 04:08:00 GMT</pubDate><guid>http://www.blogjava.net/nbtymm/archive/2007/03/02/101440.html</guid><wfw:comment>http://www.blogjava.net/nbtymm/comments/101440.html</wfw:comment><comments>http://www.blogjava.net/nbtymm/archive/2007/03/02/101440.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/nbtymm/comments/commentRss/101440.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/nbtymm/services/trackbacks/101440.html</trackback:ping><description><![CDATA[    最近在用eclipse的时候，过上一会老弹出一个对话框，提示内存不足（大意），找了好多资料都没有解决，最近在eclipse的官方网站上找到了其解决的办法，希望对像我一样的朋友有帮助，解决方法如下，<br />在桌面上建一个启动eclipse的快捷方式，在该快捷方式上单击右键，在常规标签的目标中加入下面的内容：<br /><br />E:\eclipse\eclipse.exe -clean -vmargs -Xms128M -Xmx512M -XX:PermSize=64M -XX:MaxPermSize=128M，其中“E:\eclipse\eclipse.exe” 是我eclipse的路径。<br /><br />然后重启你的eclipse试试！ <img src ="http://www.blogjava.net/nbtymm/aggbug/101440.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/nbtymm/" target="_blank">nbt</a> 2007-03-02 12:08 <a href="http://www.blogjava.net/nbtymm/archive/2007/03/02/101440.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JAR 文件是什么？</title><link>http://www.blogjava.net/nbtymm/archive/2006/08/09/62597.html</link><dc:creator>nbt</dc:creator><author>nbt</author><pubDate>Wed, 09 Aug 2006 08:26:00 GMT</pubDate><guid>http://www.blogjava.net/nbtymm/archive/2006/08/09/62597.html</guid><wfw:comment>http://www.blogjava.net/nbtymm/comments/62597.html</wfw:comment><comments>http://www.blogjava.net/nbtymm/archive/2006/08/09/62597.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/nbtymm/comments/commentRss/62597.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/nbtymm/services/trackbacks/62597.html</trackback:ping><description><![CDATA[
		<br />JAR 文件格式以流行的 ZIP 文件格式为基础，用于将许多个文件聚集为一个文件。与 ZIP 文件不同的是，JAR 文件不仅用于压缩和发布，而且还用于部署和封装库、组件和插件程序，并可被像编译器和 JVM 这样的工具直接使用。在 JAR 中包含特殊的文件，如 manifests 和部署描述符，用来指示工具如何处理特定的 JAR。 <br />一个 JAR 文件可以用于：<br /><br />□ 用于发布和使用类库 <br /><br />□ 作为应用程序和扩展的构建单元 <br /><br />□ 作为组件、applet 或者插件程序的部署单位 <br /><br />□ 用于打包与组件相关联的辅助资源 <br />JAR 文件格式提供了许多优势和功能，其中很多是传统的压缩格式如 ZIP 或者 TAR 所没有提供的。它们包括：<br />☆ 安全性。 可以对 JAR 文件内容加上数字化签名。这样，能够识别签名的工具就可以有选择地为您授予软件安全特权，这是其他文件做不到的，它还可以检测代码是否被篡改过。<br />☆ 减少下载时间。 如果一个 applet 捆绑到一个 JAR 文件中，那么浏览器就可以在一个 HTTP 事务中下载这个 applet 的类文件和相关的资源，而不是对每一个文件打开一个新连接。<br />☆ 压缩。JAR 格式允许您压缩文件以提高存储效率。<br />☆ 传输平台扩展。 Java 扩展框架(Java Extensions Framework)提供了向 Java 核心平台添加功能的方法，这些扩展是用 JAR 文件打包的(Java 3D 和 JavaMail 就是由 Sun 开发的扩展例子)。<br />☆ 包密封。 存储在 JAR 文件中的包可以选择进行密封，以增强版本一致性和安全性。密封一个包意味着包中的所有类都必须在同一 JAR 文件中找到。<br />☆ 包版本控制。 一个 JAR 文件可以包含有关它所包含的文件的数据，如厂商和版本信息。<br />☆ 可移植性。 处理 JAR 文件的机制是 Java 平台核心 API 的标准部分。 <br />压缩的和未压缩的 JAR<br /><br />jar 工具在默认情况下压缩文件。未压缩的 JAR 文件一般可以比压缩过的 JAR 文件更快地装载，因为在装载过程中要解压缩文件，但是未压缩的文件在网络上的下载时间可能更长。<br />META-INF 目录<br /><br />大多数 JAR 文件包含一个 META-INF 目录，它用于存储包和扩展的配置数据，如安全性和版本信息。Java 2 平台识别并解释 META-INF 目录中的下述文件和目录，以便配置应用程序、扩展和类装载器：<br />☆ MANIFEST.MF。 这个 manifest 文件定义了与扩展和包相关的数据。<br />☆ INDEX.LIST。 这个文件由 jar 工具的新选项 -i 生成，它包含在应用程序或者扩展中定义的包的位置信息。它是 JarIndex 实现的一部分，并由类装载器用于加速类装载过程。<br />☆ xxx.SF。 这是 JAR 文件的签名文件。占位符 xxx 标识了签名者。<br />☆ xxx.DSA。 与签名文件相关联的签名程序块文件，它存储了用于签名 JAR 文件的公共签名。 <br />jar 工具<br /><br />为了用 JAR 文件执行基本的任务，要使用作为Java Development Kit 的一部分提供的 Java Archive Tool (jar 工具)。用 jar 命令调用 jar 工具。表 1 显示了一些常见的应用：<br />表 1. 常见的 jar 工具用法 <br />功能    命令<br />用一个单独的文件创建一个 JAR 文件    jar cf jar-file input-file...<br />用一个目录创建一个 JAR 文件    jar cf jar-file dir-name<br />创建一个未压缩的 JAR 文件    jar cf0 jar-file dir-name<br />更新一个 JAR 文件    jar uf jar-file input-file...<br />查看一个 JAR 文件的内容    jar tf jar-file<br />提取一个 JAR 文件的内容    jar xf jar-file<br />从一个 JAR 文件中提取特定的文件    jar xf jar-file archived-file...<br />运行一个打包为可执行 JAR 文件的应用程序    java -jar app.jar<br />可执行的 JAR<br /><br />一个可执行的 jar 文件是一个自包含的 Java 应用程序，它存储在特别配置的JAR 文件中，可以由 JVM 直接执行它而无需事先提取文件或者设置类路径。要运行存储在非可执行的 JAR 中的应用程序，必须将它加入到您的类路径中，并用名字调用应用程序的主类。但是使用可执行的 JAR 文件，我们可以不用提取它或者知道主要入口点就可以运行一个应用程序。可执行 JAR 有助于方便发布和执行 Java 应用程序。<br />创建可执行 JAR<br /><br />创建一个可执行 JAR 很容易。首先将所有应用程序代码放到一个目录中。假设应用程序中的主类是 com.mycompany.myapp.Sample。您要创建一个包含应用程序代码的 JAR 文件并标识出主类。为此，在某个位置(不是在应用程序目录中)创建一个名为 manifest 的文件，并在其中加入以下一行：<br />Main-Class: com.mycompany.myapp.Sample<br />然后，像这样创建 JAR 文件：<br />jar cmf manifest ExecutableJar.jar application-dir<br />所要做的就是这些了 -- 现在可以用 java -jar 执行这个 JAR 文件 ExecutableJar.jar。<br />一个可执行的 JAR 必须通过 menifest 文件的头引用它所需要的所有其他从属 JAR。如果使用了 -jar 选项，那么环境变量 CLASSPATH 和在命令行中指定的所有类路径都被 JVM 所忽略。<br />启动可执行 JAR<br /><br />既然我们已经将自己的应用程序打包到了一个名为 ExecutableJar.jar 的可执行 JAR 中了，那么我们就可以用下面的命令直接从文件启动这个应用程序：<br />java -jar ExecutableJar.jar<br />包密封<br /><br />密封 JAR 文件中的一个包意味着在这个包中定义的所有类都必须在同一个 JAR 文件中找到。这使包的作者可以增强打包类之间的版本一致性。密封还提供了防止代码篡改的手段。<br />要密封包，需要在 JAR 的 manifest 文件中为包添加一个 Name 头，然后加上值为“true”的 Sealed 头。与可执行的 JAR 一样，可以在创建 JAR 时，通过指定一个具有适当头元素的 manifest 文件密封一个 JAR，如下所示：<br />Name: com/samplePackage/<br /><br />Sealed: true<br />Name 头标识出包的相对路径名。它以一个“/”结束以与文件名区别。在 Name 头后面第一个空行之前的所有头都作用于在 Name 头中指定的文件或者包。在上述例子中，因为 Sealed 头出现在 Name 头后并且中间没有空行，所以 Sealed 头将被解释为只应用到包 com/samplePackage 上。<br />如果试图从密封包所在的 JAR 文件以外的其他地方装载密封包中的一个类，那么 JVM 将抛出一个 SecurityException。<br />扩展打包<br /><br />扩展为 Java 平台增加了功能，在 JAR 文件格式中已经加入了扩展机制。扩展机制使得 JAR 文件可以通过 manifest 文件中的 Class-Path 头指定所需要的其他 JAR 文件。<br />假设 extension1.jar 和 extension2.jar 是同一个目录中的两个 JAR 文件，extension1.jar 的 manifest 文件包含以下头：<br />Class-Path: extension2.jar<br />这个头表明 extension2.jar 中的类是 extension1.jar 中的类的扩展类。extension1.jar 中的类可以调用 extension2.jar 中的类，并且不要求 extension2.jar 处在类路径中。<br />在装载使用扩展机制的 JAR 时，JVM 会高效而自动地将在Class-Path 头中引用的 JAR 添加到类路径中。不过，扩展 JAR 路径被解释为相对路径，所以一般来说，扩展 JAR 必须存储在引用它的 JAR 所在的同一目录中。<br />例如，假设类 ExtensionClient 引用了类 ExtensionDemo,它捆绑在一个名为 ExtensionClient.jar 的 JAR 文件中，而类 ExtensionDemo 则捆绑在 ExtensionDemo.jar 中。为了使 ExtensionDemo.jar 可以成为扩展，必须将 ExtensionDemo.jar 列在 ExtensionClient.jar 的 manifest 的 Class-Path 头中，如下所示：<br />Manifest-Version: 1.0<br /><br />Class-Path: ExtensionDemo.jar<br />在这个 manifest 中 Class-Path 头的值是没有指定路径的 ExtensionDemo.jar，表明 ExtensionDemo.jar 与 ExtensionClient JAR 文件处在同一目录中。<br />JAR 文件中的安全性<br /><br />JAR 文件可以用 jarsigner 工具或者直接通过 java.security API 签名。一个签名的 JAR 文件与原来的 JAR 文件完全相同，只是更新了它的 manifest，并在 META-INF 目录中增加了两个文件，一个签名文件和一个签名块文件。<br />JAR 文件是用一个存储在 Keystore 数据库中的证书签名的。存储在 keystore 中的证书有密码保护，必须向 jarsigner 工具提供这个密码才能对 JAR 文件签名。<br /> <br /><br />图 1. Keystore 数据库<br />JAR 的每一位签名者都由在 JAR 文件的 META-INF 目录中的一个具有 .SF 扩展名的签名文件表示。这个文件的格式类似于 manifest 文件 -- 一组 RFC-822 头。如下所示，它的组成包括一个主要部分，它包括了由签名者提供的信息、但是不特别针对任何特定的 JAR 文件项，还有一系列的单独的项，这些项也必须包含在 menifest 文件中。在验证一个签名的 JAR 时，将签名文件的摘要值与对 JAR 文件中的相应项计算的摘要值进行比较。<br />清单 1. 签名 JAR 中的 Manifest 和 signature 文件<br />Contents of signature file META-INF/MANIFEST.MF<br /><br />Manifest-Version: 1.0<br /><br />Created-By: 1.3.0 (Sun Microsystems Inc.)<br /><br />Name: Sample.java<br /><br />SHA1-Digest: 3+DdYW8INICtyG8ZarHlFxX0W6g=<br /><br />Name: Sample.class<br /><br />SHA1-Digest: YJ5yQHBZBJ3SsTNcHJFqUkfWEmI=<br /><br />Contents of signature file META-INF/JAMES.SF<br /><br />Signature-Version: 1.0<br /><br />SHA1-Digest-Manifest: HBstZOJBuuTJ6QMIdB90T8sjaOM=<br /><br />Created-By: 1.3.0 (Sun Microsystems Inc.)<br /><br />Name: Sample.java<br /><br />SHA1-Digest: qipMDrkurQcKwnyIlI3Jtrnia8Q=<br /><br />Name: Sample.class<br /><br />SHA1-Digest: pT2DYby8QXPcCzv2NwpLxd8p4G4=<br />数字签名<br /><br />一个数字签名是.SF 签名文件的已签名版本。数字签名文件是二进制文件，并且与 .SF 文件有相同的文件名，但是扩展名不同。根据数字签名的类型 -- RSA、DSA 或者 PGP -- 以及用于签名 JAR 的证书类型而有不同的扩展名。<br />Keystore<br /><br />要签名一个 JAR 文件，必须首先有一个私钥。私钥及其相关的公钥证书存储在名为 keystores 的、有密码保护的数据库中。JDK 包含创建和修改 keystores 的工具。keystore 中的每一个密钥都可以用一个别名标识，它通常是拥有这个密钥的签名者的名字。<br />所有 keystore 项(密钥和信任的证书项)都是用唯一别名访问的。别名是在用 keytool -genkey 命令生成密钥对(公钥和私钥)并在 keystore 中添加项时指定的。之后的 keytool 命令必须使用同样的别名引用这一项。<br />例如，要用别名“james”生成一个新的公钥/私钥对并将公钥包装到自签名的证书中，要使用下述命令：<br />keytool -genkey -alias james -keypass jamespass <br /><br />-validity 80 -keystore jamesKeyStore <br /><br />-storepass jamesKeyStorePass<br />这个命令序列指定了一个初始密码“jamespass”，后续的命令在访问 keystore “jamesKeyStore”中与别名“james”相关联的私钥时，就需要这个密码。如果 keystore“jamesKeyStore”不存在，则 keytool 会自动创建它。<br />jarsigner 工具<br /><br />jarsigner 工具使用 keystore 生成或者验证 JAR 文件的数字签名。<br />假设像上述例子那样创建了 keystore “jamesKeyStore”，并且它包含一个别名为“james”的密钥，可以用下面的命令签名一个 JAR 文件：<br />jarsigner -keystore jamesKeyStore -storepass jamesKeyStorePass <br /><br />-keypass jamespass -signedjar SSample.jar Sample.jar james<br />这个命令用密码“jamesKeyStorePass”从名为“jamesKeyStore”的 keystore 中提出别名为“james”、密码为“jamespass”的密钥，并对 Sample.jar 文件签名、创建一个签名的 JAR -- SSample.jar。<br />jarsigner 工具还可以验证一个签名的 JAR 文件，这种操作比签名 JAR 文件要简单得多，只需执行以下命令：<br />jarsigner -verify SSample.jar<br />如果签名的 JAR 文件没有被篡改过，那么 jarsigner 工具就会告诉您 JAR 通过验证了。否则，它会抛出一个 SecurityException， 表明哪些文件没有通过验证。<br />还可以用 java.util.jar 和 java.security API 以编程方式签名 JAR(有关细节参阅参考资料)。也可以使用像 Netscape Object Signing Tool 这样的工具。<br />JAR 索引<br /><br />如果一个应用程序或者 applet 捆绑到多个 JAR 文件中，那么类装载器就使用一个简单的线性搜索算法搜索类路径中的每一个元素，这使类装载器可能要下载并打开许多个 JAR 文件，直到找到所要的类或者资源。如果类装载器试图寻找一个不存在的资源，那么在应用程序或者 applet 中的所有 JAR 文件都会下载。对于大型的网络应用程序和 applet，这会导致启动缓慢、响应迟缓并浪费带宽。<br />从 JDK 1.3 以后，JAR 文件格式开始支持索引以优化网络应用程序中类的搜索过程，特别是 applet。JarIndex 机制收集在 applet 或者应用程序中定义的所有 JAR 文件的内容，并将这些信息存储到第一个 JAR 文件中的索引文件中。下载了第一个 JAR 文件后，applet 类装载器将使用收集的内容信息高效地装载 JAR 文件。这个目录信息存储在根 JAR 文件的 META-INF 目录中的一个名为 INDEX.LIST 的简单文本文件中。<br />创建一个 JarIndex<br /><br />可以通过在 jar 命令中指定 -i 选项创建一个 JarIndex。假设我们的目录结构如下图所示：<br /> <br /><br />图 2. JarIndex<br />您将使用下述命令为 JarIndex_Main.jar、JarIndex_test.jar 和 JarIndex_test1.jar 创建一个索引文件：<br />jar -i JarIndex_Main.jar JarIndex_test.jar SampleDir/JarIndex_test1.jar <br />INDEX.LIST 文件的格式很简单，包含每个已索引的 JAR 文件中包含的包或者类的名字，如清单 2 所示：<br />清单 2. JarIndex INDEX.LIST 文件示例<br />JarIndex-Version: 1.0<br /><br />JarIndex_Main.jar<br /><br />sp<br /><br />JarIndex_test.jar<br /><br />Sample<br /><br />SampleDir/JarIndex_test1.jar<br /><br />org<br /><br />org/apache<br /><br />org/apache/xerces<br /><br />org/apache/xerces/framework<br /><br />org/apache/xerces/framework/xml4j<br />结束语 <br /><br />JAR 格式远远超出了一种压缩格式，它有许多可以改进效率、安全性和组织 Java 应用程序的功能。因为这些功能已经建立在核心平台 -- 包括编译器和类装载器 -- 中了，所以开发人员可以利用 JAR 文件格式的能力简化和改进开发和部署过程。<br /><img src ="http://www.blogjava.net/nbtymm/aggbug/62597.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/nbtymm/" target="_blank">nbt</a> 2006-08-09 16:26 <a href="http://www.blogjava.net/nbtymm/archive/2006/08/09/62597.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JAR文件包及jar命令详解</title><link>http://www.blogjava.net/nbtymm/archive/2006/08/09/62595.html</link><dc:creator>nbt</dc:creator><author>nbt</author><pubDate>Wed, 09 Aug 2006 08:23:00 GMT</pubDate><guid>http://www.blogjava.net/nbtymm/archive/2006/08/09/62595.html</guid><wfw:comment>http://www.blogjava.net/nbtymm/comments/62595.html</wfw:comment><comments>http://www.blogjava.net/nbtymm/archive/2006/08/09/62595.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/nbtymm/comments/commentRss/62595.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/nbtymm/services/trackbacks/62595.html</trackback:ping><description><![CDATA[
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
								</td>
						</tr>
						<!-- end of article title -->
						<tr>
								<td valign="top" align="middle" width="100%">
										<!--start of article content -->
										<table width="98%" border="0">
												<tbody>
														<tr>
																<td class="text" align="left" width="100%">常常在网上看到有人询问：如何把 java 程序编译成 .exe 文件。通常回答只有两种，一种是制作一个可执行的 JAR 文件包，然后就可以像.chm 文档一样双击运行了；而另一种是使用 JET 来进行 编译。但是 JET 是要用钱买的，而且据说 JET 也不是能把所有的 Java 程序都编译成执行文件，性能也要打些折扣。所以，使用制作可执行 JAR 文件包的方法就是最佳选择了，何况它还能保持 Java 的跨平台特性。 <br /><br />　　下面就来看看什么是 JAR 文件包吧： <br /><br />　　1. JAR 文件包 <br /><br />　　JAR 文件就是 Java Archive File，顾名思意，它的应用是与 Java 息息相关的，是 Java 的一种文档格式。JAR 文件非常类似 ZIP 文件??准确的说，它就是 ZIP 文件，所以叫它文件包。JAR 文件与 ZIP 文件唯一的区别就是在 JAR 文件的内容中，包含了一个 META-INF/MANIFEST.MF 文件，这个文件是在生成 JAR 文件的时候自动创建的。举个例子，如果我们具有如下目录结构的一些文件： <br /><br />　　== <br /><br />　　`-- test <br /><br />　　　 `-- Test.class <br /><br />　　把它压缩成 ZIP 文件 test.zip，则这个 ZIP 文件的内部目录结构为： <br /><br />　　test.zip <br /><br />　　`-- test <br /><br />　　　 `-- Test.class <br /><br />　　如果我们使用 JDK 的 jar 命令把它打成 JAR 文件包 test.jar，则这个 JAR 文件的内部目录结构为： <br /><br />　　test.jar <br /><br />　　|-- META-INF <br /><br />　　|　 `-- MANIFEST.MF <br /><br />　　`-- test <br /><br />　　　　`--Test.class <br /><br />　　2. 创建可执行的 JAR 文件包 <br /><br />　　制作一个可执行的 JAR 文件包来发布你的程序是 JAR 文件包最典型的用法。 <br /><br />　　Java 程序是由若干个 .class 文件组成的。这些 .class 文件必须根据它们所属的包不同而分级分目录存放；运行前需要把所有用到的包的根目录指定给 CLASSPATH 环境变量或者 java 命令的 -cp 参数；运行时还要到控制台下去使用 java 命令来运行，如果需要直接双击运行必须写 Windows 的批处理文件 (.bat) 或者 Linux 的 Shell 程序。因此，许多人说，Java 是一种方便开发者苦了用户的程序设计语言。 <br /><br />　　其实不然，如果开发者能够制作一个可执行的 JAR 文件包交给用户，那么用户使用起来就方便了。在 Windows 下安装 JRE (Java Runtime Environment) 的时候，安装文件会将 .jar 文件映射给 javaw.exe 打开。那么，对于一个可执行的 JAR 文件包，用户只需要双击它就可以运行程序了，和阅读 .chm 文档一样方便 (.chm 文档默认是由 hh.exe 打开的)。那么，现在的关键，就是如何来创建这个可执行的 JAR 文件包。 <br /><br />　　创建可执行的 JAR 文件包，需要使用带 cvfm 参数的 jar 命令，同样以上述 test 目录为例，命令如下： <br /><br />jar cvfm test.jar manifest.mf test <br /><br />　　这里 test.jar 和 manifest.mf 两个文件，分别是对应的参数 f 和 m，其重头戏在 manifest.mf。因为要创建可执行的 JAR 文件包，光靠指定一个 manifest.mf 文件是不够的，因为 MANIFEST 是 JAR 文件包的特征，可执行的 JAR 文件包和不可执行的 JAR 文件包都包含 MANIFEST。关键在于可执行 JAR 文件包的 MANIFEST，其内容包含了 Main-Class 一项。这在 MANIFEST 中书写格式如下： <br /><br />　　Main-Class: 可执行主类全名(包含包名) <br /><br />　　例如，假设上例中的 Test.class 是属于 test 包的，而且是可执行的类 (定义了 public static void main(String[]) 方法)，那么这个 manifest.mf 可以编辑如下： <br /><br />Main-Class: test.Test &lt;回车&gt; <br /><br />　　这个 manifest.mf 可以放在任何位置，也可以是其它的文件名，只需要有 Main-Class: test.Test 一行，且该行以一个回车符结束即可。创建了 manifest.mf 文件之后，我们的目录结构变为： <br /><br />　　== <br /><br />　　|-- test <br /><br />　　|　 `-- Test.class <br /><br />　　`-- manifest.mf <br /><br />　　这时候，需要到 test 目录的上级目录中去使用 jar 命令来创建 JAR 文件包。也就是在目录树中使用“==”表示的那个目录中，使用如下命令： <br /><br />jar cvfm test.jar manifest.mf test <br /><br />　　之后在“==”目录中创建了 test.jar，这个 test.jar 就是执行的 JAR 文件包。运行时只需要使用 java -jar test.jar 命令即可。 <br /><br />　　需要注意的是，创建的 JAR 文件包中需要包含完整的、与 Java 程序的包结构对应的目录结构，就像上例一样。而 Main-Class 指定的类，也必须是完整的、包含包路径的类名，如上例的 test.Test；而且在没有打成 JAR 文件包之前可以使用 java &lt;类名&gt; 来运行这个类，即在上例中 java test.Test 是可以正确运行的 (当然要在 CLASSPATH 正确的情况下)。 <br />　3. jar 命令详解 <br /><br />　　jar 是随 JDK 安装的，在 JDK 安装目录下的 bin 目录中，Windows 下文件名为 jar.exe，Linux 下文件名为 jar。它的运行需要用到 JDK 安装目录下 lib 目录中的 tools.jar 文件。不过我们除了安装 JDK 什么也不需要做，因为 SUN 已经帮我们做好了。我们甚至不需要将 tools.jar 放到 CLASSPATH 中。 <br /><br />　　使用不带任何的 jar 命令我们可以看到 jar 命令的用法如下： <br /><br />　　jar {ctxu}[vfm0M] [jar-文件] [manifest-文件] [-C 目录] 文件名 ... <br /><br />　　其中 {ctxu} 是 jar 命令的子命令，每次 jar 命令只能包含 ctxu 中的一个，它们分别表示： <br /><br />　　　-c　创建新的 JAR 文件包 <br /><br />　　　-t　列出 JAR 文件包的内容列表 <br /><br />　　　-x　展开 JAR 文件包的指定文件或者所有文件 <br /><br />　　　-u　更新已存在的 JAR 文件包 (添加文件到 JAR 文件包中) <br /><br />　　　　　[vfm0M] 中的选项可以任选，也可以不选，它们是 jar 命令的选项参数 <br /><br />　　　-v　生成详细报告并打印到标准输出 <br /><br />　　　-f　指定 JAR 文件名，通常这个参数是必须的 <br /><br />　　　-m　指定需要包含的 MANIFEST 清单文件 <br /><br />　　　-0　只存储，不压缩，这样产生的 JAR 文件包会比不用该参数产生的体积大，但速度更快 <br /><br />　　　-M　不产生所有项的清单（MANIFEST〕文件，此参数会忽略 -m 参数 <br /><br />　　　　　[jar-文件] 即需要生成、查看、更新或者解开的 JAR 文件包，它是 -f 参数的附属参数 <br /><br />　　　　　[manifest-文件] 即 MANIFEST 清单文件，它是 -m 参数的附属参数 <br /><br />　　　　　[-C 目录] 表示转到指定目录下去执行这个 jar 命令的操作。它相当于先使用 cd 命令转该目录下再执行不带 -C 参数的 jar 命令，它只能在创建和更新 JAR 文件包的时候可用。　　 <br /><br />　　文件名 ... 指定一个文件/目录列表，这些文件/目录就是要添加到 JAR 文件包中的文件/目录。如果指定了目录，那么 jar 命令打包的时候会自动把该目录中的所有文件和子目录打入包中。 <br /><br />　　下面举一些例子来说明 jar 命令的用法： <br /><br />　　1) jar cf test.jar test <br /><br />　　该命令没有执行过程的显示，执行结果是在当前目录生成了 test.jar 文件。如果当前目录已经存在 test.jar，那么该文件将被覆盖。 <br /><br />　　2) jar cvf test.jar test <br /><br />　　该命令与上例中的结果相同，但是由于 v 参数的作用，显示出了打包过程，如下： <br /><br />　　标明清单(manifest) <br /><br />　　增加：test/(读入= 0) (写出= 0)(存储了 0%) <br /><br />　　增加：test/Test.class(读入= 7) (写出= 6)(压缩了 14%) <br /><br />　　3) jar cvfM test.jar test <br /><br />　　该命令与 2) 结果类似，但在生成的 test.jar 中没有包含 META-INF/MANIFEST 文件，打包过程的信息也略有差别： <br /><br />　　增加：test/(读入= 0) (写出= 0)(存储了 0%) <br /><br />　　增加：test/Test.class(读入= 7) (写出= 6)(压缩了 14%) <br /><br />　　4) jar cvfm test.jar manifest.mf test <br /><br />　　运行结果与 2) 相似，显示信息也相同，只是生成 JAR 包中的 META-INF/MANIFEST 内容不同，是包含了 manifest.mf 的内容 <br /><br />　　5) jar tf test.jar <br /><br />　　在 test.jar 已经存在的情况下，可以查看 test.jar 中的内容，如对于 2) 和 3) 生成的 test.jar 分别应该此命令，结果如下； <br /><br />　　对于 2) <br /><br />　　META-INF/ <br /><br />　　META-INF/MANIFEST.MF <br /><br />　　test/ <br /><br />　　test/Test.class <br /><br />　　对于 3) <br /><br />　　test/ <br /><br />　　test/Test.class <br /><br />　　6) jar tvf test.jar <br /><br />　　除显示 5) 中显示的内容外，还包括包内文件的详细信息，如： <br /><br />　　0 Wed Jun 19 15:39:06 GMT 2002 META-INF/ <br /><br />　　86 Wed Jun 19 15:39:06 GMT 2002 META-INF/MANIFEST.MF <br /><br />　　0 Wed Jun 19 15:33:04 GMT 2002 test/ <br /><br />　　7 Wed Jun 19 15:33:04 GMT 2002 test/Test.class <br /><br />　　7) jar xf test.jar <br /><br />　　解开 test.jar 到当前目录，不显示任何信息，对于 2) 生成的 test.jar，解开后的目录结构如下： <br /><br />　　== <br /><br />　　|-- META-INF <br /><br />　　|　 `-- MANIFEST <br /><br />　　`-- test <br /><br />　　　　`--Test.class <br /><br />jar xvf test.jar <br /><br />　　运行结果与 7) 相同，对于解压过程有详细信息显示，如： <br /><br />　　创建：META-INF/ <br /><br />　　展开：META-INF/MANIFEST.MF <br /><br />　　创建：test/ <br /><br />　　展开：test/Test.class <br /><br />　　9) jar uf test.jar manifest.mf <br /><br />　　在 test.jar 中添加了文件 manifest.mf，此使用 jar tf 来查看 test.jar 可以发现 test.jar 中比原来多了一个 manifest。这里顺便提一下，如果使用 -m 参数并指定 manifest.mf 文件，那么 manifest.mf 是作为清单文件 MANIFEST 来使用的，它的内容会被添加到 MANIFEST 中；但是，如果作为一般文件添加到 JAR 文件包中，它跟一般文件无异。 <br /><br />　　10) jar uvf test.jar manifest.mf <br /><br />　　与 9) 结果相同，同时有详细信息显示，如： <br /><br />　　增加：manifest.mf(读入= 17) (写出= 19)(压缩了 -11%) <br /><br />　　4. 关于 JAR 文件包的一些技巧 <br /><br />　　1) 使用 unzip 来解压 JAR 文件 <br /><br />　　在介绍 JAR 文件的时候就已经说过了，JAR 文件实际上就是 ZIP 文件，所以可以使用常见的一些解压 ZIP 文件的工具来解压 JAR 文件，如 Windows 下的 WinZip、WinRAR 等和 Linux 下的 unzip 等。使用 WinZip 和 WinRAR 等来解压是因为它们解压比较直观，方便。而使用 unzip，则是因为它解压时可以使用 -d 参数指定目标目录。 <br /><br />　　在解压一个 JAR 文件的时候是不能使用 jar 的 -C 参数来指定解压的目标的，因为 -C 参数只在创建或者更新包的时候可用。那么需要将文件解压到某个指定目录下的时候就需要先将这具 JAR 文件拷贝到目标目录下，再进行解压，比较麻烦。如果使用 unzip，就不需要这么麻烦了，只需要指定一个 -d 参数即可。如： <br /><br />　　unzip test.jar -d dest/ <br /><br />　　2) 使用 WinZip 或者 WinRAR 等工具创建 JAR 文件 <br /><br />　　上面提到 JAR 文件就是包含了 META-INF/MANIFEST 的 ZIP 文件，所以，只需要使用 WinZip、WinRAR 等工具创建所需要 ZIP 压缩包，再往这个 ZIP 压缩包中添加一个包含 MANIFEST 文件的 META-INF 目录即可。对于使用 jar 命令的 -m 参数指定清单文件的情况，只需要将这个 MANIFEST 按需要修改即可。 <br /><br />　　3) 使用 jar 命令创建 ZIP 文件 <br /><br />　　有些 Linux 下提供了 unzip 命令，但没有 zip 命令，所以需要可以对 ZIP 文件进行解压，即不能创建 ZIP 文件。如要创建一个 ZIP 文件，使用带 -M 参数的 jar 命令即可，因为 -M 参数表示制作 JAR 包的时候不添加 MANIFEST 清单，那么只需要在指定目标 JAR 文件的地方将 .jar 扩展名改为 .zip 扩展名，创建的就是一个不折不扣的 ZIP 文件了，如将上一节的第 3) 个例子略作改动： <br /><br />　　jar cvfM test.zip test<br /></td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
<img src ="http://www.blogjava.net/nbtymm/aggbug/62595.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/nbtymm/" target="_blank">nbt</a> 2006-08-09 16:23 <a href="http://www.blogjava.net/nbtymm/archive/2006/08/09/62595.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java enum 枚举类</title><link>http://www.blogjava.net/nbtymm/archive/2006/08/07/62115.html</link><dc:creator>nbt</dc:creator><author>nbt</author><pubDate>Mon, 07 Aug 2006 01:38:00 GMT</pubDate><guid>http://www.blogjava.net/nbtymm/archive/2006/08/07/62115.html</guid><wfw:comment>http://www.blogjava.net/nbtymm/comments/62115.html</wfw:comment><comments>http://www.blogjava.net/nbtymm/archive/2006/08/07/62115.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/nbtymm/comments/commentRss/62115.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/nbtymm/services/trackbacks/62115.html</trackback:ping><description><![CDATA[(转自<a href="/dazuiba/archive/2006/08/04/j2se_enum.html">http://www.blogjava.net/dazuiba/archive/2006/08/04/j2se_enum.html</a>)<br /><br />1 定义在常量类中<br />    <br />    经常碰到要将枚举类当成常量使用的情况，这不仅可以将相关的常量定义到一个枚举类中，而且还可以利用枚举类强大而又灵活的功能，在加上编译器内置的支持，使得在eclipse下的编程更方便，引入的bug更少。<br />    一般规模的项目中都会用一个单独的类来定义系统中用到的常量，起码笔者经历的几个项目都是有此种做法，该做法的好处就是便于集中管理，虽然这违背类封装的原则，但鉴于其易用性，我们还是会常常这么做。<br />    例子：<br /><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /><span style="COLOR: #000000"><br /><img id="Codehighlighter1_29_1284_Open_Image" onclick="this.style.display='none'; Codehighlighter1_29_1284_Open_Text.style.display='none'; Codehighlighter1_29_1284_Closed_Image.style.display='inline'; Codehighlighter1_29_1284_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_29_1284_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_29_1284_Closed_Text.style.display='none'; Codehighlighter1_29_1284_Open_Image.style.display='inline'; Codehighlighter1_29_1284_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> SystemConstant </span><span id="Codehighlighter1_29_1284_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/images/dot.gif" /></span><span id="Codehighlighter1_29_1284_Open_Text"><span style="COLOR: #000000">{<br /><img id="Codehighlighter1_35_75_Open_Image" onclick="this.style.display='none'; Codehighlighter1_35_75_Open_Text.style.display='none'; Codehighlighter1_35_75_Closed_Image.style.display='inline'; Codehighlighter1_35_75_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_35_75_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_35_75_Closed_Text.style.display='none'; Codehighlighter1_35_75_Open_Image.style.display='inline'; Codehighlighter1_35_75_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span><span id="Codehighlighter1_35_75_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">/** */</span><span id="Codehighlighter1_35_75_Open_Text"><span style="COLOR: #008000">/**</span><span style="COLOR: #008000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />     * 金库　sourceortarget 系统相关<br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />     </span><span style="COLOR: #008000">*/</span></span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">final</span><span style="COLOR: #000000"> String CASHWASTEBOOK_SOURCEORTARGET_SYS </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">系统</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br /><img id="Codehighlighter1_147_165_Open_Image" onclick="this.style.display='none'; Codehighlighter1_147_165_Open_Text.style.display='none'; Codehighlighter1_147_165_Closed_Image.style.display='inline'; Codehighlighter1_147_165_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_147_165_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_147_165_Closed_Text.style.display='none'; Codehighlighter1_147_165_Open_Image.style.display='inline'; Codehighlighter1_147_165_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span><span id="Codehighlighter1_147_165_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">/** */</span><span id="Codehighlighter1_147_165_Open_Text"><span style="COLOR: #008000">/**</span><span style="COLOR: #008000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />     * 附件上传路径<br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />     </span><span style="COLOR: #008000">*/</span></span><span style="COLOR: #000000"> <br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000"> String UPLOAD_ATTACHMENT_DIR</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">upload\\</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000"> String CONFIG_DIR</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">config\\</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br /><img id="Codehighlighter1_274_292_Open_Image" onclick="this.style.display='none'; Codehighlighter1_274_292_Open_Text.style.display='none'; Codehighlighter1_274_292_Closed_Image.style.display='inline'; Codehighlighter1_274_292_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_274_292_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_274_292_Closed_Text.style.display='none'; Codehighlighter1_274_292_Open_Image.style.display='inline'; Codehighlighter1_274_292_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span><span id="Codehighlighter1_274_292_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">/** */</span><span id="Codehighlighter1_274_292_Open_Text"><span style="COLOR: #008000">/**</span><span style="COLOR: #008000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />     * 临时文件路径<br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />     </span><span style="COLOR: #008000">*/</span></span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000"> String TEMP_DIR</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">temp\\</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br /><img id="Codehighlighter1_338_354_Open_Image" onclick="this.style.display='none'; Codehighlighter1_338_354_Open_Text.style.display='none'; Codehighlighter1_338_354_Closed_Image.style.display='inline'; Codehighlighter1_338_354_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_338_354_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_338_354_Closed_Text.style.display='none'; Codehighlighter1_338_354_Open_Image.style.display='inline'; Codehighlighter1_338_354_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span><span id="Codehighlighter1_338_354_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">/** */</span><span id="Codehighlighter1_338_354_Open_Text"><span style="COLOR: #008000">/**</span><span style="COLOR: #008000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />     * 会员关系<br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />     </span><span style="COLOR: #008000">*/</span></span><span style="COLOR: #000000"><br /><img id="Codehighlighter1_389_629_Open_Image" onclick="this.style.display='none'; Codehighlighter1_389_629_Open_Text.style.display='none'; Codehighlighter1_389_629_Closed_Image.style.display='inline'; Codehighlighter1_389_629_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_389_629_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_389_629_Closed_Text.style.display='none'; Codehighlighter1_389_629_Open_Image.style.display='inline'; Codehighlighter1_389_629_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">enum</span><span style="COLOR: #000000"> Relationship </span><span id="Codehighlighter1_389_629_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/images/dot.gif" /></span><span id="Codehighlighter1_389_629_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />        GoodFriend(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">亲密好友</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">),<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />        CommonFriend(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">普通朋友</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">),<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />        BLACK(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">不受欢迎</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />        </span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">   String v;<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />        <br /><img id="Codehighlighter1_523_548_Open_Image" onclick="this.style.display='none'; Codehighlighter1_523_548_Open_Text.style.display='none'; Codehighlighter1_523_548_Closed_Image.style.display='inline'; Codehighlighter1_523_548_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_523_548_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_523_548_Closed_Text.style.display='none'; Codehighlighter1_523_548_Open_Image.style.display='inline'; Codehighlighter1_523_548_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />        Relationship(String value) </span><span id="Codehighlighter1_523_548_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/images/dot.gif" /></span><span id="Codehighlighter1_523_548_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />          v </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> value;<br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />        }</span></span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />        @Override<br /><img id="Codehighlighter1_595_623_Open_Image" onclick="this.style.display='none'; Codehighlighter1_595_623_Open_Text.style.display='none'; Codehighlighter1_595_623_Closed_Image.style.display='inline'; Codehighlighter1_595_623_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_595_623_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_595_623_Closed_Text.style.display='none'; Codehighlighter1_595_623_Open_Image.style.display='inline'; Codehighlighter1_595_623_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />        </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> String toString() </span><span id="Codehighlighter1_595_623_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/images/dot.gif" /></span><span id="Codehighlighter1_595_623_Open_Text"><span style="COLOR: #000000">{        <br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />            </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> v;<br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />        }</span></span><span style="COLOR: #000000"> <br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />      }</span></span><span style="COLOR: #000000">  <br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">final</span><span style="COLOR: #000000"> String SUCCESS </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">OK</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br /><img id="Codehighlighter1_678_691_Open_Image" onclick="this.style.display='none'; Codehighlighter1_678_691_Open_Text.style.display='none'; Codehighlighter1_678_691_Closed_Image.style.display='inline'; Codehighlighter1_678_691_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_678_691_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_678_691_Closed_Text.style.display='none'; Codehighlighter1_678_691_Open_Image.style.display='inline'; Codehighlighter1_678_691_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span><span id="Codehighlighter1_678_691_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">/** */</span><span id="Codehighlighter1_678_691_Open_Text"><span style="COLOR: #008000">/**</span><span style="COLOR: #008000">用户选择管理员登录</span><span style="COLOR: #008000">*/</span></span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">final</span><span style="COLOR: #000000"> String MESSAGE_LOGIN_TYPEERROR1 </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">您不能选择管理员登录</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br /><img id="Codehighlighter1_763_779_Open_Image" onclick="this.style.display='none'; Codehighlighter1_763_779_Open_Text.style.display='none'; Codehighlighter1_763_779_Closed_Image.style.display='inline'; Codehighlighter1_763_779_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_763_779_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_763_779_Closed_Text.style.display='none'; Codehighlighter1_763_779_Open_Image.style.display='inline'; Codehighlighter1_763_779_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span><span id="Codehighlighter1_763_779_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">/** */</span><span id="Codehighlighter1_763_779_Open_Text"><span style="COLOR: #008000">/**</span><span style="COLOR: #008000">管理员选择会员或家长登录</span><span style="COLOR: #008000">*/</span></span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">final</span><span style="COLOR: #000000"> String MESSAGE_LOGIN_TYPEERROR2 </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">您应该选择管理员登录</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br /><img id="Codehighlighter1_851_864_Open_Image" onclick="this.style.display='none'; Codehighlighter1_851_864_Open_Text.style.display='none'; Codehighlighter1_851_864_Closed_Image.style.display='inline'; Codehighlighter1_851_864_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_851_864_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_851_864_Closed_Text.style.display='none'; Codehighlighter1_851_864_Open_Image.style.display='inline'; Codehighlighter1_851_864_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span><span id="Codehighlighter1_851_864_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">/** */</span><span id="Codehighlighter1_851_864_Open_Text"><span style="COLOR: #008000">/**</span><span style="COLOR: #008000">会员或家长重复登陆</span><span style="COLOR: #008000">*/</span></span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">final</span><span style="COLOR: #000000"> String MESSAGE_LOGIN_REPEAT </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">可能因为以下原因，您无法登陆系统\n\t１　有人盗用您的帐号\n２ 您的{0}正在使用本帐号</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">final</span><span style="COLOR: #000000"> String MESSAGE_LONGIN_PASSWORDERROR </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">用户名或密码无效</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">final</span><span style="COLOR: #000000"> String MESSAGE_INSUFFICIENT_FUNDS </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">您的帐户余额不足</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">final</span><span style="COLOR: #000000"> String MESSAGE_MEMBER_ONLINETIME_FULL </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">您今日的累计上线时间已超过１.５小时</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br /><img id="Codehighlighter1_1194_1219_Open_Image" onclick="this.style.display='none'; Codehighlighter1_1194_1219_Open_Text.style.display='none'; Codehighlighter1_1194_1219_Closed_Image.style.display='inline'; Codehighlighter1_1194_1219_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_1194_1219_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_1194_1219_Closed_Text.style.display='none'; Codehighlighter1_1194_1219_Open_Image.style.display='inline'; Codehighlighter1_1194_1219_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span><span id="Codehighlighter1_1194_1219_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">/** */</span><span id="Codehighlighter1_1194_1219_Open_Text"><span style="COLOR: #008000">/**</span><span style="COLOR: #008000">会员每天最大登录时限 单位分钟 默认90*</span><span style="COLOR: #008000">*/</span></span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">final</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> MEMBER_MAX_DAY_ONLINE_MINUTES </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">90</span><span style="COLOR: #000000">;<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    <br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /></span></div>   <br />    可以看到，枚举类型Relationship是定义一些会员关系之间的东东，其实我可以把它单独定义一个类，或者放到Member(会员)这个类中，但综合考虑，我还是觉得放到SystemConstant比较好，并且今后重构SystemConstant，会添加从xml文件读取属性的功能。<br />     虽然Relationship是一个内部类，但由于是静态的，所以可以直接import,而无须每次都用SystemConstant.Relationship;<br /> 例如：<br />    public Relationship getRelationship() {<br />           return Relationship.valueOf(relationship);<br />        }<br /><br />  2 说到从xml文件读取属性来动态配置枚举类，我下面就举个例子，演示演示<br />     一些web系统中涉及到文件上传，根据文件类型显示相应图标，并且有些jsp,asp等等的文件不允许上传，下面就是一个满足这种需求的枚举类，它最大的特点就是可以从xml中读取配置信息<br /><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img id="Codehighlighter1_0_43_Open_Image" onclick="this.style.display='none'; Codehighlighter1_0_43_Open_Text.style.display='none'; Codehighlighter1_0_43_Closed_Image.style.display='inline'; Codehighlighter1_0_43_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_0_43_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_0_43_Closed_Text.style.display='none'; Codehighlighter1_0_43_Open_Image.style.display='inline'; Codehighlighter1_0_43_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top" /><span id="Codehighlighter1_0_43_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">/** */</span><span id="Codehighlighter1_0_43_Open_Text"><span style="COLOR: #008000">/**</span><span style="COLOR: #008000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /> * 系统中用到的文件扩展名 枚举类<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /> * </span><span style="COLOR: #808080">@author</span><span style="COLOR: #008000"> zgy<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /> *<br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" /> </span><span style="COLOR: #008000">*/</span></span><span style="COLOR: #000000"><br /><img id="Codehighlighter1_71_1286_Open_Image" onclick="this.style.display='none'; Codehighlighter1_71_1286_Open_Text.style.display='none'; Codehighlighter1_71_1286_Closed_Image.style.display='inline'; Codehighlighter1_71_1286_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_71_1286_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_71_1286_Closed_Text.style.display='none'; Codehighlighter1_71_1286_Open_Image.style.display='inline'; Codehighlighter1_71_1286_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">enum</span><span style="COLOR: #000000"> FileExtension </span><span id="Codehighlighter1_71_1286_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/images/dot.gif" /></span><span id="Codehighlighter1_71_1286_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    doc, jsp, jpeg, jpg, rar, zip, txt,unknown;<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">boolean</span><span style="COLOR: #000000"> allow;<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /> <br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000"> String comment;<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000"> String iconPath;<br /><img id="Codehighlighter1_206_227_Open_Image" onclick="this.style.display='none'; Codehighlighter1_206_227_Open_Text.style.display='none'; Codehighlighter1_206_227_Closed_Image.style.display='inline'; Codehighlighter1_206_227_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_206_227_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_206_227_Closed_Text.style.display='none'; Codehighlighter1_206_227_Open_Image.style.display='inline'; Codehighlighter1_206_227_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000"> </span><span id="Codehighlighter1_206_227_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/images/dot.gif" /></span><span id="Codehighlighter1_206_227_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />        loadFromXml(); <br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</span></span><span style="COLOR: #000000"> <br /><img id="Codehighlighter1_247_347_Open_Image" onclick="this.style.display='none'; Codehighlighter1_247_347_Open_Text.style.display='none'; Codehighlighter1_247_347_Closed_Image.style.display='inline'; Codehighlighter1_247_347_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_247_347_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_247_347_Closed_Text.style.display='none'; Codehighlighter1_247_347_Open_Image.style.display='inline'; Codehighlighter1_247_347_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    FileExtension() </span><span id="Codehighlighter1_247_347_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/images/dot.gif" /></span><span id="Codehighlighter1_247_347_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />        </span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">.iconPath </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">\\</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">+</span><span style="COLOR: #000000"> name();<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />        </span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">.allow </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">true</span><span style="COLOR: #000000">;<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />        </span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">.comment </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">comment for</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">+</span><span style="COLOR: #000000"> name();<br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</span></span><span style="COLOR: #000000">    <br /><img id="Codehighlighter1_351_382_Open_Image" onclick="this.style.display='none'; Codehighlighter1_351_382_Open_Text.style.display='none'; Codehighlighter1_351_382_Closed_Image.style.display='inline'; Codehighlighter1_351_382_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_351_382_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_351_382_Closed_Text.style.display='none'; Codehighlighter1_351_382_Open_Image.style.display='inline'; Codehighlighter1_351_382_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span><span id="Codehighlighter1_351_382_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">/** */</span><span id="Codehighlighter1_351_382_Open_Text"><span style="COLOR: #008000">/**</span><span style="COLOR: #008000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />     * 从config目录中load<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />     * <br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />     </span><span style="COLOR: #008000">*/</span></span><span style="COLOR: #000000"><br /><img id="Codehighlighter1_419_1033_Open_Image" onclick="this.style.display='none'; Codehighlighter1_419_1033_Open_Text.style.display='none'; Codehighlighter1_419_1033_Closed_Image.style.display='inline'; Codehighlighter1_419_1033_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_419_1033_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_419_1033_Closed_Text.style.display='none'; Codehighlighter1_419_1033_Open_Image.style.display='inline'; Codehighlighter1_419_1033_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> loadFromXml() </span><span id="Codehighlighter1_419_1033_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/images/dot.gif" /></span><span id="Codehighlighter1_419_1033_Open_Text"><span style="COLOR: #000000">{<br /><img id="Codehighlighter1_427_969_Open_Image" onclick="this.style.display='none'; Codehighlighter1_427_969_Open_Text.style.display='none'; Codehighlighter1_427_969_Closed_Image.style.display='inline'; Codehighlighter1_427_969_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_427_969_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_427_969_Closed_Text.style.display='none'; Codehighlighter1_427_969_Open_Image.style.display='inline'; Codehighlighter1_427_969_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />        </span><span style="COLOR: #0000ff">try</span><span style="COLOR: #000000"> </span><span id="Codehighlighter1_427_969_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/images/dot.gif" /></span><span id="Codehighlighter1_427_969_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />            Document doc </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> XmlUtil.parseXmlFile(SystemConstant.CONFIG_DIR<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />                    </span><span style="COLOR: #000000">+</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">fileExtension.xml</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />            NodeList extensionList </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> doc.getElementsByTagName(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">FileExtension</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br /><img id="Codehighlighter1_649_965_Open_Image" onclick="this.style.display='none'; Codehighlighter1_649_965_Open_Text.style.display='none'; Codehighlighter1_649_965_Closed_Image.style.display='inline'; Codehighlighter1_649_965_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_649_965_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_649_965_Closed_Text.style.display='none'; Codehighlighter1_649_965_Open_Image.style.display='inline'; Codehighlighter1_649_965_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />            </span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000"> (</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> i </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">; i </span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000"> extensionList.getLength(); i</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">) </span><span id="Codehighlighter1_649_965_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/images/dot.gif" /></span><span id="Codehighlighter1_649_965_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />                Element item </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> (Element) extensionList.item(i);<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />                String name </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> item.getAttribute(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">name</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />                FileExtension em </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> FileExtension.valueOf(name);<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />                em.allow </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> Boolean.parseBoolean(item.getAttribute(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">allow</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">));<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />                em.iconPath </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> item.getAttribute(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">iconPath</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />                em.comment </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> item.getAttribute(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">comment</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">); <br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />            }</span></span><span style="COLOR: #000000"><br /><img id="Codehighlighter1_991_1030_Open_Image" onclick="this.style.display='none'; Codehighlighter1_991_1030_Open_Text.style.display='none'; Codehighlighter1_991_1030_Closed_Image.style.display='inline'; Codehighlighter1_991_1030_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_991_1030_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_991_1030_Closed_Text.style.display='none'; Codehighlighter1_991_1030_Open_Image.style.display='inline'; Codehighlighter1_991_1030_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />        }</span></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">catch</span><span style="COLOR: #000000"> (Exception e) </span><span id="Codehighlighter1_991_1030_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/images/dot.gif" /></span><span id="Codehighlighter1_991_1030_Open_Text"><span style="COLOR: #000000">{ <br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />            </span><span style="COLOR: #0000ff">throw</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> RuntimeException(e);<br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />        }</span></span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</span></span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img id="Codehighlighter1_1062_1081_Open_Image" onclick="this.style.display='none'; Codehighlighter1_1062_1081_Open_Text.style.display='none'; Codehighlighter1_1062_1081_Closed_Image.style.display='inline'; Codehighlighter1_1062_1081_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_1062_1081_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_1062_1081_Closed_Text.style.display='none'; Codehighlighter1_1062_1081_Open_Image.style.display='inline'; Codehighlighter1_1062_1081_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">boolean</span><span style="COLOR: #000000"> isAllow() </span><span id="Codehighlighter1_1062_1081_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/images/dot.gif" /></span><span id="Codehighlighter1_1062_1081_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />        </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> allow;<br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</span></span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img id="Codehighlighter1_1112_1133_Open_Image" onclick="this.style.display='none'; Codehighlighter1_1112_1133_Open_Text.style.display='none'; Codehighlighter1_1112_1133_Closed_Image.style.display='inline'; Codehighlighter1_1112_1133_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_1112_1133_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_1112_1133_Closed_Text.style.display='none'; Codehighlighter1_1112_1133_Open_Image.style.display='inline'; Codehighlighter1_1112_1133_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> String getComment() </span><span id="Codehighlighter1_1112_1133_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/images/dot.gif" /></span><span id="Codehighlighter1_1112_1133_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />        </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> comment;<br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</span></span><span style="COLOR: #000000"> <br /><img id="Codehighlighter1_1167_1189_Open_Image" onclick="this.style.display='none'; Codehighlighter1_1167_1189_Open_Text.style.display='none'; Codehighlighter1_1167_1189_Closed_Image.style.display='inline'; Codehighlighter1_1167_1189_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_1167_1189_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_1167_1189_Closed_Text.style.display='none'; Codehighlighter1_1167_1189_Open_Image.style.display='inline'; Codehighlighter1_1167_1189_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> String getUploadIcon() </span><span id="Codehighlighter1_1167_1189_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/images/dot.gif" /></span><span id="Codehighlighter1_1167_1189_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />        </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> iconPath;<br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</span></span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img id="Codehighlighter1_1232_1284_Open_Image" onclick="this.style.display='none'; Codehighlighter1_1232_1284_Open_Text.style.display='none'; Codehighlighter1_1232_1284_Closed_Image.style.display='inline'; Codehighlighter1_1232_1284_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_1232_1284_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_1232_1284_Closed_Text.style.display='none'; Codehighlighter1_1232_1284_Open_Image.style.display='inline'; Codehighlighter1_1232_1284_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> main(String[] args) </span><span id="Codehighlighter1_1232_1284_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/images/dot.gif" /></span><span id="Codehighlighter1_1232_1284_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />        System.out.println(FileExtension.doc.comment);<br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</span></span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /></span></div><br />配置文件如下：config/fileExtension.xml<br />&lt;?xml version="1.0" encoding="UTF-8"?&gt;<br />&lt;FileExtensions&gt; <br /> &lt;FileExtension name="doc" iconPath="doc.jpg" allow="true"   comment="文本"/&gt;<br /> &lt;FileExtension name="jpg" iconPath="jpg.jpg" allow="true"   comment=""/&gt;<br /> &lt;FileExtension name="jpeg" iconPath="jpeg.jpg" allow="true" comment=""/&gt;<br /> &lt;FileExtension name="rar" iconPath="rar.jpg" allow="true"   comment=""/&gt;<br /> &lt;FileExtension name="zip" iconPath="zip.jpg" allow="true"   comment=""/&gt;<br /> &lt;FileExtension name="txt" iconPath="txt.jpg" allow="true"   comment=""/&gt;<br />    &lt;FileExtension name="jsp" iconPath="jsp.jpg" allow="false"  comment=""/&gt;<br />&lt;/FileExtensions&gt;<br /><br />可能系统中其他的一些枚举类（比如1 中提到的RelationShip）也会用到非常类似的做法，这时候我们就可以重构了，将一些共同的特点抽取到一个抽象类中。这将会在以后的文章中提到。<br />有不同的观点，请联系<a href="mailto:come2u@gmail.co">come2u at gmail.co</a>m  ,欢迎交流。<img src ="http://www.blogjava.net/nbtymm/aggbug/62115.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/nbtymm/" target="_blank">nbt</a> 2006-08-07 09:38 <a href="http://www.blogjava.net/nbtymm/archive/2006/08/07/62115.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java文件操作详解</title><link>http://www.blogjava.net/nbtymm/archive/2006/08/04/61644.html</link><dc:creator>nbt</dc:creator><author>nbt</author><pubDate>Fri, 04 Aug 2006 01:23:00 GMT</pubDate><guid>http://www.blogjava.net/nbtymm/archive/2006/08/04/61644.html</guid><wfw:comment>http://www.blogjava.net/nbtymm/comments/61644.html</wfw:comment><comments>http://www.blogjava.net/nbtymm/archive/2006/08/04/61644.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.blogjava.net/nbtymm/comments/commentRss/61644.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/nbtymm/services/trackbacks/61644.html</trackback:ping><description><![CDATA[
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
								</td>
						</tr>
						<!-- end of article title -->
						<tr>
								<td valign="top" align="middle" width="100%">
										<!--start of article content -->
										<table width="98%" border="0">
												<tbody>
														<tr>
																<td class="text" align="left" width="100%">
																		<p>输入输出流 <br />在Java中，我们把能够读取一个字节序列的对象称作一个输入流;而我们把够写一个字节序列称作一个输出流。它们分别由抽象类 <br />InputStream和OutputStream类表示。因为面向字节的流不方便用来处理存储为Unicode（每个字符使用两个字节)的信息。所以Java <br />引入了用来处理Unicode字符的类层次，这些类派生自抽象类Reader和Writer，它们用于读写双字节的Unicode字符，而不是单字节字符。 <br />Java.io包简介 <br />JDK标准帮助文档是这样解释Java.io包的，通过数据流、序列和文件系统为系统提供输入输出。 <br />InputStream类和OutputStream类 <br />InputStream类是所有输入数据流的父类，它是一个抽象类，定义了所有输入数据流都具有的共通特性。 <br />java.io.InputStream的方法如下： <br />public abstract read()throws IOException <br />读取一个字节并返回该字节，如果到输入源的末则返回-1。一个具体的输入流类需要重载此方法，以提供 有用的功能。例如：在FileInputStream类中，该方法从一个文件读取一个字节。 <br />public int read(byte[] b)throws IOException <br />把数据读入到一个字节数据中，并返回实际读取的字节数目。如果遇到流末 则返回-1，该方法最多读取b.length个字节。 <br />public abstract int read(byte[] b,int off,int len)throws IOException <br />把数据读入到一个字节数组中并返回实际读取的字节数目。如果遇到流的末尾则的返回-1。 其中参数off表示第一个字节在b中的位置，len表示读取的最大字节数。 <br />public long skip(long n)throws IOException <br />略过N个字节不读取，会返回实际略过的字节数目。因为数据流中剩下的数据可能不到N 个字节那么多，所以此时返回值会小于N。 <br />public int available()throws IOException <br />read方法(包括后面要讲的OutputStream类的Write方法)都能够阴塞一个线程，直到字节被 实际读取或写入。这意味着如果一个流不能立即被读或被写 <br />/* <br />* Created on 2005-3-10 <br />* To change the template for this generated file go to <br />* Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments <br />*/ <br /><br />import java.io.BufferedReader; <br />import java.io.File; <br />import java.io.FileReader; <br />import java.io.FileWriter; <br />import java.io.IOException; <br />import java.io.PrintWriter; <br />import java.io.FileInputStream;; <br />/** <br />* @author zhangqinglin <br />* To change the template for this generated type comment go to <br />* Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments <br />*/ <br />public class Files <br />{ <br />public static void main(String[] args) throws IOException <br />{ <br />Files f = new Files(); <br />// System.out.println(f.readFile("f:\\LinkFile.java")); <br />f.fileIsNull("D:\\java\\","ejb"); <br />//f.readLineFile("D:\\java\\","TestFile.txt"); <br />// System.out.println(f.fileIsNull("f:\\","122.txt")); <br />//f.readFolderByFile("F:\\Login"); //不区分大小写<br />// System.out.println(f.createAndDeleteFolder("ss","f:\\")); <br />// System.out.println(f.createAndDeleteFile("f:\\ss\\","TestFile.dat")); <br />//f.createAndDeleteFolder("1","D:\\java\\");<br />String[] ss = new String[50]; //定义对象数组<br />for(int i=0;i&lt;ss.length;i++) <br />{ <br />ss = "信息技术和互联网(计算机软硬件,通讯) "+i; <br />} <br />f.writeFile("D:\\java\\","TestFile.txt",ss); <br /><br />} <br />/** <br />* 文件的写入 <br />* @param filePath(文件路径) <br />* @param fileName(文件名) <br />* @param args[] <br />* @throws IOException <br />*/ <br />public void writeFile(String filePath,String fileName,String[] args) throws IOException <br />{ <br />FileWriter fw = new FileWriter(filePath+fileName); <br />PrintWriter out=new PrintWriter(fw); <br />for(int i=0;i&lt;args.length;i++) <br />{ <br />out.write(args); <br />out.println(); <br />//out.flush(); <br />}<br />System.out.println("写入成功！"); <br />fw.close(); <br />out.close(); <br />} <br />/** <br />* 文件的写入 <br />* @param filePath(文件路径) <br />* @param fileName(文件名) <br />* @param args <br />* @throws IOException <br />*/ <br />public void writeFile(String filePath,String fileName,String args) throws IOException <br />{ <br />FileWriter fw = new FileWriter(filePath+fileName); <br />fw.write(args); <br />fw.close(); <br />} <br />/** <br />* 创建与删除文件 <br />* @param filePath <br />* @param fileName <br />* @return 创建成功返回true <br />* @throws IOException <br />*/ <br />public boolean createAndDeleteFile(String filePath,String fileName) throws IOException <br />{ <br />boolean result = false; <br />File file = new File(filePath,fileName); <br />if(file.exists()){<br />if(file.isFile()) <br />{ <br />file.delete(); <br />result = true; <br />System.out.println("文件已经删除！"); <br />} <br />else <br />{<br />   System.out.println("对不起,该路径为目录！"); <br />   <br />}<br />}<br />else <br />{ <br />file.createNewFile(); //jdk5.0的新方法<br />result = true; <br />System.out.println("文件已经创建！"); <br />} <br />return result; <br />} <br />/** <br />* 创建和删除目录 <br />* @param folderName <br />* @param filePath <br />* @return 删除成功返回true <br />*/ <br />public boolean createAndDeleteFolder(String folderName,String filePath) <br />{ <br />boolean result = false; <br />try <br />{ <br />File file = new File(filePath+folderName); <br />if(file.exists()) <br />{ <br />if(file.isDirectory()){<br />file.delete(); <br />System.out.println("目录已经存在，已删除!"); <br />result = true; <br />}<br />else{<br />System.out.println("对不起,该路径为文件！"); <br />}<br />} <br />else <br />{ <br />file.mkdir(); <br />System.out.println("目录不存在，已经建立!"); <br />result = true; <br />} <br />} <br />catch(Exception ex) <br />{ <br />result = false; <br />System.out.println("CreateAndDeleteFolder is error:"+ex); <br />} <br />return result; <br />} <br />/** <br />* 输出目录中的所有文件及目录名字 <br />* @param filePath <br />*/ <br />public void readFolderByFile(String filePath)<br />{ <br />File file = new File(filePath); <br />File[] tempFile = file.listFiles(); <br />for(int i = 0;i&lt;tempFile.length;i++) <br />{ <br />if(tempFile.isFile()) <br />{ <br />System.out.println("File : "+tempFile.getName()); <br />} <br />if(tempFile.isDirectory()) <br />{ <br />System.out.println("Directory : "+tempFile.getName()); <br />} <br />} <br />} <br />/** <br />* 检查文件中是否为一个空 <br />* @param filePath <br />* @param fileName <br />* @return 为空返回true <br />* @throws IOException <br />*/ <br />public boolean fileIsNull(String filePath,String fileName) throws IOException <br />{ <br />boolean result = false; <br />FileReader fr = new FileReader(filePath+fileName); <br />if(fr.read() == -1) <br />{ <br />result = true; <br />System.out.println(fileName+" 文件中没有数据!"); <br />} <br />else <br />{ <br />System.out.println(fileName+" 文件中有数据!"); <br />} <br />fr.close(); <br />return result; <br />} <br />/** <br />* 读取文件中的所有内容 <br />* @param filePath <br />* @param fileName <br />* @throws IOException <br />*/ <br />public void readAllFile(String filePath,String fileName) throws IOException <br />{ <br />FileReader fr = new FileReader(filePath+fileName); <br />//PrintWriter pr=new PrintWriter(fr);<br />//pr.print<br />int count = fr.read(); <br />while(count != -1) <br />{ <br />System.out.print((char)count); <br />count = fr.read(); <br />//System.out.println();<br />if(count == 13) <br />{ <br />fr.skip(1); <br />System.out.print("跳过!"); <br />}<br />} <br />System.out.println(); <br />fr.close(); <br />} <br />/** <br />* 一行一行的读取文件中的数据 <br />* @param filePath <br />* @param fileName <br />* @throws IOException <br />*/ <br />public void readLineFile(String filePath,String fileName) throws IOException <br />{ <br />FileReader fr = new FileReader(filePath+fileName); <br />BufferedReader br = new BufferedReader(fr); <br />String line = br.readLine(); <br />while(line != null) <br />{ <br />System.out.println(line); <br />line = br.readLine(); <br />} <br />br.close(); <br />fr.close(); <br />}<br />}<br /><br /><br />/***************************以下是常用的文件操作方法******************************/<br /><br />/**  <br />     *  @see 新建目录  <br />     *  @param  folderPath  String  如  c:/fqf  <br />     *  @return  boolean  <br />     */  <br />   public  void  newFolder(String  folderPath)  <br />{  <br />       try  {  <br />           String  filePath  =  folderPath;  <br />           filePath  =  filePath.toString();  <br />           java.io.File  myFilePath  =  new  java.io.File(filePath);  <br />           if  (!myFilePath.exists())  <br />            {  <br />               myFilePath.mkdir();  <br />           }  <br />       }  <br />       catch  (Exception  e) <br />       {  <br />           System.out.println("新建目录操作出错");  <br />           e.printStackTrace();  <br />       }  <br />   }  <br /> <br />   /**  <br />     *  @see 新建文件  <br />     *  @param  filePathAndName  String  文件路径及名称  如c:/fqf.txt  <br />     *  @param  fileContent  String  文件内容  <br />     *  @return  boolean  <br />     */  <br />   public  void  newFile(String  filePathAndName,  String  fileContent)  {  <br /> <br />       try  {  <br />           String  filePath  =  filePathAndName;  <br />           filePath  =  filePath.toString();  <br />           File  myFilePath  =  new  File(filePath);  <br />           if  (!myFilePath.exists())  {  <br />               myFilePath.createNewFile();  <br />           }  <br />           FileWriter  resultFile  =  new  FileWriter(myFilePath);  <br />           PrintWriter  myFile  =  new  PrintWriter(resultFile);  <br />           String  strContent  =  fileContent;  <br />           myFile.println(strContent);  <br />           resultFile.close();  <br /> <br />       }  <br />       catch  (Exception  e)  {  <br />           System.out.println("新建文件操作出错");  <br />           e.printStackTrace();  <br /> <br />       }  <br /> <br />   }  <br /> <br />   /**  <br />     *  @see 删除文件  <br />     *  @param  filePathAndName  String  文件路径及名称  如c:/fqf.txt  <br />     *  @param  fileContent  String  <br />     *  @return  boolean  <br />     */  <br />   public  void  delFile(String  filePathAndName)  {  <br />       try  {  <br />           String  filePath  =  filePathAndName;  <br />           filePath  =  filePath.toString();  <br />           java.io.File  myDelFile  =  new  java.io.File(filePath);  <br />           myDelFile.delete();  <br />           System.out.println(myDelFile + "\\文件存在，已删除。");<br /> <br />       }  <br />       catch  (Exception  e)  {  <br />           System.out.println("删除文件操作出错");  <br />           e.printStackTrace();  <br /> <br />       }  <br /> <br />   }  <br /> <br />   /**  <br />     *  @see 删除文件夹  <br />     *  @param  filePathAndName  String  文件夹路径及名称  如c:/fqf  <br />     *  @param  fileContent  String  <br />     *  @return  boolean  <br />     */  <br />   public  void  delFolder(String  folderPath)  {  <br />       try  {  <br />           delAllFile(folderPath);  //删除完里面所有内容  <br />           String  filePath  =  folderPath;  <br />           filePath  =  filePath.toString();  <br />           java.io.File  myFilePath  =  new  java.io.File(filePath);  <br />           myFilePath.delete();  //删除空文件夹  <br /> <br />       }  <br />       catch  (Exception  e)  {  <br />           System.out.println("删除文件夹操作出错");  <br />           e.printStackTrace();  <br /> <br />       }  <br /> <br />   }  <br /> <br />   /**  <br />     *  @see 删除文件夹里面的所有文件  <br />     *  @param  path  String  文件夹路径  如  c:/fqf  <br />     */  <br />   public  void  delAllFile(String  path)  {  <br />       File  file  =  new  File(path);  <br />       if  (!file.exists())  {  <br />           return;  <br />       }  <br />       if  (!file.isDirectory())  {  <br />           return;  <br />       }  <br />       String[]  tempList  =  file.list();  <br />       File  temp  =  null;  <br />       for  (int  i  =  0;  i  &lt;  tempList.length;  i++)  {  <br />           if  (path.endsWith(File.separator))  {  <br />               temp  =  new  File(path  +  tempList[i]);  <br />           }  <br />           else  {  <br />               temp  =  new  File(path  +  File.separator  +  tempList[i]);  <br />           }  <br />           if  (temp.isFile())  {  <br />               temp.delete();  <br />           }  <br />           if  (temp.isDirectory())  {  <br />               delAllFile(path+"/"+  tempList[i]);//先删除文件夹里面的文件  <br />               delFolder(path+"/"+  tempList[i]);//再删除空文件夹  <br />           }  <br />       }  <br />   }  <br /> <br />   /**  <br />     *  @see 复制单个文件  <br />     *  @param  oldPath  String  原文件路径  如：c:/fqf.txt  <br />     *  @param  newPath  String  复制后路径  如：f:/fqf.txt  <br />     *  @return  boolean  <br />     */  <br />   public  void  copyFile(String  oldPath,  String  newPath)  {  <br />       try  {  <br />           int  bytesum  =  0;  <br />           int  byteread  =  0;  <br />           File  oldfile  =  new  File(oldPath);  <br />           if  (oldfile.exists())  {  //文件存在时  <br />               InputStream  inStream  =  new  FileInputStream(oldPath);  //读入原文件  <br />               FileOutputStream  fs  =  new  FileOutputStream(newPath);  <br />               byte[]  buffer  =  new  byte[1444];  <br />               //int  length = 0;  <br />               while  (  (byteread  =  inStream.read(buffer))  !=  -1)  {  <br />                   bytesum  +=  byteread;  //字节数  文件大小  <br />                   System.out.println(bytesum);  <br />                   fs.write(buffer,  0,  byteread);  <br />               }  <br />               inStream.close();  <br />           }  <br />       }  <br />       catch  (Exception  e)  {  <br />           System.out.println("复制单个文件操作出错");  <br />           e.printStackTrace();  <br /> <br />       }  <br /> <br />   }  <br /> <br />   /**  <br />     *  @see 复制整个文件夹内容  <br />     *  @param  oldPath  String  原文件路径  如：c:/fqf  <br />     *  @param  newPath  String  复制后路径  如：f:/fqf/ff  <br />     *  @return  boolean  <br />     */  <br />   public  void  copyFolder(String  oldPath,  String  newPath)  {  <br /> <br />       try  {  <br />           (new  File(newPath)).mkdirs();  //如果文件夹不存在  则建立新文件夹  <br />           File  a=new  File(oldPath);  <br />           String[]  file=a.list();  <br />           File  temp=null;  <br />           for  (int  i  =  0;  i  &lt;  file.length;  i++)  {  <br />               if(oldPath.endsWith(File.separator)){  <br />                   temp=new  File(oldPath+file[i]);  <br />               }  <br />               else{  <br />                   temp=new  File(oldPath+File.separator+file[i]);  <br />               }  <br /> <br />               if(temp.isFile()){  <br />                   FileInputStream  input  =  new  FileInputStream(temp);  <br />                   FileOutputStream  output  =  new  FileOutputStream(newPath  +  "/"  +  <br />                           (temp.getName()).toString());  <br />                   byte[]  b  =  new  byte[1024  *  5];  <br />                   int  len;  <br />                   while  (  (len  =  input.read(b))  !=  -1)  {  <br />                       output.write(b,  0,  len);  <br />                   }  <br />                   output.flush();  <br />                   output.close();  <br />                   input.close();  <br />               }  <br />               if(temp.isDirectory()){//如果是子文件夹  <br />                   copyFolder(oldPath+"/"+file[i],newPath+"/"+file[i]);  <br />               }  <br />           }  <br />       }  <br />       catch  (Exception  e)  {  <br />           System.out.println("复制整个文件夹内容操作出错");  <br />           e.printStackTrace();  <br /> <br />       }  <br /> <br />   }  <br /> <br />   /**  <br />     *  @see 移动文件到指定目录  <br />     *  @param  oldPath  String  如：c:/fqf.txt  <br />     *  @param  newPath  String  如：d:/fqf.txt  <br />     */  <br />   public  void  moveFile(String  oldPath,  String  newPath)  {  <br />       copyFile(oldPath,  newPath);  <br />       delFile(oldPath);  <br /> <br />   }  <br /> <br />   /**  <br />     *  移动文件到指定目录  <br />     *  @param  oldPath  String  如：c:/fqf.txt  <br />     *  @param  newPath  String  如：d:/fqf.txt  <br />     */  <br />   public  void  moveFolder(String  oldPath,  String  newPath)  {  <br />       copyFolder(oldPath,  newPath);  <br />       delFolder(oldPath);  <br /> <br />   }  <br />   <br />   /**  <br />    * @see 获得系统根目录绝对路径  <br />    * @return String  <br />    *    <br />    */ <br />   public String getPath(){</p>
																		<p>  String sysPath = this.getClass().getResource("/").getPath();<br />     //对路径进行修改<br />  sysPath = sysPath.substring(1, sysPath.length() - 16);<br />  return  sysPath;<br />    <br />   }<br /><br /></p>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
<img src ="http://www.blogjava.net/nbtymm/aggbug/61644.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/nbtymm/" target="_blank">nbt</a> 2006-08-04 09:23 <a href="http://www.blogjava.net/nbtymm/archive/2006/08/04/61644.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JVM(JAVA虚拟机介绍)</title><link>http://www.blogjava.net/nbtymm/archive/2006/06/09/51722.html</link><dc:creator>nbt</dc:creator><author>nbt</author><pubDate>Fri, 09 Jun 2006 08:25:00 GMT</pubDate><guid>http://www.blogjava.net/nbtymm/archive/2006/06/09/51722.html</guid><wfw:comment>http://www.blogjava.net/nbtymm/comments/51722.html</wfw:comment><comments>http://www.blogjava.net/nbtymm/archive/2006/06/09/51722.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/nbtymm/comments/commentRss/51722.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/nbtymm/services/trackbacks/51722.html</trackback:ping><description><![CDATA[
		<table class="fixedTable blogpost" cellspacing="0" width="100%" border="0">
				<tbody>
						<tr>
								<td class="ellipse">
										<span class="bvTitle" id="subjcns!48122F59260F24A8!123">
												<strong>
												</strong>
										</span>
								</td>
						</tr>
						<tr>
								<td class="bvh8">
										<strong>
										</strong>
								</td>
						</tr>
						<tr>
								<td id="msgcns!48122F59260F24A8!123">
										<div>Java虚拟机(JVM)是可运行Java代码的假想计算机。只要根据JVM规格描述将解释器移植到特定的计算机上，就能保证经过编译的任何Java代码能够在该系统上运行。本文首先简要介绍从Java文件的编译到最终执行的过程，随后对JVM规格描述作一说明。 
<p>　　一.Java源文件的编译、下载、解释和执行<br />　　Java应用程序的开发周期包括编译、下载、解释和执行几个部分。Java编译程序将Java源程序翻译为JVM可执行代码—字节码。这一编译过程同C/C++的编译有些不同。当C编译器编译生成一个对象的代码时，该代码是为在某一特定硬件平台运行而产生的。因此，在编译过程中，编译程序通过查表将所有对符号的引用转换为特定的内存偏移量，以保证程序运行。Java编译器却不将对变量和方法的引用编译为数值引用，也不确定程序执行过程中的内存布局，而是将这些符号引用信息保留在字节码中，由解释器在运行过程中创立内存布局，然后再通过查表来确定一个方法所在的地址。这样就有效的保证了Java的可移植性和安全性。 <br />运行JVM字节码的工作是由解释器来完成的。解释执行过程分三部进行：代码的装入、代码的校验和代码的执行。装入代码的工作由"类装载器"（class loader）完成。类装载器负责装入运行一个程序需要的所有代码，这也包括程序代码中的类所继承的类和被其调用的类。当类装载器装入一个类时，该类被放在自己的名字空间中。除了通过符号引用自己名字空间以外的类，类之间没有其他办法可以影响其他类。在本台计算机上的所有类都在同一地址空间内，而所有从外部引进的类，都有一个自己独立的名字空间。这使得本地类通过共享相同的名字空间获得较高的运行效率，同时又保证它们与从外部引进的类不会相互影响。当装入了运行程序需要的所有类后，解释器便可确定整个可执行程序的内存布局。解释器为符号引用同特定的地址空间建立对应关系及查询表。通过在这一阶段确定代码的内存布局，Java很好地解决了由超类改变而使子类崩溃的问题，同时也防止了代码对地址的非法访问。 <br />随后，被装入的代码由字节码校验器进行检查。校验器可发现操作数栈溢出，非法数据类型转化等多种错误。通过校验后，代码便开始执行了。 <br />　　Java字节码的执行有两种方式： <br />　　1.即时编译方式：解释器先将字节码编译成机器码，然后再执行该机器码。 <br />　　2.解释执行方式：解释器通过每次解释并执行一小段代码来完成Java字节码程 序的所有操作。 <br />　　通常采用的是第二种方法。由于JVM规格描述具有足够的灵活性，这使得将字节码翻译为机器代码的工作具有较高的效率。对于那些对运行速度要求较高的应用程序，解释器可将Java字节码即时编译为机器码，从而很好地保证了Java代码的可移植性和高性能。</p><p>　　二.JVM规格描述 <br />　　JVM的设计目标是提供一个基于抽象规格描述的计算机模型，为解释程序开发人员提很好的灵活性，同时也确保Java代码可在符合该规范的任何系统上运行。JVM对其实现的某些方面给出了具体的定义，特别是对Java可执行代码，即字节码(Bytecode)的格式给出了明确的规格。这一规格包括操作码和操作数的语法和数值、标识符的数值表示方式、以及Java类文件中的Java对象、常量缓冲池在JVM的存储映象。这些定义为JVM解释器开发人员提供了所需的信息和开发环境。Java的设计者希望给开发人员以随心所欲使用Java的自由。 <br />　　JVM定义了控制Java代码解释执行和具体实现的五种规格，它们是： <br />　　JVM指令系统 <br />　　JVM寄存器 <br />　　JVM栈结构 <br />　　JVM碎片回收堆 <br />　　JVM存储区 <br />　　2.1JVM指令系统 <br />JVM指令系统同其他计算机的指令系统极其相似。Java指令也是由 操作码和操作数两部分组成。操作码为8位二进制数，操作数进紧随在操作码的后面，其长度根据需要而不同。操作码用于指定一条指令操作的性质（在这里我们采用汇编符号的形式进行说明），如iload表示从存储器中装入一个整数，anewarray表示为一个新数组分配空间，iand表示两个整数的"与"，ret用于流程控制，表示从对某一方法的调用中返回。当长度大于8位时，操作数被分为两个以上字节存放。JVM采用了"big endian"的编码方式来处理这种情况，即高位bits存放在低字节中。这同 Motorola及其他的RISC CPU采用的编码方式是一致的，而与Intel采用的"little endian "的编码方式即低位bits存放在低位字节的方法不同。 <br />　　Java指令系统是以Java语言的实现为目的设计的，其中包含了用于调用方法和监视多先程系统的指令。Java的8位操作码的长度使得JVM最多有256种指令，目前已使用了160多种操作码。 <br />　　2.2JVM指令系统 <br />所有的CPU均包含用于保存系统状态和处理器所需信息的寄存器组。如果虚拟机定义较多的寄存器，便可以从中得到更多的信息而不必对栈或内存进行访问，这有利于提高运行速度。然而，如果虚拟机中的寄存器比实际CPU的寄存器多，在实现虚拟机时就会占用处理器大量的时间来用常规存储器模拟寄存器，这反而会降低虚拟机的效率。针对这种情况，JVM只设置了4个最为常用的寄存器。它们是： <br />　　pc程序计数器 <br />　　optop操作数栈顶指针 <br />　　frame当前执行环境指针 <br />　　vars指向当前执行环境中第一个局部变量的指针 <br />所有寄存器均为32位。pc用于记录程序的执行。optop,frame和vars用于记录指向Java栈区的指针。 <br />　　2.3JVM栈结构 <br />　　作为基于栈结构的计算机，Java栈是JVM存储信息的主要方法。当JVM得到一个Java字节码应用程序后，便为该代码中一个类的每一个方法创建一个栈框架，以保存该方法的状态信息。每个栈框架包括以下三类信息： <br />　　局部变量 <br />　　执行环境 <br />　　操作数栈<br />局部变量用于存储一个类的方法中所用到的局部变量。vars寄存器指向该变量表中的第一个局部变量。 <br />　　执行环境用于保存解释器对Java字节码进行解释过程中所需的信息。它们是：上次调用的方法、局部变量指针和操作数栈的栈顶和栈底指针。执行环境是一个执行一个方法的控制中心。例如：如果解释器要执行iadd(整数加法)，首先要从frame寄存器中找到当前执行环境，而后便从执行环境中找到操作数栈，从栈顶弹出两个整数进行加法运算，最后将结果压入栈顶。 <br />操作数栈用于存储运算所需操作数及运算的结果。 <br />　　2.4JVM碎片回收堆 <br />　　Java类的实例所需的存储空间是在堆上分配的。解释器具体承担为类实例分配空间的工作。解释器在为一个实例分配完存储空间后，便开始记录对该实例所占用的内存区域的使用。一旦对象使用完毕，便将其回收到堆中。 <br />在Java语言中，除了new语句外没有其他方法为一对象申请和释放内存。对内存进行释放和回收的工作是由Java运行系统承担的。这允许Java运行系统的设计者自己决定碎片回收的方法。在SUN公司开发的Java解释器和Hot Java环境中，碎片回收用后台线程的方式来执行。这不但为运行系统提供了良好的性能，而且使程序设计人员摆脱了自己控制内存使用的风险。 <br />　　2.5JVM存储区 <br />JVM有两类存储区：常量缓冲池和方法区。常量缓冲池用于存储类名称、方法和字段名称以及串常量。方法区则用于存储Java方法的字节码。对于这两种存储区域具体实现方式在JVM规格中没有明确规定。这使得Java应用程序的存储布局必须在运行过程中确定，依赖于具体平台的实现方式。 <br />　　JVM是为Java字节码定义的一种独立于具体平台的规格描述，是Java平台独立性的基础。目前的JVM还存在一些限制和不足，有待于进一步的完善，但无论如何，JVM的思想是成功的。</p><p>　　对比分析：如果把Java原程序想象成我们的C++原程序，Java原程序编译后生成的字节码就相当于C++原程序编译后的80x86的机器码（二进制程序文件），JVM虚拟机相当于80x86计算机系统,Java解释器相当于80x86CPU。在80x86CPU上运行的是机器码，在Java解释器上运行的是Java字节码。<br />　　Java解释器相当于运行Java字节码的“CPU”,但该“CPU”不是通过硬件实现的，而是用软件实现的。Java解释器实际上就是特定的平台下的一个应用程序。只要实现了特定平台下的解释器程序，Java字节码就能通过解释器程序在该平台下运行，这是Java跨平台的根本。当前，并不是在所有的平台下都有相应Java解释器程序，这也是Java并不能在所有的平台下都能运行的原因，它只能在已实现了Java解释器程序的平台下运行。</p></div>
								</td>
						</tr>
				</tbody>
		</table>
<img src ="http://www.blogjava.net/nbtymm/aggbug/51722.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/nbtymm/" target="_blank">nbt</a> 2006-06-09 16:25 <a href="http://www.blogjava.net/nbtymm/archive/2006/06/09/51722.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java中一些关于日期、日期格式、日期的解析和日期的计算 (转)</title><link>http://www.blogjava.net/nbtymm/archive/2006/06/09/51716.html</link><dc:creator>nbt</dc:creator><author>nbt</author><pubDate>Fri, 09 Jun 2006 08:00:00 GMT</pubDate><guid>http://www.blogjava.net/nbtymm/archive/2006/06/09/51716.html</guid><wfw:comment>http://www.blogjava.net/nbtymm/comments/51716.html</wfw:comment><comments>http://www.blogjava.net/nbtymm/archive/2006/06/09/51716.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/nbtymm/comments/commentRss/51716.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/nbtymm/services/trackbacks/51716.html</trackback:ping><description><![CDATA[
		<div class="postText">跑系统时,难免遇到了数据量大的情况,只好让爱机彻夜工作了,自己闪人。毕竟对它不放心，这时得用到日志，日志里的时间肯定是要的啦。至少得知道他什么时候罢工吧（今天一来，我电脑就在昨天不明时间罢工了！）。下面是转自一位网友的：<br /><br />Java中一些关于日期、日期格式、日期的解析和日期的计算 <br /><p><font size="2">Java 语言的Calendar(日历),Date(日期), 和DateFormat(日期格式)组成了Java标准的一个基本但是非常重要的部分. 日期是商业逻辑计算一个关键的部分. 所有的开发者都应该能够计算未来的日期, 定制日期的显示格式, 并将文本数据解析成日期对象. 我们写了两篇文章, 这是第一篇, 我们将大概的学习日期, 日期格式, 日期的解析和日期的计算. </font></p><p><font size="2">我们将讨论下面的类: </font></p><p><font size="2">1、具体类(和抽象类相对)java.util.Date <br />2、抽象类java.text.DateFormat 和它的一个具体子类,java.text.SimpleDateFormat <br />3、抽象类java.util.Calendar 和它的一个具体子类,java.util.GregorianCalendar </font></p><p><font size="2">具体类可以被实例化, 但是抽象类却不能. 你首先必须实现抽象类的一个具体子类. </font></p><p><font size="2">Date 类从Java 开发包(JDK) 1.0 就开始进化, 当时它只包含了几个取得或者设置一个日期数据的各个部分的方法, 比如说月, 日, 和年. 这些方法现在遭到了批评并且已经被转移到了Calendar类里去了, 我们将在本文中进一步讨论它. 这种改进旨在更好的处理日期数据的国际化格式. 就象在JDK 1.1中一样, Date 类实际上只是一个包裹类, 它包含的是一个长整型数据, 表示的是从GMT(格林尼治标准时间)1970年, 1 月 1日00:00:00这一刻之前或者是之后经历的毫秒数. </font></p><p><font size="2">一、创建一个日期对象 </font></p><p><font size="2">让我们看一个使用系统的当前日期和时间创建一个日期对象并返回一个长整数的简单例子. 这个时间通常被称为Java 虚拟机(JVM)主机环境的系统时间. <br />//------------------------------------------------------<br />import java.util.Date; </font></p><p><font size="2">public class DateExample1 <br />{ <br />public static void main(String[] args)<br />{ <br />// Get the system date/time <br />Date date = new Date(); </font></p><p><font size="2">System.out.println(date.getTime()); <br />} <br />} <br />//------------------------------------------------------</font><font size="2"></font></p><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; HEIGHT: 27px; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000">1145681088396<br /></span></div><p><br />在星期六, 2001年9月29日, 下午大约是6:50的样子, 上面的例子在系统输出设备上显示的结果是 1001803809710. 在这个例子中,值得注意的是我们使用了Date 构造函数创建一个日期对象, 这个构造函数没有接受任何参数. 而这个构造函数在内部使用了System.currentTimeMillis() 方法来从系统获取日期. </p><p><font size="2">那么, 现在我们已经知道了如何获取从1970年1月1日开始经历的毫秒数了. 我们如何才能以一种用户明白的格式来显示这个日期呢? 在这里类java.text.SimpleDateFormat 和它的抽象基类 java.text.DateFormat 就派得上用场了. </font></p><p><font size="2">二、日期数据的定制格式 </font></p><p><font size="2">假如我们希望定制日期数据的格式, 比方星期六-9月-29日-2001年. 下面的例子展示了如何完成这个工作: </font></p><p><font size="2">//------------------------------------------------------<br />import java.text.SimpleDateFormat; <br />import java.util.Date; </font></p><p><font size="2">public class DateExample2 <br />{ </font></p><p><font size="2">public static void main(String[] args) <br />{ </font></p><p><font size="2">SimpleDateFormat bartDateFormat = <br />new SimpleDateFormat("EEEE-MMMM-dd-yyyy"); </font></p><p><font size="2">Date date = new Date(); </font></p><p><font size="2">System.out.println(bartDateFormat.format(date)); <br />} <br />} <br />//------------------------------------------------------<br /><br /></font></p><p><font size="2"></font></p><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /><span style="COLOR: #000000">星期六-四月-22-2006</span></div><p><br />只要通过向SimpleDateFormat 的构造函数传递格式字符串"EEE-MMMM-dd-yyyy", 我们就能够指明自己想要的格式. 你应该可以看见, 格式字符串中的ASCII 字符告诉格式化函数下面显示日期数据的哪一个部分. EEEE是星期, MMMM是月, dd是日, yyyy是年. 字符的个数决定了日期是如何格式化的.传递"EE-MM-dd-yy"会显示 Sat-09-29-01. 请察看Sun 公司的Web 站点获取日期格式化选项的完整的指示.</p><p><font size="2">三、将文本数据解析成日期对象 </font></p><p><font size="2">假设我们有一个文本字符串包含了一个格式化了的日期对象, 而我们希望解析这个字符串并从文本日期数据创建一个日期对象. 我们将再次以格式化字符串"MM-dd-yyyy" 调用SimpleDateFormat类, 但是这一次, 我们使用格式化解析而不是生成一个文本日期数据. 我们的例子, 显示在下面, 将解析文本字符串"9-29-2001"并创建一个值为001736000000 的日期对象. </font></p><p><font size="2">//------------------------------------------------------<br />import java.text.SimpleDateFormat; <br />import java.util.Date; </font></p><p><font size="2">public class DateExample3 <br />{ </font></p><p><font size="2">public static void main(String[] args) <br />{ <br />// Create a date formatter that can parse dates of <br />// the form MM-dd-yyyy. <br />SimpleDateFormat bartDateFormat = <br />new SimpleDateFormat("MM-dd-yyyy"); </font></p><p><font size="2">// Create a string containing a text date to be parsed. <br />String dateStringToParse = "9-29-2001"; </font></p><p><font size="2">try { <br />// Parse the text version of the date. <br />// We have to perform the parse method in a <br />// try-catch construct in case dateStringToParse <br />// does not contain a date in the format we are expecting. <br />Date date = bartDateFormat.parse(dateStringToParse); </font></p><p><font size="2">// Now send the parsed date as a long value <br />// to the system output. <br />System.out.println(date.getTime()); <br />} <br />catch (Exception ex) { <br />System.out.println(ex.getMessage()); <br />} <br />} <br />} <br />//------------------------------------------------------<br /></font></p><p><font size="2"></font></p><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /><span style="COLOR: #000000">1001692800000</span></div><p><br /><br />四、使用标准的日期格式化过程 </p><p><font size="2">既然我们已经可以生成和解析定制的日期格式了, 让我们来看一看如何使用内建的格式化过程. 方法 DateFormat.getDateTimeInstance() 让我们得以用几种不同的方法获得标准的日期格式化过程. 在下面的例子中, 我们获取了四个内建的日期格式化过程. 它们包括一个短的, 中等的, 长的, 和完整的日期格式. </font></p><p><font size="2">//------------------------------------------------------<br />import java.text.DateFormat; <br />import java.util.Date; </font></p><p><font size="2">public class DateExample4 <br />{ </font></p><p><font size="2">public static void main(String[] args) <br />{ <br />Date date = new Date(); </font></p><p><font size="2">DateFormat shortDateFormat = <br />DateFormat.getDateTimeInstance( <br />DateFormat.SHORT, <br />DateFormat.SHORT); </font></p><p><font size="2">DateFormat mediumDateFormat = <br />DateFormat.getDateTimeInstance( <br />DateFormat.MEDIUM, <br />DateFormat.MEDIUM); </font></p><p><font size="2">DateFormat longDateFormat = <br />DateFormat.getDateTimeInstance( <br />DateFormat.LONG, <br />DateFormat.LONG); </font></p><p><font size="2">DateFormat fullDateFormat = <br />DateFormat.getDateTimeInstance( <br />DateFormat.FULL, <br />DateFormat.FULL); </font></p><p><font size="2">System.out.println(shortDateFormat.format(date)); <br />System.out.println(mediumDateFormat.format(date)); <br />System.out.println(longDateFormat.format(date)); <br />System.out.println(fullDateFormat.format(date)); <br />} <br />} <br />//------------------------------------------------------<br /></font></p><p><font size="2"></font></p><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /><span style="COLOR: #000000">01-9-29 上午12:00<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />2001-9-29 0:00:00<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />2001年9月29日 上午12时00分00秒<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />2001年9月29日 星期六 上午12时00分00秒 CST</span></div><p><br />注意我们在对 getDateTimeInstance的每次调用中都传递了两个值. 第一个参数是日期风格, 而第二个参数是时间风格. 它们都是基本数据类型int(整型). 考虑到可读性, 我们使用了DateFormat 类提供的常量: SHORT, MEDIUM, LONG, 和 FULL. 要知道获取时间和日期格式化过程的更多的方法和选项, 请看Sun 公司Web 站点上的解释. </p><p><font size="2">运行我们的例子程序的时候, 它将向标准输出设备输出下面的内容: <br />9/29/01 8:44 PM <br />Sep 29, 2001 8:44:45 PM <br />September 29, 2001 8:44:45 PM EDT <br />Saturday, September 29, 2001 8:44:45 PM EDT</font></p><p><font size="2">五、Calendar 类 </font></p><p><font size="2">我们现在已经能够格式化并创建一个日期对象了, 但是我们如何才能设置和获取日期数据的特定部分呢, 比如说小时, 日, 或者分钟? 我们又如何在日期的这些部分加上或者减去值呢? 答案是使用Calendar 类. 就如我们前面提到的那样, Calendar 类中的方法替代了Date 类中被人唾骂的方法. </font></p><p><font size="2">假设你想要设置, 获取, 和操纵一个日期对象的各个部分, 比方一个月的一天或者是一个星期的一天. 为了演示这个过程, 我们将使用具体的子类 java.util.GregorianCalendar. 考虑下面的例子, 它计算得到下面的第十个星期五是13号. </font></p><p><font size="2">//------------------------------------------------------<br />import java.util.GregorianCalendar; <br />import java.util.Date; <br />import java.text.DateFormat; </font></p><p><font size="2">public class DateExample5 <br />{ </font></p><p><font size="2">public static void main(String[] args) <br />{ <br />DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.FULL); </font></p><p><font size="2">// Create our Gregorian Calendar. <br />GregorianCalendar cal = new GregorianCalendar(); <br /><br />// Set the date and time of our calendar <br />// to the system&amp;s date and time <br />cal.setTime(new Date()); </font></p><p><font size="2">System.out.println("System Date: " + <br />dateFormat.format(cal.getTime()));<br /><br />System.out.println("Befor Setting Day of Week to Friday: " + <br />dateFormat.format(cal.getTime()));  <br /></font></p><p><font size="2">// Set the day of week to FRIDAY <br />cal.set(GregorianCalendar.DAY_OF_WEEK, <br />GregorianCalendar.FRIDAY); <br />System.out.println("After Setting Day of Week to Friday: " + <br />dateFormat.format(cal.getTime())); </font></p><p><font size="2">int friday13Counter = 0; <br /><br />while (friday13Counter &lt;= 10) <br />{ </font></p><p><font size="2">// Go to the next Friday by adding 7 days. <br />cal.add(GregorianCalendar.DAY_OF_MONTH, 7); </font></p><p><font size="2">// If the day of month is 13 we have <br />// another Friday the 13th. <br />if (cal.get(GregorianCalendar.DAY_OF_MONTH) == 13) <br />{ <br />friday13Counter++; <br />System.out.println(dateFormat.format(cal.getTime())); <br />} <br />} <br />} <br />} <br />//------------------------------------------------------<br /></font></p><p><font size="2"></font></p><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">    Befor Setting Day of Week to Friday: 2006年4月22日 星期六<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /><span style="COLOR: #000000">After Setting Day of Week to Friday: 2006年4月21日 星期五<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />2006年10月13日 星期五<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />2007年4月13日 星期五<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />2007年7月13日 星期五<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />2008年6月13日 星期五<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />2009年2月13日 星期五<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />2009年3月13日 星期五<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />2009年11月13日 星期五<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />2010年8月13日 星期五<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />2011年5月13日 星期五<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />2012年1月13日 星期五<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />2012年4月13日 星期五</span></div><p><br /><br />在这个例子中我们作了有趣的函数调用: <br />cal.set(GregorianCalendar.DAY_OF_WEEK, <br />GregorianCalendar.FRIDAY); </p><p><font size="2">和: <br />cal.add(GregorianCalendar.DAY_OF_MONTH, 7); </font></p><p><font size="2">set 方法能够让我们通过简单的设置星期中的哪一天这个域来将我们的时间调整为星期五. 注意到这里我们使用了常量 DAY_OF_WEEK 和 FRIDAY来增强代码的可读性. add 方法让我们能够在日期上加上数值. 润年的所有复杂的计算都由这个方法自动处理. </font></p><p><font size="2">我们这个例子的输出结果是: <br />System Date: Saturday, September 29, 2001 <br />当我们将它设置成星期五以后就成了: Friday, September 28, 2001 <br />Friday, September 13, 2002 <br />Friday, December 13, 2002 <br />Friday, June 13, 2003 <br />Friday, February 13, 2004 <br />Friday, August 13, 2004 <br />Friday, May 13, 2005 <br />Friday, January 13, 2006 <br />Friday, October 13, 2006 <br />Friday, April 13, 2007 <br />Friday, July 13, 2007 <br />Friday, June 13, 2008 </font></p><p><font size="2">六、时间掌握在你的手里 </font></p><p><font size="2">有了这些Date 和Calendar 类的例子, 你应该能够使用 java.util.Date, java.text.SimpleDateFormat, 和 java.util.GregorianCalendar 创建许多方法了. </font></p></div>
<img src ="http://www.blogjava.net/nbtymm/aggbug/51716.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/nbtymm/" target="_blank">nbt</a> 2006-06-09 16:00 <a href="http://www.blogjava.net/nbtymm/archive/2006/06/09/51716.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java容器集合学习心得</title><link>http://www.blogjava.net/nbtymm/archive/2006/06/09/51713.html</link><dc:creator>nbt</dc:creator><author>nbt</author><pubDate>Fri, 09 Jun 2006 07:57:00 GMT</pubDate><guid>http://www.blogjava.net/nbtymm/archive/2006/06/09/51713.html</guid><wfw:comment>http://www.blogjava.net/nbtymm/comments/51713.html</wfw:comment><comments>http://www.blogjava.net/nbtymm/archive/2006/06/09/51713.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/nbtymm/comments/commentRss/51713.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/nbtymm/services/trackbacks/51713.html</trackback:ping><description><![CDATA[
		<font color="#008000">在Java中有许多的容器集合。初一看起来有些糊涂，特别是对刚接触Java来说（至少我当初就是这样的）！其实稍微细心，深入一点点就会发现原来一切都是有规律的。我想别的事情也会是如此。<br />       Java中的容器，接口都是由一些接口，抽象类及它们的实现类所组成。而它们全部封装在java.util<br />包中。<br /><br /><br /></font>
		<font color="#008000">
				<strong>1：Collection接口。<br /><br /></strong>       大多数的集合都实现了此接口，它基本方法是add（没有get()方法，实现类中可能有如Arrylist)，添加一对象。添加成功则返回true ,否则返回false。这是与Map不同的地方。还有一些常用的方法如iterator(),size(),toArray()(注：toArray()是返回一对象----object数组，而Arrays----也是java.util下的一个类，有一个asList方法它们通常认为是各集合之间转换的桥梁)等等！具体用法可以参考API文档。<br /><br /><br /><strong>2：Map</strong>(映射)<br />       Map接口跟Collection接口实际上没有半点关系。集合中的每一个元素都包含一对键对对象和值对象，集合中没有重复的键对象，值对象可以重复。它的有些实现类能对集合中的键对象进行排序。与Collection截然不同的是，它其中所存取的是一些值与名相对应的数据。也就是一个Key对应一个Value的方式来存储。所以它就有与之对应的一些方法如：put (K key, V value)等等，更多可以参考API文档。<br /><br /><strong>3：List(列表)</strong><br />      集合中的对象按索引位置排序，可以有重复对象，允许按照对象在集合中的索引位置检索对象<br /><br /><strong>4：Set(集)</strong><br />      集合中的对象中按特定的方式排序，并且没有重复对象。它的有些实现类能对集合中的对象<br />按特定的方式排序<br /><br /><strong>5：迭代器：Iterator</strong><br />       它是一个接口，只有三个方法hasnext(),next(),remove()只有最后一个是可选的,也就是remove()是可选（在实现的时候）。其可选性也意味着它的实现类中，remove方法是可有可无的。例如，若有一个如下的List 实例。<br />         </font>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<font color="#008000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				</font>
				<span style="COLOR: #000000">
						<font color="#008000">    Arrylist al </font>
				</span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #0000ff">new</span>
				<span style="COLOR: #000000"> Arrylist();<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />    Object[] ob </span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000"> al.toArray();<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />    List list </span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000"> Arrays.asList(ob);<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />    Iterator itor </span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000"> list.iterator();<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />    itor.remove();      </span>
				<span style="COLOR: #008000">//</span>
				<span style="COLOR: #008000">Error <br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /></span>
		</div>
		<br />        当调用Ierator itr = list.iterator()方法返回一迭代器的时候，便不支持remove方法，所以当你再使用irt.remove()时程序就是异常！<br /><br />        使用此迭代器要注意的是remove()方法。它所删除的是指指针（暂这么叫着）上次所移经过的位置（Removes from the underlying collection the last element returned by the iterator (optional operation).）。我个人觉得有点象在JDBC中的ResultSet rs = ....;rs.last();rowsCount=rs.getRow();类似呢。<br />        前面所讲的，由于clollection提供了iterator()方法，所以迭代器是很容易实现的！<br /><br /><font color="#008000"><strong>6：常用实现类的一些继承关系：</strong><br /><br />        <strong>Collections</strong>，它是Java.util下的一个类。它为我们提供了许多有用的方法，如sort(...),max()等其具体用法可以参考API文档，比如sort(List list);中list内的所有元素都必须实现<font face="Courier New">Comparable接口（All elements in the list must implement the <tt>Comparable</tt> interface）。<br /></font><br />      </font><font color="#008000"><em><strong>Arrylist</strong></em>，它是List接口的实现类，而List则是继承于Collection。<br />       <strong><em>LinkedList</em></strong>，它也是间接对Colections的实现。用linkedlist的一些方法如addfirst(),removefirst(),addlast()等等可以用来实现如C中的堆栈，链表。（对于频繁使用插入与删除操作使用linkedlist是个不错的选择，对于经常进行索引操作则arrylist较好）。</font><br /><br />        <font color="#008000"><strong><em>HashSet</em></strong>（散列表），它实现了Set接口，也就意味着它的元素不能有重复值出现。并且在HashSet中没有get()方法，但可以通过iterator()来实现。要注意的是假如要在HasSet中存放一些对象，那么你得重定义hashCode()与equals()二个方法来保不可以存放相同的内容的元素。对于hashcode()所返回的值，hashset用它来计算（通过特定的函数）该对象在内存中的存放位置；后者主要用来判断二个对象的内容是否相等而返回对应的boolen型。<br />       <strong><em>TreeSet</em></strong>，主要用来对元素进行排序操作，假如要往其中添加对象，则对象得实现</font><font face="Courier New" color="#008000"><font color="#008000">Comparable接口。（假如不要对元素排序，则一般可选用HashSet）。</font><br /><br /></font>       <font color="#008000"><strong><em>HashMap</em></strong>，主要特点是存放的一个键值对，一些有用的方法是可返回视图（我觉得可以把它理解为一个集合）如：keyset(),values(),entyset()等。<br />        <strong><em>TreeMap</em></strong>，它与HashMap差不多，不过是增加了对元素的排序功能，所以运行速度也就当然没有hashmap来得快了。<br />         以下是HashMap的一个实例(在对DB进行操作的时候很有用):<br /></font><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /><span style="COLOR: #000000">HashMap valueMap;<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">this function just get key-value form DB ,defined by yourself</span><span style="COLOR: #008000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #000000">valueMap </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> commondb.getElementStringValues(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">COMMENT_ID</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">, </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">content</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />java.util.Set tempkeys </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> valueMap.entrySet();<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />            java.util.Iterator keys </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> tempkeys.iterator();<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">(keys.hasNext())<br /><img id="Codehighlighter1_273_390_Open_Image" onclick="this.style.display='none'; Codehighlighter1_273_390_Open_Text.style.display='none'; Codehighlighter1_273_390_Closed_Image.style.display='inline'; Codehighlighter1_273_390_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_273_390_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_273_390_Closed_Text.style.display='none'; Codehighlighter1_273_390_Open_Image.style.display='inline'; Codehighlighter1_273_390_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top" />                </span><span id="Codehighlighter1_273_390_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/images/dot.gif" /></span><span id="Codehighlighter1_273_390_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />                    java.util.Map.Entry me</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">(java.util.Map.Entry)keys.next();<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />String value </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> me.getValue();<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> key </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> me.getKey();<br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /></span></div><br />       <font color="#ff1493">要注意的是entrySet()所返回的每一个元素都是Map.Entry类型的!(<font color="#000000">Returns a collection view of the mappings contained in this map. Each element in the returned collection is a <tt>Map.Entry</tt>.</font>)</font>      <br /> <br /><font color="#008000"><strong><em>       Properties</em></strong>，继承于hashtable。这个东东相信我们比较的喜欢了（在i18n,ant中可以是常见得很），呵呵。它可以从外部导入属性文件。文件中的键值都是String类型。just like this:<br /></font>         
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /><span style="COLOR: #000000">company</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">study<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />author</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">Jkallen<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />copyright</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">2005</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">2006</span></div>       <br />        <font color="#008000"> 操作如下：<br /></font>        
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /><span style="COLOR: #0000ff">import</span><span style="COLOR: #000000"> java.util.</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">;<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #0000ff">import</span><span style="COLOR: #000000"> java.io.</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">;<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> PropTest<br /><img id="Codehighlighter1_53_545_Open_Image" onclick="this.style.display='none'; Codehighlighter1_53_545_Open_Text.style.display='none'; Codehighlighter1_53_545_Closed_Image.style.display='inline'; Codehighlighter1_53_545_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_53_545_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_53_545_Closed_Text.style.display='none'; Codehighlighter1_53_545_Open_Image.style.display='inline'; Codehighlighter1_53_545_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span><span id="Codehighlighter1_53_545_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/images/dot.gif" /></span><span id="Codehighlighter1_53_545_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> main(String[] args)<br /><img id="Codehighlighter1_96_543_Open_Image" onclick="this.style.display='none'; Codehighlighter1_96_543_Open_Text.style.display='none'; Codehighlighter1_96_543_Closed_Image.style.display='inline'; Codehighlighter1_96_543_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_96_543_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_96_543_Closed_Text.style.display='none'; Codehighlighter1_96_543_Open_Image.style.display='inline'; Codehighlighter1_96_543_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span><span id="Codehighlighter1_96_543_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/images/dot.gif" /></span><span id="Codehighlighter1_96_543_Open_Text"><span style="COLOR: #000000">{<br /><img id="Codehighlighter1_100_165_Open_Image" onclick="this.style.display='none'; Codehighlighter1_100_165_Open_Text.style.display='none'; Codehighlighter1_100_165_Closed_Image.style.display='inline'; Codehighlighter1_100_165_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_100_165_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_100_165_Closed_Text.style.display='none'; Codehighlighter1_100_165_Open_Image.style.display='inline'; Codehighlighter1_100_165_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />        </span><span id="Codehighlighter1_100_165_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">/**/</span><span id="Codehighlighter1_100_165_Open_Text"><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">Properties pps=System.getProperties();<br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />        pps.list(System.out);</span><span style="COLOR: #008000">*/</span></span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />        Properties pps</span><span style="COLOR: #000000">=</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> Properties();<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />        </span><span style="COLOR: #0000ff">try</span><span style="COLOR: #000000"><br /><img id="Codehighlighter1_210_487_Open_Image" onclick="this.style.display='none'; Codehighlighter1_210_487_Open_Text.style.display='none'; Codehighlighter1_210_487_Closed_Image.style.display='inline'; Codehighlighter1_210_487_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_210_487_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_210_487_Closed_Text.style.display='none'; Codehighlighter1_210_487_Open_Image.style.display='inline'; Codehighlighter1_210_487_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />        </span><span id="Codehighlighter1_210_487_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/images/dot.gif" /></span><span id="Codehighlighter1_210_487_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />            pps.load(</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> FileInputStream(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">winsun.ini</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">));<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />            Enumeration </span><span style="COLOR: #0000ff">enum</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">pps.propertyNames();<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />            </span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">(</span><span style="COLOR: #0000ff">enum</span><span style="COLOR: #000000">.hasMoreElements())<br /><img id="Codehighlighter1_337_483_Open_Image" onclick="this.style.display='none'; Codehighlighter1_337_483_Open_Text.style.display='none'; Codehighlighter1_337_483_Closed_Image.style.display='inline'; Codehighlighter1_337_483_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_337_483_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_337_483_Closed_Text.style.display='none'; Codehighlighter1_337_483_Open_Image.style.display='inline'; Codehighlighter1_337_483_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />            </span><span id="Codehighlighter1_337_483_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/images/dot.gif" /></span><span id="Codehighlighter1_337_483_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />                String strKey</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">(String)</span><span style="COLOR: #0000ff">enum</span><span style="COLOR: #000000">.nextElement();<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />                String strValue</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">pps.getProperty(strKey);<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />                <br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />                System.out.println(strKey</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">strValue);<br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />            }</span></span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />        }</span></span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />        </span><span style="COLOR: #0000ff">catch</span><span style="COLOR: #000000">(Exception e)<br /><img id="Codehighlighter1_512_540_Open_Image" onclick="this.style.display='none'; Codehighlighter1_512_540_Open_Text.style.display='none'; Codehighlighter1_512_540_Closed_Image.style.display='inline'; Codehighlighter1_512_540_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_512_540_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_512_540_Closed_Text.style.display='none'; Codehighlighter1_512_540_Open_Image.style.display='inline'; Codehighlighter1_512_540_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />        </span><span id="Codehighlighter1_512_540_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/images/dot.gif" /></span><span id="Codehighlighter1_512_540_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />            e.printStackTrace();<br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />        }</span></span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</span></span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span></div><br />       <font color="#008000"> 其用法可以查看API文档呢。<br /><br />        Java中的集合容器确实不少呢...其中有些我们也许一直都用不到，（我也是查看了些相关的资料再加上自己的一些想法整理了一下，希望对相关朋友有用！）可是重要的是知道我们在实现一个功能时应该选用哪种集合类来实现就OK了。</font><img src ="http://www.blogjava.net/nbtymm/aggbug/51713.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/nbtymm/" target="_blank">nbt</a> 2006-06-09 15:57 <a href="http://www.blogjava.net/nbtymm/archive/2006/06/09/51713.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入理解abstract class和interface</title><link>http://www.blogjava.net/nbtymm/archive/2006/06/09/51701.html</link><dc:creator>nbt</dc:creator><author>nbt</author><pubDate>Fri, 09 Jun 2006 07:42:00 GMT</pubDate><guid>http://www.blogjava.net/nbtymm/archive/2006/06/09/51701.html</guid><wfw:comment>http://www.blogjava.net/nbtymm/comments/51701.html</wfw:comment><comments>http://www.blogjava.net/nbtymm/archive/2006/06/09/51701.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/nbtymm/comments/commentRss/51701.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/nbtymm/services/trackbacks/51701.html</trackback:ping><description><![CDATA[
		<table class="fixedTable blogpost" cellspacing="0" width="100%" border="0">
				<tbody>
						<tr>
								<td class="ellipse">
								</td>
						</tr>
						<tr>
								<td class="bvh8">
										<strong>
										</strong>
								</td>
						</tr>
						<tr>
								<td id="msgcns!48122F59260F24A8!112">
										<div>abstract class和interface是Java语言中对于抽象类定义进行支持的两种机制，正是由于这两种机制的存在，才赋予了Java强大的面向对象能力。abstract class和interface之间在对于抽象类定义的支持方面具有很大的相似性，甚至可以相互替换，因此很多开发者在进行抽象类定义时对于abstract class和interface的选择显得比较随意。其实，两者之间还是有很大的区别的，对于它们的选择甚至反映出对于问题领域本质的理解、对于设计意图的理解是否正确、合理。本文将对它们之间的区别进行一番剖析，试图给开发者提供一个在二者之间进行选择的依据。 <br /><br />理解抽象类 <br /><br />abstract class和interface在Java语言中都是用来进行抽象类（本文中的抽象类并非从abstract class翻译而来，它表示的是一个抽象体，而abstract class为Java语言中用于定义抽象类的一种方法，请读者注意区分）定义的，那么什么是抽象类，使用抽象类能为我们带来什么好处呢？ <br /><br />在面向对象的概念中，我们知道所有的对象都是通过类来描绘的，但是反过来却不是这样。并不是所有的类都是用来描绘对象的，如果一个类中没有包含足够的信息来描绘一个具体的对象，这样的类就是抽象类。抽象类往往用来表征我们在对问题领域进行分析、设计中得出的抽象概念，是对一系列看上去不同，但是本质上相同的具体概念的抽象。比如：如果我们进行一个图形编辑软件的开发，就会发现问题领域存在着圆、三角形这样一些具体概念，它们是不同的，但是它们又都属于形状这样一个概念，形状这个概念在问题领域是不存在的，它就是一个抽象概念。正是因为抽象的概念在问题领域没有对应的具体概念，所以用以表征抽象概念的抽象类是不能够实例化的。 <br /><br />在面向对象领域，抽象类主要用来进行类型隐藏。我们可以构造出一个固定的一组行为的抽象描述，但是这组行为却能够有任意个可能的具体实现方式。这个抽象描述就是抽象类，而这一组任意个可能的具体实现则表现为所有可能的派生类。模块可以操作一个抽象体。由于模块依赖于一个固定的抽象体，因此它可以是不允许修改的；同时，通过从这个抽象体派生，也可扩展此模块的行为功能。熟悉OCP的读者一定知道，为了能够实现面向对象设计的一个最核心的原则OCP(Open-Closed Principle)，抽象类是其中的关键所在。 <br /><br /><br />从语法定义层面看abstract class和interface <br /><br />在语法层面，Java语言对于abstract class和interface给出了不同的定义方式，下面以定义一个名为Demo的抽象类为例来说明这种不同。 <br /><br />使用abstract class的方式定义Demo抽象类的方式如下： <br /><br />abstract class Demo ｛ <br /> abstract void method1(); <br /> abstract void method2(); <br /> … <br />｝ <br /><br />使用interface的方式定义Demo抽象类的方式如下： <br /><br />interface Demo { <br /> void method1(); <br /> void method2(); <br /> … <br />} <br /><br />在abstract class方式中，Demo可以有自己的数据成员，也可以有非abstarct的成员方法，而在interface方式的实现中，Demo只能够有静态的不能被修改的数据成员（也就是必须是static final的，不过在interface中一般不定义数据成员），所有的成员方法都是abstract的。从某种意义上说，interface是一种特殊形式的abstract class。 <br /><br />      从编程的角度来看，abstract class和interface都可以用来实现"design by contract"的思想。但是在具体的使用上面还是有一些区别的。 <br /><br />首先，abstract class在Java语言中表示的是一种继承关系，一个类只能使用一次继承关系。但是，一个类却可以实现多个interface。也许，这是Java语言的设计者在考虑Java对于多重继承的支持方面的一种折中考虑吧。 <br /><br />其次，在abstract class的定义中，我们可以赋予方法的默认行为。但是在interface的定义中，方法却不能拥有默认行为，为了绕过这个限制，必须使用委托，但是这会 增加一些复杂性，有时会造成很大的麻烦。 <br /><br />在抽象类中不能定义默认行为还存在另一个比较严重的问题，那就是可能会造成维护上的麻烦。因为如果后来想修改类的界面（一般通过abstract class或者interface来表示）以适应新的情况（比如，添加新的方法或者给已用的方法中添加新的参数）时，就会非常的麻烦，可能要花费很多的时间（对于派生类很多的情况，尤为如此）。但是如果界面是通过abstract class来实现的，那么可能就只需要修改定义在abstract class中的默认行为就可以了。 <br /><br />同样，如果不能在抽象类中定义默认行为，就会导致同样的方法实现出现在该抽象类的每一个派生类中，违反了"one rule，one place"原则，造成代码重复，同样不利于以后的维护。因此，在abstract class和interface间进行选择时要非常的小心。 <br /><br /><br />从设计理念层面看abstract class和interface <br /><br />上面主要从语法定义和编程的角度论述了abstract class和interface的区别，这些层面的区别是比较低层次的、非本质的。本小节将从另一个层面：abstract class和interface所反映出的设计理念，来分析一下二者的区别。作者认为，从这个层面进行分析才能理解二者概念的本质所在。 <br /><br />前面已经提到过，abstarct class在Java语言中体现了一种继承关系，要想使得继承关系合理，父类和派生类之间必须存在"is a"关系，即父类和派生类在概念本质上应该是相同的（参考文献〔3〕中有关于"is a"关系的大篇幅深入的论述，有兴趣的读者可以参考）。对于interface 来说则不然，并不要求interface的实现者和interface定义在概念本质上是一致的，仅仅是实现了interface定义的契约而已。为了使论述便于理解，下面将通过一个简单的实例进行说明。 <br /><br />考虑这样一个例子，假设在我们的问题领域中有一个关于Door的抽象概念，该Door具有执行两个动作open和close，此时我们可以通过abstract class或者interface来定义一个表示该抽象概念的类型，定义方式分别如下所示： <br /><br />使用abstract class方式定义Door： <br /><br />abstract class Door { <br /> abstract void open(); <br /> abstract void close()； <br />} <br /><br />  <br />使用interface方式定义Door： <br /><br /><br />interface Door { <br /> void open(); <br /> void close(); <br />} <br /><br />  <br />其他具体的Door类型可以extends使用abstract class方式定义的Door或者implements使用interface方式定义的Door。看起来好像使用abstract class和interface没有大的区别。 <br /><br />如果现在要求Door还要具有报警的功能。我们该如何设计针对该例子的类结构呢（在本例中，主要是为了展示abstract class和interface反映在设计理念上的区别，其他方面无关的问题都做了简化或者忽略）？下面将罗列出可能的解决方案，并从设计理念层面对这些不同的方案进行分析。 <br /><br />解决方案一： <br /><br />简单的在Door的定义中增加一个alarm方法，如下： <br /><br />abstract class Door { <br /> abstract void open(); <br /> abstract void close()； <br /> abstract void alarm(); <br />} <br /><br />  <br />或者 <br /><br />interface Door { <br /> void open(); <br /> void close(); <br /> void alarm(); <br />} <br /><br />  <br />那么具有报警功能的AlarmDoor的定义方式如下： <br /><br />class AlarmDoor extends Door { <br /> void open() { … } <br /> void close() { … } <br /> void alarm() { … } <br />} <br /><br />  <br />或者 <br /><br />class AlarmDoor implements Door ｛ <br /> void open() { … } <br /> void close() { … } <br /> void alarm() { … } <br />｝ <br /><br />这种方法违反了面向对象设计中的一个核心原则ISP（Interface Segregation Priciple），在Door的定义中把Door概念本身固有的行为方法和另外一个概念"报警器"的行为方法混在了一起。这样引起的一个问题是那些仅仅依赖于Door这个概念的模块会因为"报警器"这个概念的改变（比如：修改alarm方法的参数）而改变，反之依然。 <br /><br />解决方案二： <br /><br />既然open、close和alarm属于两个不同的概念，根据ISP原则应该把它们分别定义在代表这两个概念的抽象类中。定义方式有：这两个概念都使用abstract class方式定义；两个概念都使用interface方式定义；一个概念使用abstract class方式定义，另一个概念使用interface方式定义。 <br /><br />显然，由于Java语言不支持多重继承，所以两个概念都使用abstract class方式定义是不可行的。后面两种方式都是可行的，但是对于它们的选择却反映出对于问题领域中的概念本质的理解、对于设计意图的反映是否正确、合理。我们一一来分析、说明。 <br /><br />如果两个概念都使用interface方式来定义，那么就反映出两个问题：1、我们可能没有理解清楚问题领域，AlarmDoor在概念本质上到底是Door还是报警器？2、如果我们对于问题领域的理解没有问题，比如：我们通过对于问题领域的分析发现AlarmDoor在概念本质上和Door是一致的，那么我们在实现时就没有能够正确的揭示我们的设计意图，因为在这两个概念的定义上（均使用interface方式定义）反映不出上述含义。 <br /><br />如果我们对于问题领域的理解是：AlarmDoor在概念本质上是Door，同时它有具有报警的功能。我们该如何来设计、实现来明确的反映出我们的意思呢？前面已经说过，abstract class在Java语言中表示一种继承关系，而继承关系在本质上是"is a"关系。所以对于Door这个概念，我们应该使用abstarct class方式来定义。另外，AlarmDoor又具有报警功能，说明它又能够完成报警概念中定义的行为，所以报警概念可以通过interface方式定义。如下所示： <br /><br />abstract class Door { <br /> abstract void open(); <br /> abstract void close()； <br />} <br />interface Alarm { <br /> void alarm(); <br />} <br />class AlarmDoor extends Door implements Alarm { <br /> void open() { … } <br /> void close() { … } <br />    void alarm() { … } <br />} <br /><br />  <br />这种实现方式基本上能够明确的反映出我们对于问题领域的理解，正确的揭示我们的设计意图。其实abstract class表示的是"is a"关系，interface表示的是"like a"关系，大家在选择时可以作为一个依据，当然这是建立在对问题领域的理解上的，比如：如果我们认为AlarmDoor在概念本质上是报警器，同时又具有Door的功能，那么上述的定义方式就要反过来了。 <br /><br /><br /><br />结论 <br /><br />abstract class和interface是Java语言中的两种定义抽象类的方式，它们之间有很大的相似性。但是对于它们的选择却又往往反映出对于问题领域中的概念本质的理解、对于设计意图的反映是否正确、合理，因为它们表现了概念间的不同的关系（虽然都能够实现需求的功能）。这其实也是语言的一种的惯用法，希望读者朋友能够细细体会。<br /></div>
								</td>
						</tr>
				</tbody>
		</table>
<img src ="http://www.blogjava.net/nbtymm/aggbug/51701.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/nbtymm/" target="_blank">nbt</a> 2006-06-09 15:42 <a href="http://www.blogjava.net/nbtymm/archive/2006/06/09/51701.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java知识汇总(二)</title><link>http://www.blogjava.net/nbtymm/archive/2006/06/09/51698.html</link><dc:creator>nbt</dc:creator><author>nbt</author><pubDate>Fri, 09 Jun 2006 07:27:00 GMT</pubDate><guid>http://www.blogjava.net/nbtymm/archive/2006/06/09/51698.html</guid><wfw:comment>http://www.blogjava.net/nbtymm/comments/51698.html</wfw:comment><comments>http://www.blogjava.net/nbtymm/archive/2006/06/09/51698.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/nbtymm/comments/commentRss/51698.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/nbtymm/services/trackbacks/51698.html</trackback:ping><description><![CDATA[
		<div>
				<strong>51、垃圾回收的优点和原理。并考虑2种回收机制。<br /></strong>Java语言中一个显著的特点就是引入了垃圾回收机制，使c++程序员最头疼的内存管理的问题迎刃而解，它使得Java程序员在编写程序的时候不再需要考虑内存管理。由于有个垃圾回收机制，Java中的对象不再有"作用域"的概念，只有对象的引用才有"作用域"。垃圾回收可以有效的防止内存泄露，有效的使用可以使用的内存。垃圾回收器通常是作为一个单独的低级别的线程运行，不可预知的情况下对内存堆中已经死亡的或者长时间没有使用的对象进行清楚和回收，程序员不能实时的调用垃圾回收器对某个对象或所有对象进行垃圾回收。回收机制有分代复制垃圾回收和标记垃圾回收，增量垃圾回收。 
<p><br /><strong>52、请说出你所知道的线程同步的方法。<br /></strong>wait():使一个线程处于等待状态，并且释放所持有的对象的lock。<br />sleep():使一个正在运行的线程处于睡眠状态，是一个静态方法，调用此方法要捕捉InterruptedException异常。<br />notify():唤醒一个处于等待状态的线程，注意的是在调用此方法的时候，并不能确切的唤醒某一个等待状态的线程，而是由JVM确定唤醒哪个线程，而且不是按优先级。<br />Allnotity():唤醒所有处入等待状态的线程，注意并不是给所有唤醒线程一个对象的锁，而是让它们竞争。</p><p><strong>53、你所知道的集合类都有哪些？主要方法？<br /></strong>最常用的集合类是 List 和 Map。 List 的具体实现包括 ArrayList 和 Vector，它们是可变大小的列表，比较适合构建、存储和操作任何类型对象的元素列表。 List 适用于按数值索引访问元素的情形。 <br />Map 提供了一个更通用的元素存储方法。 Map 集合类用于存储元素对（称作"键"和"值"），其中每个键映射到一个值。<br /><br /><br /><strong>54、描述一下JVM加载class文件的原理机制?</strong><br />JVM中类的装载是由ClassLoader和它的子类来实现的,Java ClassLoader 是一个重要的Java运行时系统组件。它负责在运行时查找和装入类文件的类。</p><p><strong>55、char型变量中能不能存贮一个中文汉字?为什么?</strong> <br />能够定义成为一个中文的，因为java中以unicode编码，一个char占16个字节，所以放一个中文是没问题的<br /><br /><br /><strong>56、多线程有几种实现方法,都是什么?同步有几种实现方法,都是什么? <br /></strong>多线程有两种实现方法，分别是继承Thread类与实现Runnable接口 <br />同步的实现方面有两种，分别是synchronized,wait与notify</p><p><br /><strong>58、线程的基本概念、线程的基本状态以及状态之间的关系</strong><br />线程指在程序执行过程中，能够执行程序代码的一个执行单位，每个程序至少都有一个线程，也就是程序本身。<br />Java中的线程有四种状态分别是：运行、就绪、挂起、结束。 <br /><br /><br /><strong>59、JSP的常用指令</strong><br />&lt;%@page language="java" contenType="text/html;charset=gb2312" session="true" buffer="64kb" autoFlush="true" isThreadSafe="true" info="text" errorPage="error.jsp" isErrorPage="true" isELIgnored="true" pageEncoding="gb2312" import="java.sql.*"%&gt;<br />isErrorPage(是否能使用Exception对象)，isELIgnored(是否忽略表达式)<br />&lt;%@include file="filename"%&gt;<br />&lt;%@taglib prefix="c"uri="http://......"%&gt;<br /><br /><br /><strong>60、什么情况下调用doGet()和doPost()？</strong><br />Jsp页面中的form标签里的method属性为get时调用doGet()，为post时调用doPost()。 <br /><br /><strong> <br />61、servlet的生命周期</strong><br />web容器加载servlet，生命周期开始。通过调用servlet的init()方法进行servlet的初始化。通过调用service()方法实现，根据请求的不同调用不同的do***()方法。结束服务，web容器调用servlet的destroy()方法。<br /><br /><br /><strong>62、如何现实servlet的单线程模式</strong><br />&lt;%@ page isThreadSafe="false"%&gt;<br /><br /><br /><strong>63、页面间对象传递的方法<br /></strong>request，session，application，cookie等<br /><br /><br /><strong>64、JSP和Servlet有哪些相同点和不同点，他们之间的联系是什么？</strong> <br />JSP是Servlet技术的扩展，本质上是Servlet的简易方式，更强调应用的外表表达。JSP编译后是"类servlet"。Servlet和JSP最主要的不同点在于，Servlet的应用逻辑是在Java文件中，并且完全从表示层中的HTML里分离开来。而JSP的情况是Java和HTML可以组合成一个扩展名为.jsp的文件。JSP侧重于视图，Servlet主要用于控制逻辑。<br /><br /><br /><strong>65、四种会话跟踪技术</strong><br />会话作用域ServletsJSP 页面描述<br />page否是代表与一个页面相关的对象和属性。一个页面由一个编译好的 Java servlet 类（可以带有任何的 include 指令，但是没有 include 动作）表示。这既包括 servlet 又包括被编译成 servlet 的 JSP 页面<br />request是是代表与 Web 客户机发出的一个请求相关的对象和属性。一个请求可能跨越多个页面，涉及多个 Web 组件（由于 forward 指令和 include 动作的关系）<br />session是是代表与用于某个 Web 客户机的一个用户体验相关的对象和属性。一个 Web 会话可以也经常会跨越多个客户机请求<br />application是是代表与整个 Web 应用程序相关的对象和属性。这实质上是跨越整个 Web 应用程序，包括多个页面、请求和会话的一个全局作用域<br /><br /><br /><strong>66、Request对象的主要方法：</strong><br />setAttribute(String name,Object)：设置名字为name的request的参数值<br />getAttribute(String name)：返回由name指定的属性值<br />getAttributeNames()：返回request对象所有属性的名字集合，结果是一个枚举的实例<br />getCookies()：返回客户端的所有Cookie对象，结果是一个Cookie数组<br />getCharacterEncoding()：返回请求中的字符编码方式<br />getContentLength()：返回请求的Body的长度<br />getHeader(String name)：获得HTTP协议定义的文件头信息<br />getHeaders(String name)：返回指定名字的request Header的所有值，结果是一个枚举的实例<br />getHeaderNames()：返回所以request Header的名字，结果是一个枚举的实例<br />getInputStream()：返回请求的输入流，用于获得请求中的数据<br />getMethod()：获得客户端向服务器端传送数据的方法<br />getParameter(String name)：获得客户端传送给服务器端的有name指定的参数值<br />getParameterNames()：获得客户端传送给服务器端的所有参数的名字，结果是一个枚举的实例<br />getParameterValues(String name)：获得有name指定的参数的所有值<br />getProtocol()：获取客户端向服务器端传送数据所依据的协议名称<br />getQueryString()：获得查询字符串<br />getRequestURI()：获取发出请求字符串的客户端地址<br />getRemoteAddr()：获取客户端的IP地址<br />getRemoteHost()：获取客户端的名字<br />getSession([Boolean create])：返回和请求相关Session<br />getServerName()：获取服务器的名字<br />getServletPath()：获取客户端所请求的脚本文件的路径<br />getServerPort()：获取服务器的端口号<br />removeAttribute(String name)：删除请求中的一个属性<br /><br /><br /><strong>67、J2EE是技术还是平台还是框架？</strong><br />    J2EE本身是一个标准，一个为企业分布式应用的开发提供的标准平台。<br />    J2EE也是一个框架，包括JDBC、JNDI、RMI、JMS、EJB、JTA等技术。<br /><br /><br /><strong>68、我们在web应用开发过程中经常遇到输出某种编码的字符，如iso8859-1等，如何输出一个某种编码的字符串？</strong><br />  Public String translate (String str) {<br />    String tempStr = "";<br />    try {<br />      tempStr = new String(str.getBytes("ISO-8859-1"), "GBK");<br />      tempStr = tempStr.trim();<br />    }<br />    catch (Exception e) {<br />      System.err.println(e.getMessage());<br />    }<br />    return tempStr;<br />  }<br /><br /><br /><strong>69、简述逻辑操作(&amp;,|,^)与条件操作(&amp;&amp;,||)的区别。<br /></strong>区别主要答两点：a.条件操作只能操作布尔型的,而逻辑操作不仅可以操作布尔型,而且可以操作数值型<br />b.逻辑操作不会产生短路<br /><br /><br /><strong>70、XML文档定义有几种形式？它们之间有何本质区别？解析XML文档有哪几种方式？ <br /></strong>a: 两种形式 dtd  schema，b: 本质区别:schema本身是xml的，可以被XML解析器解析(这也是从DTD上发展schema的根本目的)，c:有DOM,SAX,STAX等 <br />    DOM:处理大型文件时其性能下降的非常厉害。这个问题是由DOM的树结构所造成的，这种结构占用的内存较多，而且DOM必须在解析文件之前把整个文档装入内存,适合对XML的随机访问<br />SAX:不现于DOM,SAX是事件驱动型的XML解析方式。它顺序读取XML文件，不需要一次全部装载整个文件。当遇到像文件开头，文档结束，或者标签开头与标签结束时，它会触发一个事件，用户通过在其回调事件中写入处理代码来处理XML文件，适合对XML的顺序访问 <br />    STAX:Streaming API for XML (StAX)<br /><br /><br /><strong>71、简述synchronized和java.util.concurrent.locks.Lock的异同 ？<br /></strong>主要相同点：Lock能完成synchronized所实现的所有功能<br />主要不同点：Lock有比synchronized更精确的线程语义和更好的性能。synchronized会自动释放锁，而Lock一定要求程序员手工释放，并且必须在finally从句中释放。<br /><br /><br /><strong>72、EJB的角色和三个对象<br /></strong>一个完整的基于EJB的分布式计算结构由六个角色组成，这六个角色可以由不同的开发商提供，每个角色所作的工作必须遵循Sun公司提供的EJB规范，以保证彼此之间的兼容性。这六个角色分别是EJB组件开发者（Enterprise Bean Provider） 、应用组合者（Application Assembler）、部署者（Deployer）、EJB 服务器提供者（EJB Server Provider）、EJB 容器提供者（EJB Container Provider）、系统管理员（System Administrator）<br />三个对象是Remote（Local）接口、Home（LocalHome）接口，Bean类<br /><br /><br /><strong>73、EJB容器提供的服务</strong><br />主要提供声明周期管理、代码产生、持续性管理、安全、事务管理、锁和并发行管理等服务。<br /><br /><br /><strong>74、EJB规范规定EJB中禁止的操作有哪些？</strong> <br />    1.不能操作线程和线程API(线程API指非线程对象的方法如notify,wait等)，2.不能操作awt，3.不能实现服务器功能，4.不能对静态属生存取，5.不能使用IO操作直接存取文件系统，6.不能加载本地库.，7.不能将this作为变量和返回，8.不能循环调用。<br /><br /><br /><strong>75、remote接口和home接口主要作用</strong><br />remote接口定义了业务方法，用于EJB客户端调用业务方法。<br />home接口是EJB工厂用于创建和移除查找EJB实例<br /><br /><br /><strong>76、bean 实例的生命周期</strong><br />对于Stateless Session Bean、Entity Bean、Message Driven Bean一般存在缓冲池管理，而对于Entity Bean和Statefull Session Bean存在Cache管理，通常包含创建实例，设置上下文、创建EJB Object（create）、业务方法调用、remove等过程，对于存在缓冲池管理的Bean，在create之后实例并不从内存清除，而是采用缓冲池调度机制不断重用实例，而对于存在Cache管理的Bean则通过激活和去激活机制保持Bean的状态并限制内存中实例数量。<br />77、EJB的激活机制<br />以Stateful Session Bean 为例：其Cache大小决定了内存中可以同时存在的Bean实例的数量，根据MRU或NRU算法，实例在激活和去激活状态之间迁移，激活机制是当客户端调用某个EJB实例业务方法时，如果对应EJB Object发现自己没有绑定对应的Bean实例则从其去激活Bean存储中（通过序列化机制存储实例）回复（激活）此实例。状态变迁前会调用对应的ejbActive和ejbPassivate方法。<br /><br /><br /><strong>78、EJB的几种类型<br /></strong>会话（Session）Bean ，实体（Entity）Bean 消息驱动的（Message Driven）Bean<br />会话Bean又可分为有状态（Stateful）和无状态（Stateless）两种<br />实体Bean可分为Bean管理的持续性（BMP）和容器管理的持续性（CMP）两种<br /><br /><br /><strong>79、客服端调用EJB对象的几个基本步骤<br /></strong>设置JNDI服务工厂以及JNDI服务地址系统属性，查找Home接口，从Home接口调用Create方法创建Remote接口，通过Remote接口调用其业务方法。<br /><br /><br /><strong>80、如何给weblogic指定大小的内存? <br /></strong>在启动Weblogic的脚本中（位于所在Domian对应服务器目录下的startServerName），增加set MEM_ARGS=-Xms32m -Xmx200m，可以调整最小内存为32M，最大200M<br /> <br /><br /><strong>81、如何设定的weblogic的热启动模式(开发模式)与产品发布模式?</strong><br />可以在管理控制台中修改对应服务器的启动模式为开发或产品模式之一。或者修改服务的启动文件或者commenv文件，增加set PRODUCTION_MODE=true。<br /><br /><br /><strong>82、如何启动时不需输入用户名与密码?</strong><br />修改服务启动文件，增加 WLS_USER和WLS_PW项。也可以在boot.properties文件中增加加密过的用户名和密码.<br /><br /><br /><strong>83、在weblogic管理制台中对一个应用域(或者说是一个网站,Domain)进行jms及ejb或连接池等相关信息进行配置后,实际保存在什么文件中?</strong><br />保存在此Domain的config.xml文件中，它是服务器的核心配置文件。<br /><br /><br /><strong>84、说说weblogic中一个Domain的缺省目录结构?比如要将一个简单的helloWorld.jsp放入何目录下,然的在浏览器上就可打入http://主机:端口号//helloword.jsp就可以看到运行结果了? 又比如这其中用到了一个自己写的javaBean该如何办?<br /></strong>Domain目录服务器目录applications，将应用目录放在此目录下将可以作为应用访问，如果是Web应用，应用目录需要满足Web应用目录要求，jsp文件可以直接放在应用目录中，Javabean需要放在应用目录的WEB-INF目录的classes目录中，设置服务器的缺省应用将可以实现在浏览器上无需输入应用名。<br /><br /><br /><strong>85、在weblogic中发布ejb需涉及到哪些配置文件</strong><br />不同类型的EJB涉及的配置文件不同，都涉及到的配置文件包括ejb-jar.xml,weblogic-ejb-jar.xmlCMP实体Bean一般还需要weblogic-cmp-rdbms-jar.xml <br /><br /><br /><strong>86、如何在weblogic中进行ssl配置与客户端的认证配置或说说j2ee(标准)进行ssl的配置</strong><br />缺省安装中使用DemoIdentity.jks和DemoTrust.jks  KeyStore实现SSL，需要配置服务器使用Enable SSL，配置其端口，在产品模式下需要从CA获取私有密钥和数字证书，创建identity和trust keystore，装载获得的密钥和数字证书。可以配置此SSL连接是单向还是双向的。<br /><br /><br /><strong>87、如何查看在weblogic中已经发布的EJB?</strong><br />可以使用管理控制台，在它的Deployment中可以查看所有已发布的EJB<br /><br /><br /><strong>88、CORBA是什么?用途是什么?</strong> <br />CORBA 标准是公共对象请求代理结构(Common Object Request Broker Architecture)，由对象管理组织 (Object Management Group，缩写为 OMG)标准化。它的组成是接口定义语言(IDL), 语言绑定(binding:也译为联编)和允许应用程序间互操作的协议。 其目的为：用不同的程序设计语言书写在不同的进程中运行，为不同的操作系统开发。<br /><br /><br /><strong>89、说说你所熟悉或听说过的j2ee中的几种常用模式?及对设计模式的一些看法<br /></strong>  Session Facade Pattern：使用SessionBean访问EntityBean<br />Message Facade Pattern：实现异步调用<br />EJB Command Pattern：使用Command JavaBeans取代SessionBean，实现轻量级访问<br />Data Transfer Object Factory：通过DTO Factory简化EntityBean数据提供特性<br />Generic Attribute Access：通过AttibuteAccess接口简化EntityBean数据提供特性<br />Business Interface：通过远程（本地）接口和Bean类实现相同接口规范业务逻辑一致性<br />ＥＪＢ架构的设计好坏将直接影响系统的性能、可扩展性、可维护性、组件可重用性及开发效率。项目越复杂，项目队伍越庞大则越能体现良好设计的重要性。<br /><br /><br /><strong>90、说说在weblogic中开发消息Bean时的persistent与non-persisten的差别</strong><br />persistent方式的MDB可以保证消息传递的可靠性,也就是如果EJB容器出现问题而JMS服务器依然会将消息在此MDB可用的时候发送过来，而non－persistent方式的消息将被丢弃。<br /><br /><br /><strong>91、Servlet执行时一般实现哪几个方法？</strong><br />public void init(ServletConfig config)<br />public ServletConfig getServletConfig()<br />public String getServletInfo()<br />public void service(ServletRequest request,ServletResponse response)<br />public void destroy()<br /><br /><br /><strong>92、j2ee常用的设计模式？说明工厂模式</strong>。<br />    Java中的23种设计模式：<br />Factory（工厂模式），      Builder（建造模式），       Factory Method（工厂方法模式），<br />Prototype（原始模型模式），Singleton（单例模式），    Facade（门面模式），<br />Adapter（适配器模式），    Bridge（桥梁模式），        Composite（合成模式），<br />Decorator（装饰模式），    Flyweight（享元模式），     Proxy（代理模式），<br />Command（命令模式），      Interpreter（解释器模式）， Visitor（访问者模式），<br />Iterator（迭代子模式），   Mediator（调停者模式），    Memento（备忘录模式），<br />Observer（观察者模式），   State（状态模式），         Strategy（策略模式），<br />Template Method（模板方法模式）， Chain Of Responsibleity（责任链模式）<br />工厂模式：工厂模式是一种经常被使用到的模式，根据工厂模式实现的类可以根据提供的数据生成一组类中某一个类的实例，通常这一组类有一个公共的抽象父类并且实现了相同的方法，但是这些方法针对不同的数据进行了不同的操作。首先需要定义一个基类，该类的子类通过不同的方法实现了基类中的方法。然后需要定义一个工厂类，工厂类可以根据条件生成不同的子类实例。当得到子类的实例后，开发人员可以调用基类中的方法而不必考虑到底返回的是哪一个子类的实例。<br /><br /><br /><strong>93、EJB需直接实现它的业务接口或Home接口吗，请简述理由。</strong><br />远程接口和Home接口不需要直接实现，他们的实现代码是由服务器产生的，程序运行中对应实现类会作为对应接口类型的实例被使用。<br /><br /><br /><strong>94、排序都有哪几种方法？请列举。用JAVA实现一个快速排序。</strong><br />    排序的方法有：插入排序（直接插入排序、希尔排序），交换排序（冒泡排序、快速排序），选择排序（直接选择排序、堆排序），归并排序，分配排序（箱排序、基数排序）<br />快速排序的伪代码。<br />/ /使用快速排序方法对a[ 0 :n- 1 ]排序<br />从a[ 0 :n- 1 ]中选择一个元素作为m i d d l e，该元素为支点<br />把余下的元素分割为两段left 和r i g h t，使得l e f t中的元素都小于等于支点，而right 中的元素都大于等于支点<br />递归地使用快速排序方法对left 进行排序<br />递归地使用快速排序方法对right 进行排序<br />所得结果为l e f t + m i d d l e + r i g h t<br /><br /><br /><strong>95、请对以下在J2EE中常用的名词进行解释(或简单描述)</strong><br />web容器：给处于其中的应用程序组件（JSP，SERVLET）提供一个环境，使JSP,SERVLET直接更容器中的环境变量接口交互，不必关注其它系统问题。主要有WEB服务器来实现。例如：TOMCAT,WEBLOGIC,WEBSPHERE等。该容器提供的接口严格遵守J2EE规范中的WEB APPLICATION 标准。我们把遵守以上标准的WEB服务器就叫做J2EE中的WEB容器。<br />EJB容器：Enterprise java bean 容器。更具有行业领域特色。他提供给运行在其中的组件EJB各种管理功能。只要满足J2EE规范的EJB放入该容器，马上就会被容器进行高效率的管理。并且可以通过现成的接口来获得系统级别的服务。例如邮件服务、事务管理。<br />JNDI：（Java Naming &amp; Directory Interface）JAVA命名目录服务。主要提供的功能是：提供一个目录系统，让其它各地的应用程序在其上面留下自己的索引，从而满足快速查找和定位分布式应用程序的功能。<br />JMS：（Java Message Service）JAVA消息服务。主要实现各个应用程序之间的通讯。包括点对点和广播。<br />JTA：（Java Transaction API）JAVA事务服务。提供各种分布式事务服务。应用程序只需调用其提供的接口即可。<br />JAF：（Java Action FrameWork）JAVA安全认证框架。提供一些安全控制方面的框架。让开发者通过各种部署和自定义实现自己的个性安全控制策略。<br />RMI/IIOP:（Remote Method Invocation /internet对象请求中介协议）他们主要用于通过远程调用服务。例如，远程有一台计算机上运行一个程序，它提供股票分析服务，我们可以在本地计算机上实现对其直接调用。当然这是要通过一定的规范才能在异构的系统之间进行通信。RMI是JAVA特有的。<br /><br /><br /><strong>96、JAVA语言如何进行异常处理，关键字：throws,throw,try,catch,finally分别代表什么意义？在try块中可以抛出异常吗？</strong><br />Java通过面向对象的方法进行异常处理，把各种不同的异常进行分类，并提供了良好的接口。在Java中，每个异常都是一个对象，它是Throwable类或其它子类的实例。当一个方法出现异常后便抛出一个异常对象，该对象中包含有异常信息，调用这个对象的方法可以捕获到这个异常并进行处理。Java的异常处理是通过5个关键词来实现的：try、catch、throw、throws和finally。一般情况下是用try来执行一段程序，如果出现异常，系统会抛出（throws）一个异常，这时候你可以通过它的类型来捕捉（catch）它，或最后（finally）由缺省处理器来处理。<br />用try来指定一块预防所有"异常"的程序。紧跟在try程序后面，应包含一个catch子句来指定你想要捕捉的"异常"的类型。<br />throw语句用来明确地抛出一个"异常"。<br />throws用来标明一个成员函数可能抛出的各种"异常"。<br />Finally为确保一段代码不管发生什么"异常"都被执行一段代码。<br />可以在一个成员函数调用的外面写一个try语句，在这个成员函数内部写另一个try语句保护其他代码。每当遇到一个try语句，"异常"的框架就放到堆栈上面，直到所有的try语句都完成。如果下一级的try语句没有对某种"异常"进行处理，堆栈就会展开，直到遇到有处理这种"异常"的try语句。<br /><br /><br /><strong>97、一个".java"源文件中是否可以包括多个类（不是内部类）？有什么限制？<br /></strong>可以。必须只有一个类名与文件名相同。<br /><br /><br /><strong>98、MVC的各个部分都有那些技术来实现?如何实现?</strong> <br />MVC是Model－View－Controller的简写。"Model" 代表的是应用的业务逻辑（通过JavaBean，EJB组件实现）， "View" 是应用的表示面（由JSP页面产生），"Controller" 是提供应用的处理过程控制（一般是一个Servlet），通过这种设计模型把应用逻辑，处理过程和显示逻辑分成不同的组件实现。这些组件可以进行交互和重用。<br /><br /><br /><strong>99、java中有几种方法可以实现一个线程？用什么关键字修饰同步方法? stop()和suspend()方法为何不推荐使用？<br /></strong>有两种实现方法，分别是继承Thread类与实现Runnable接口<br />用synchronized关键字修饰同步方法<br />反对使用stop()，是因为它不安全。它会解除由线程获取的所有锁定，而且如果对象处于一种不连贯状态，那么其他线程能在那种状态下检查和修改它们。结果很难检查出真正的问题所在。suspend()方法容易发生死锁。调用suspend()的时候，目标线程会停下来，但却仍然持有在这之前获得的锁定。此时，其他任何线程都不能访问锁定的资源，除非被"挂起"的线程恢复运行。对任何线程来说，如果它们想恢复目标线程，同时又试图使用任何一个锁定的资源，就会造成死锁。所以不应该使用suspend()，而应在自己的Thread类中置入一个标志，指出线程应该活动还是挂起。若标志指出线程应该挂起，便用wait()命其进入等待状态。若标志指出线程应当恢复，则用一个notify()重新启动线程。<br /><br /><br /><strong>100、java中有几种类型的流？JDK为每种类型的流提供了一些抽象类以供继承，请说出他们分别是哪些类？</strong><br />字节流，字符流。字节流继承于InputStream  OutputStream，字符流继承于InputStreamReader  OutputStreamWriter。在java.io包中还有许多其他的流，主要是为了提高性能和使用方便。</p><p><br /><strong> 101、java中会存在内存泄漏吗，请简单描述。</strong><br />会。如：int i,i2;  return (i-i2);   file://when i为足够大的正数,i2为足够大的负数。结果会造成溢位，导致错误。<br /><br /><br /><strong>102、java中实现多态的机制是什么？</strong><br />方法的重写Overriding和重载Overloading是Java多态性的不同表现。重写Overriding是父类与子类之间多态性的一种表现，重载Overloading是一个类中多态性的一种表现。<br /><br /><br /><strong>103、垃圾回收器的基本原理是什么？垃圾回收器可以马上回收内存吗？有什么办法主动通知虚拟机进行垃圾回收？</strong><br />对于GC来说，当程序员创建对象时，GC就开始监控这个对象的地址、大小以及使用情况。通常，GC采用有向图的方式记录和管理堆(heap)中的所有对象。通过这种方式确定哪些对象是"可达的"，哪些对象是"不可达的"。当GC确定一些对象为"不可达"时，GC就有责任回收这些内存空间。可以。程序员可以手动执行System.gc()，通知GC运行，但是Java语言规范并不保证GC一定会执行。<br /><br /><br /><strong>104、静态变量和实例变量的区别？</strong><br />static i = 10; file://常量<br />class A a;  a.i =10;//可变<br /><br /><br /><strong>105、什么是java序列化，如何实现java序列化？</strong><br />序列化就是一种用来处理对象流的机制，所谓对象流也就是将对象的内容进行流化。可以对流化后的对象进行读写操作，也可将流化后的对象传输于网络之间。序列化是为了解决在对对象流进行读写操作时所引发的问题。<br />序列化的实现：将需要被序列化的类实现Serializable接口，该接口没有需要实现的方法，implements Serializable只是为了标注该对象是可被序列化的，然后使用一个输出流(如：FileOutputStream)来构造一个ObjectOutputStream(对象流)对象，接着，使用ObjectOutputStream对象的writeObject(Object obj)方法就可以将参数为obj的对象写出(即保存其状态)，要恢复的话则用输入流。<br /><br /><br /><strong>106、是否可以从一个static方法内部发出对非static方法的调用？</strong><br />不可以,如果其中包含对象的method()；不能保证对象初始化.<br /><br /><br /><strong>107、写clone()方法时，通常都有一行代码，是什么？</strong><br />Clone 有缺省行为，super.clone();他负责产生正确大小的空间，并逐位复制。<br /><br /><br /><strong>108、在JAVA中，如何跳出当前的多重嵌套循环？</strong><br />用break; return 方法。<br /><br /><br /><strong>109、List、Map、Set三个接口，存取元素时，各有什么特点？</strong><br />List 以特定次序来持有元素，可有重复元素。Set 无法拥有重复元素,内部排序。Map 保存key-value值，value可多值。<br /><br /><br /><strong>110、J2EE是什么？</strong><br />J2EE是Sun公司提出的多层(multi-diered),分布式(distributed),基于组件(component-base)的企业级应用模型(enterpriese application model).在这样的一个应用系统中，可按照功能划分为不同的组件，这些组件又可在不同计算机上，并且处于相应的层次(tier)中。所属层次包括客户层(clietn tier)组件,web层和组件,Business层和组件,企业信息系统(EIS)层。<br /><br /><br /><strong>111、UML方面</strong> <br />标准建模语言UML。用例图,静态图(包括类图、对象图和包图),行为图,交互图(顺序图,合作图),实现图。<br /><br /><br /><strong>112、说出一些常用的类，包，接口，请各举5个</strong><br /><strong>常用的类</strong>：BufferedReader  BufferedWriter  FileReader  FileWirter  String  Integer<br /><strong>常用的包</strong>：java.lang  java.awt  java.io  java.util  java.sql<br /><strong>常用的接口</strong>：Remote  List  Map  Document  NodeList <br /><br /><br /><strong>113、开发中都用到了那些设计模式?用在什么场合?</strong> <br />每个模式都描述了一个在我们的环境中不断出现的问题，然后描述了该问题的解决方案的核心。通过这种方式，你可以无数次地使用那些已有的解决方案，无需在重复相同的工作。主要用到了MVC的设计模式。用来开发JSP/Servlet或者J2EE的相关应用。简单工厂模式等。<br /><br /><br /><strong>114、jsp有哪些动作?作用分别是什么?</strong> <br />JSP共有以下6种基本动作 jsp:include：在页面被请求的时候引入一个文件。 jsp:useBean：寻找或者实例化一个JavaBean。 jsp:setProperty：设置JavaBean的属性。 jsp:getProperty：输出某个JavaBean的属性。 jsp:forward：把请求转到一个新的页面。 jsp:plugin：根据浏览器类型为Java插件生成OBJECT或EMBED标记。<br /><br /><br /><strong>115、Anonymous Inner Class (匿名内部类) 是否可以extends(继承)其它类，是否可以implements(实现)interface(接口)?</strong> <br />可以继承其他类或完成其他接口，在swing编程中常用此方式。<br /><br /><br /><strong>116、应用服务器与WEB SERVER的区别？</strong><br />应用服务器：Weblogic、Tomcat、Jboss<br />WEB SERVER：IIS、 Apache<br /><br /><br /><strong>117、BS与CS的联系与区别。<br /></strong>C/S是Client/Server的缩写。服务器通常采用高性能的PC、工作站或小型机，并采用大型数据库系统，如Oracle、Sybase、Informix或 SQL Server。客户端需要安装专用的客户端软件。<br />B/Ｓ是Brower/Server的缩写，客户机上只要安装一个浏览器（Browser），如Netscape Navigator或Internet Explorer，服务器安装Oracle、Sybase、Informix或 SQL Server等数据库。在这种结构下，用户界面完全通过WWW浏览器实现，一部分事务逻辑在前端实现，但是主要事务逻辑在服务器端实现。浏览器通过Ｗeb Server 同数据库进行数据交互。<br />C/S 与 B/S 区别： <br />１．硬件环境不同: <br />　　C/S 一般建立在专用的网络上, 小范围里的网络环境, 局域网之间再通过专门服务器提供连接和数据交换服务.<br />　　B/S 建立在广域网之上的, 不必是专门的网络硬件环境,例与电话上网, 租用设备. 信息自己管理. 有比C/S更强的适应范围, 一般只要有操作系统和浏览器就行 <br />２．对安全要求不同 <br />　　C/S 一般面向相对固定的用户群, 对信息安全的控制能力很强. 一般高度机密的信息系统采用C/S 结构适宜. 可以通过B/S发布部分可公开信息.<br />　　B/S 建立在广域网之上, 对安全的控制能力相对弱, 可能面向不可知的用户。<br />３．对程序架构不同 <br />　　C/S 程序可以更加注重流程, 可以对权限多层次校验, 对系统运行速度可以较少考虑.<br />　　B/S 对安全以及访问速度的多重的考虑, 建立在需要更加优化的基础之上. 比C/S有更高的要求 B/S结构的程序架构是发展的趋势, 从MS的.Net系列的BizTalk 2000 Exchange 2000等, 全面支持网络的构件搭建的系统. SUN 和IBM推的JavaBean 构件技术等,使 B/S更加成熟. <br />４．软件重用不同 <br />　　C/S 程序可以不可避免的整体性考虑, 构件的重用性不如在B/S要求下的构件的重用性好.<br />　　B/S 对的多重结构,要求构件相对独立的功能. 能够相对较好的重用.就入买来的餐桌可以再利用,而不是做在墙上的石头桌子 <br />５．系统维护不同  <br />　　C/S 程序由于整体性, 必须整体考察, 处理出现的问题以及系统升级. 升级难. 可能是再做一个全新的系统<br />　　B/S 构件组成,方面构件个别的更换,实现系统的无缝升级. 系统维护开销减到最小.用户从网上自己下载安装就可以实现升级. <br />６．处理问题不同 <br />　　C/S 程序可以处理用户面固定, 并且在相同区域, 安全要求高需求, 与操作系统相关. 应该都是相同的系统<br />　　B/S 建立在广域网上, 面向不同的用户群, 分散地域, 这是C/S无法作到的. 与操作系统平台关系最小. <br />７．用户接口不同 <br />　　C/S 多是建立的Window平台上,表现方法有限,对程序员普遍要求较高<br />　　B/S 建立在浏览器上, 有更加丰富和生动的表现方式与用户交流. 并且大部分难度减低,减低开发成本. <br />８．信息流不同 <br />　　C/S 程序一般是典型的中央集权的机械式处理, 交互性相对低<br />　　B/S 信息流向可变化, B-B B-C B-G等信息、流向的变化, 更像交易中心。<br /><br /><br /><strong>118、LINUX下线程，GDI类的解释。<br /></strong>LINUX实现的就是基于核心轻量级进程的"一对一"线程模型，一个线程实体对应一个核心轻量级进程，而线程之间的管理在核外函数库中实现。 <br />GDI类为图像设备编程接口类库。<br /><br /><br /><strong>119、STRUTS的应用(如STRUTS架构)</strong> <br />Struts是采用Java Servlet/JavaServer Pages技术，开发Web应用程序的开放源码的framework。 采用Struts能开发出基于MVC(Model-View-Controller)设计模式的应用构架。 Struts有如下的主要功能： 一.包含一个controller servlet，能将用户的请求发送到相应的Action对象。 二.JSP自由tag库，并且在controller servlet中提供关联支持，帮助开发员创建交互式表单应用。 三.提供了一系列实用对象：XML处理、通过Java reflection APIs自动处理JavaBeans属性、国际化的提示和消息。<br /><br /><br /><strong>120、Jdo是什么?</strong> <br />JDO是Java对象持久化的新的规范，为java data object的简称,也是一个用于存取某种数据仓库中的对象的标准化API。JDO提供了透明的对象存储，因此对开发人员来说，存储数据对象完全不需要额外的代码（如JDBC API的使用）。这些繁琐的例行工作已经转移到JDO产品提供商身上，使开发人员解脱出来，从而集中时间和精力在业务逻辑上。另外，JDO很灵活，因为它可以在任何数据底层上运行。JDBC只是面向关系数据库（RDBMS）JDO更通用，提供到任何数据底层的存储功能，比如关系数据库、文件、XML以及对象数据库（ODBMS）等等，使得应用可移植性更强。</p></div>
<img src ="http://www.blogjava.net/nbtymm/aggbug/51698.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/nbtymm/" target="_blank">nbt</a> 2006-06-09 15:27 <a href="http://www.blogjava.net/nbtymm/archive/2006/06/09/51698.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java知识汇总(一)</title><link>http://www.blogjava.net/nbtymm/archive/2006/06/09/51696.html</link><dc:creator>nbt</dc:creator><author>nbt</author><pubDate>Fri, 09 Jun 2006 07:21:00 GMT</pubDate><guid>http://www.blogjava.net/nbtymm/archive/2006/06/09/51696.html</guid><wfw:comment>http://www.blogjava.net/nbtymm/comments/51696.html</wfw:comment><comments>http://www.blogjava.net/nbtymm/archive/2006/06/09/51696.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/nbtymm/comments/commentRss/51696.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/nbtymm/services/trackbacks/51696.html</trackback:ping><description><![CDATA[
		<table class="fixedTable blogpost" cellspacing="0" width="100%" border="0">
				<tbody>
						<tr>
								<td id="msgcns!48122F59260F24A8!129">
										<div>
												<strong>1.面向对象的特征有哪些方面</strong>   <br />1.抽象：<br />抽象就是忽略一个主题中与当前目标无关的那些方面，以便更充分地注意与当前目标有关的方面。抽象并不打算了解全部问题，而只是选择其中的一部分，暂时不用部分细节。抽象包括两个方面，一是过程抽象，二是数据抽象。<br />2.继承：<br />继承是一种联结类的层次模型，并且允许和鼓励类的重用，它提供了一种明确表述共性的方法。对象的一个新类可以从现有的类中派生，这个过程称为类继承。新类继承了原始类的特性，新类称为原始类的派生类（子类），而原始类称为新类的基类（父类）。派生类可以从它的基类那里继承方法和实例变量，并且类可以修改或增加新的方法使之更适合特殊的需要。<br />3.封装：<br />封装是把过程和数据包围起来，对数据的访问只能通过已定义的界面。面向对象计算始于这个基本概念，即现实世界可以被描绘成一系列完全自治、封装的对象，这些对象通过一个受保护的接口访问其他对象。<br />4. 多态性：<br />多态性是指允许不同类的对象对同一消息作出响应。多态性包括参数化多态性和包含多态性。多态性语言具有灵活、抽象、行为共享、代码共享的优势，很好的解决了应用程序函数同名问题。 
<p><br /><strong>2、String是最基本的数据类型吗?</strong><br />基本数据类型包括byte、int、char、long、float、double、boolean和short。<br />java.lang.String类是final类型的，因此不可以继承这个类、不能修改这个类。为了提高效率节省空间，我们应该用StringBuffer类</p><p><br /><strong>3、int 和 Integer 有什么区别</strong><br />Java 提供两种不同的类型：引用类型和原始类型（或内置类型）。Int是java的原始数据类型，Integer是java为int提供的封装类。Java为每个原始类型提供了封装类。<br />原始类型封装类<br />booleanBoolean<br />charCharacter<br />byteByte<br />shortShort<br />intInteger<br />longLong<br />floatFloat<br />doubleDouble<br />引用类型和原始类型的行为完全不同，并且它们具有不同的语义。引用类型和原始类型具有不同的特征和用法，它们包括：大小和速度问题，这种类型以哪种类型的数据结构存储，当引用类型和原始类型用作某个类的实例数据时所指定的缺省值。对象引用实例变量的缺省值为 null，而原始类型实例变量的缺省值与它们的类型有关。</p><p><br /><strong>4、String 和StringBuffer的区别</strong><br />JAVA平台提供了两个类：String和StringBuffer，它们可以储存和操作字符串，即包含多个字符的字符数据。这个String类提供了数值不可改变的字符串。而这个StringBuffer类提供的字符串进行修改。当你知道字符数据要改变的时候你就可以使用StringBuffer。典型地，你可以使用StringBuffers来动态构造字符数据。</p><p><br /><strong>5、运行时异常与一般异常有何异同？</strong><br />异常表示程序运行过程中可能出现的非正常状态，运行时异常表示虚拟机的通常操作中可能遇到的异常，是一种常见运行错误。java编译器要求方法必须声明抛出可能发生的非运行时异常，但是并不要求必须声明抛出未被捕获的运行时异常。</p><p><br /><strong>6、说出Servlet的生命周期，并说出Servlet和CGI的区别。</strong><br />Servlet被服务器实例化后，容器运行其init方法，请求到达时运行其service方法，service方法自动派遣运行与请求对应的doXXX方法（doGet，doPost）等，当服务器决定将实例销毁的时候调用其destroy方法。<br />与cgi的区别在于servlet处于服务器进程中，它通过多线程方式运行其service方法，一个实例可以服务于多个请求，并且其实例一般不会销毁，而CGI对每个请求都产生新的进程，服务完成后就销毁，所以效率上低于servlet。</p><p><br /><strong>7、说出ArrayList,Vector, LinkedList的存储性能和特性</strong><br />ArrayList和Vector都是使用数组方式存储数据，此数组元素数大于实际存储的数据以便增加和插入元素，它们都允许直接按序号索引元素，但是插入元素要涉及数组元素移动等内存操作，所以索引数据快而插入数据慢，Vector由于使用了synchronized方法（线程安全），通常性能上较ArrayList差，而LinkedList使用双向链表实现存储，按序号索引数据需要进行前向或后向遍历，但是插入数据时只需要记录本项的前后项即可，所以插入速度较快。</p><p><br /><strong>8、EJB是基于哪些技术实现的？并说出SessionBean和EntityBean的区别，StatefulBean和StatelessBean的区别。</strong><br />    EJB包括Session Bean、Entity Bean、Message Driven Bean，基于JNDI、RMI、JAT等技术实现。<br />SessionBean在J2EE应用程序中被用来完成一些服务器端的业务操作，例如访问数据库、调用其他EJB组件。EntityBean被用来代表应用系统中用到的数据。<br />对于客户机，SessionBean是一种非持久性对象，它实现某些在服务器上运行的业务逻辑。<br />对于客户机，EntityBean是一种持久性对象，它代表一个存储在持久性存储器中的实体的对象视图，或是一个由现有企业应用程序实现的实体。<br />Session Bean 还可以再细分为 Stateful Session Bean 与 Stateless Session Bean ，这两种的 Session Bean都可以将系统逻辑放在 method之中执行，不同的是 Stateful Session Bean 可以记录呼叫者的状态，因此通常来说，一个使用者会有一个相对应的 Stateful Session Bean 的实体。Stateless Session Bean 虽然也是逻辑组件，但是他却不负责记录使用者状态，也就是说当使用者呼叫 Stateless Session Bean 的时候，EJB Container 并不会找寻特定的 Stateless Session Bean 的实体来执行这个 method。换言之，很可能数个使用者在执行某个 Stateless Session Bean 的 methods 时，会是同一个 Bean 的 Instance 在执行。从内存方面来看， Stateful Session Bean 与 Stateless Session Bean 比较， Stateful Session Bean 会消<strong>耗 J2EE Server 较多的内存，然而 Stateful Session Bean 的优势却在于他可以维持使用者的状态。</strong></p><p><br /><strong>9、Collection 和 Collections的区别。</strong> <br />　　Collection是集合类的上级接口，继承与他的接口主要有Set 和List.<br />Collections是针对集合类的一个帮助类，他提供一系列静态方法实现对各种集合的搜索、排序、线程安全化等操作。</p><p><br /><strong>10、&amp;和&amp;&amp;的区别。</strong> <br />    &amp;是位运算符，表示按位与运算，&amp;&amp;是逻辑运算符，表示逻辑与（and）。</p><p><br /><strong>11、HashMap和Hashtable的区别。</strong> <br />    HashMap是Hashtable的轻量级实现（非线程安全的实现），他们都完成了Map接口，主要区别在于HashMap允许空（null）键值（key）,由于非线程安全，效率上可能高于Hashtable。<br />HashMap允许将null作为一个entry的key或者value，而Hashtable不允许。<br />HashMap把Hashtable的contains方法去掉了，改成containsvalue和containsKey。因为contains方法容易让人引起误解。 <br />Hashtable继承自Dictionary类，而HashMap是Java1.2引进的Map interface的一个实现。<br />最大的不同是，Hashtable的方法是Synchronize的，而HashMap不是，在多个线程访问Hashtable时，不需要自己为它的方法实现同步，而HashMap 就必须为之提供外同步。 <br />Hashtable和HashMap采用的hash/rehash算法都大概一样，所以性能不会有很大的差异。</p><p><br /><strong>12、final, finally, finalize的区别。 <br /></strong>　　final 用于声明属性，方法和类，分别表示属性不可变，方法不可覆盖，类不可继承。<br />finally是异常处理语句结构的一部分，表示总是执行。<br />finalize是Object类的一个方法，在垃圾收集器执行的时候会调用被回收对象的此方法，可以覆盖此方法提供垃圾收集时的其他资源回收，例如关闭文件等。</p><p><br /><strong>13、sleep() 和 wait() 有什么区别?</strong> <br />    sleep是线程类（Thread）的方法，导致此线程暂停执行指定时间，给执行机会给其他线程，但是监控状态依然保持，到时后会自动恢复。调用sleep不会释放对象锁。<br />wait是Object类的方法，对此对象调用wait方法导致本线程放弃对象锁，进入等待此对象的等待锁定池，只有针对此对象发出notify方法（或notifyAll）后本线程才进入对象锁定池准备获得对象锁进入运行状态。</p><p><br /><strong>14、Overload和Override的区别。Overloaded的方法是否可以改变返回值的类型?</strong><br />方法的重写Overriding和重载Overloading是Java多态性的不同表现。重写Overriding是父类与子类之间多态性的一种表现，重载Overloading是一个类中多态性的一种表现。如果在子类中定义某方法与其父类有相同的名称和参数，我们说该方法被重写 (Overriding)。子类的对象使用这个方法时，将调用子类中的定义，对它而言，父类中的定义如同被"屏蔽"了。如果在一个类中定义了多个同名的方法，它们或有不同的参数个数或有不同的参数类型，则称为方法的重载(Overloading)。Overloaded的方法是可以改变返回值的类型。</p><p><br /><strong>15、error和exception有什么区别?</strong><br />error 表示恢复不是不可能但很困难的情况下的一种严重问题。比如说内存溢出。不可能指望程序能处理这样的情况。<br />    exception 表示一种设计或实现问题。也就是说，它表示如果程序运行正常，从不会发生的情况。</p><p><br /><strong>16、同步和异步有何异同，在什么情况下分别使用他们？举例说明。</strong><br />如果数据将在线程间共享。例如正在写的数据以后可能被另一个线程读到，或者正在读的数据可能已经被另一个线程写过了，那么这些数据就是共享数据，必须进行同步存取。<br />当应用程序在对象上调用了一个需要花费很长时间来执行的方法，并且不希望让程序等待方法的返回时，就应该使用异步编程，在很多情况下采用异步途径往往更有效率。</p><p><br /><strong>17、abstract class和interface有什么区别?</strong><br />声明方法的存在而不去实现它的类被叫做抽象类（abstract class），它用于要创建一个体现某些基本行为的类，并为该类声明方法，但不能在该类中实现该类的情况。不能创建abstract 类的实例。然而可以创建一个变量，其类型是一个抽象类，并让它指向具体子类的一个实例。不能有抽象构造函数或抽象静态方法。Abstract 类的子类为它们父类中的所有抽象方法提供实现，否则它们也是抽象类为。取而代之，在子类中实现该方法。知道其行为的其它类可以在类中实现这些方法。<br />接口（interface）是抽象类的变体。在接口中，所有方法都是抽象的。多继承性可通过实现这样的接口而获得。接口中的所有方法都是抽象的，没有一个有程序体。接口只可以定义static final成员变量。接口的实现与子类相似，除了该实现类不能从接口定义中继承行为。当类实现特殊接口时，它定义（即将程序体给予）所有这种接口的方法。然后，它可以在实现了该接口的类的任何对象上调用接口的方法。由于有抽象类，它允许使用接口名作为引用变量的类型。通常的动态联编将生效。引用可以转换到接口类型或从接口类型转换，instanceof 运算符可以用来决定某对象的类是否实现了接口。</p><p><br /><strong>18、heap和stack有什么区别。</strong><br />栈是一种线形集合，其添加和删除元素的操作应在同一段完成。栈按照后进先出的方式进行处理。<br />堆是栈的一个组成元素</p><p><br /><strong>19、forward 和redirect的区别</strong><br />forward是服务器请求资源，服务器直接访问目标地址的URL，把那个URL的响应内容读取过来，然后把这些内容再发给浏览器，浏览器根本不知道服务器发送的内容是从哪儿来的，所以它的地址栏中还是原来的地址。<br />    redirect就是服务端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址，一般来说浏览器会用刚才请求的所有参数重新请求，所以session,request参数都可以获取。 </p><p><br /><strong>20、EJB与JAVA BEAN的区别？</strong><br />Java Bean 是可复用的组件，对Java Bean并没有严格的规范，理论上讲，任何一个Java类都可以是一个Bean。但通常情况下，由于Java Bean是被容器所创建（如Tomcat）的，所以Java Bean应具有一个无参的构造器，另外，通常Java Bean还要实现Serializable接口用于实现Bean的持久性。Java Bean实际上相当于微软COM模型中的本地进程内COM组件，它是不能被跨进程访问的。Enterprise Java Bean 相当于DCOM，即分布式组件。它是基于Java的远程方法调用（RMI）技术的，所以EJB可以被远程访问（跨进程、跨计算机）。但EJB必须被布署在诸如Webspere、WebLogic这样的容器中，EJB客户从不直接访问真正的EJB组件，而是通过其容器访问。EJB容器是EJB组件的代理，EJB组件由容器所创建和管理。客户通过容器来访问真正的EJB组件。<br /><br /><strong>21、Static Nested Class 和 Inner Class的不同。</strong><br />    Static Nested Class是被声明为静态（static）的内部类，它可以不依赖于外部类实例被实例化。而通常的内部类需要在外部类实例化后才能实例化。<br /><br /><strong>22、JSP中动态INCLUDE与静态INCLUDE的区别？</strong><br />动态INCLUDE用jsp:include动作实现 &lt;jsp:include page="included.jsp" flush="true" /&gt;它总是会检查所含文件中的变化，适合用于包含动态页面，并且可以带参数。<br />静态INCLUDE用include伪码实现,定不会检查所含文件的变化，适用于包含静态页面&lt;%@ include file="included.htm" %&gt; <br /><br /><br /><strong>23、什么时候用assert。</strong> <br />    assertion(断言)在软件开发中是一种常用的调试方式，很多开发语言中都支持这种机制。在实现中，assertion就是在程序中的一条语句，它对一个boolean表达式进行检查，一个正确程序必须保证这个boolean表达式的值为true；如果该值为false，说明程序已经处于不正确的状态下，系统将给出警告或退出。一般来说，assertion用于保证程序最基本、关键的正确性。assertion检查通常在开发和测试时开启。为了提高性能，在软件发布后，assertion检查通常是关闭的。<br /><br /><br /><strong>24、GC是什么? 为什么要有GC?</strong> <br />　　GC是垃圾收集的意思（Gabage Collection）,内存处理是编程人员容易出现问题的地方，忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃，Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的，Java语言没有提供释放已分配内存的显示操作方法。<br /><br /> <br /><strong>25、short s1 = 1; s1 = s1 + 1;有什么错? short s1 = 1; s1 += 1;有什么错?</strong> <br />    short s1 = 1; s1 = s1 + 1; （s1+1运算结果是int型，需要强制转换类型）<br />short s1 = 1; s1 += 1;（可以正确编译）<br /><br /><br /><strong>26、Math.round(11.5)等於多少? Math.round(-11.5)等於多少?</strong> <br />    Math.round(11.5)==12<br />Math.round(-11.5)==-11<br />round方法返回与参数最接近的长整数，参数加1/2后求其floor.<br /><br /><br /><strong>27、String s = new String("xyz");创建了几个String Object? <br /></strong>    两个<br /><br /><br /><strong>28、设计4个线程，其中两个线程每次对j增加1，另外两个线程对j每次减少1。写出程序。<br /></strong>以下程序使用内部类实现线程，对j增减的时候没有考虑顺序问题。<br />public class ThreadTest1{<br />  private int j;<br />  public static void main(String args[]){<br />ThreadTest1 tt=new ThreadTest1();<br />Inc inc=tt.new Inc();<br />Dec dec=tt.new Dec();<br />for(int i=0;i&lt;2;i++){<br />Thread t=new Thread(inc);<br />t.start();<br />t=new Thread(dec);<br />t.start();<br />}<br />}<br />  private synchronized void inc(){<br />j++;<br />System.out.println(Thread.currentThread().getName()+"-inc:"+j);<br />  }<br />  private synchronized void dec(){<br />j--;<br />System.out.println(Thread.currentThread().getName()+"-dec:"+j);<br />  }<br />  class Inc implements Runnable{<br />public void run(){<br />for(int i=0;i&lt;100;i++){<br />inc();<br />}<br />}<br />  }<br />  class Dec implements Runnable{<br />public void run(){<br />for(int i=0;i&lt;100;i++){<br />dec();<br />}<br /> }<br />  }<br />}<br /><br /><br /><strong>29、Java有没有goto?</strong><br />java中的保留字，现在没有在java中使用。<br /><br /><br /><strong>30、启动一个线程是用run()还是start()?</strong><br />启动一个线程是调用start()方法，使线程所代表的虚拟处理机处于可运行状态，这意味着它可以由JVM调度并执行。这并不意味着线程就会立即运行。run()方法可以产生必须退出的标志来停止一个线程。<br /><br /><br /><strong>31、EJB包括（SessionBean,EntityBean）说出他们的生命周期，及如何管理事务的？<br /></strong>SessionBean：Stateless Session Bean 的生命周期是由容器决定的，当客户机发出请求要建立一个Bean的实例时，EJB容器不一定要创建一个新的Bean的实例供客户机调用，而是随便找一个现有的实例提供给客户机。当客户机第一次调用一个Stateful Session Bean 时，容器必须立即在服务器中创建一个新的Bean实例，并关联到客户机上，以后此客户机调用Stateful Session Bean 的方法时容器会把调用分派到与此客户机相关联的Bean实例。<br />EntityBean：Entity Beans能存活相对较长的时间，并且状态是持续的。只要数据库中的数据存在，Entity beans就一直存活。而不是按照应用程序或者服务进程来说的。即使EJB容器崩溃了，Entity beans也是存活的。Entity Beans生命周期能够被容器或者 Beans自己管理。<br />EJB通过以下技术管理实务：对象管理组织（OMG）的对象实务服务（OTS），Sun Microsystems的Transaction Service（JTS）、Java Transaction API（JTA），开发组（X/Open）的XA接口。<br /><br /><br /><strong>32、应用服务器有那些？</strong><br />BEA WebLogic Server，IBM WebSphere Application Server，Oracle9i Application Server，jBoss，Tomcat<br /><br /><br /><strong>33、给我一个你最常见到的runtime exception。</strong><br />ArithmeticException, ArrayStoreException, BufferOverflowException, BufferUnderflowException, CannotRedoException, CannotUndoException, ClassCastException, CMMException, ConcurrentModificationException, DOMException, EmptyStackException, IllegalArgumentException, IllegalMonitorStateException, IllegalPathStateException, IllegalStateException, ImagingOpException, IndexOutOfBoundsException, MissingResourceException, NegativeArraySizeException, NoSuchElementException, NullPointerException, ProfileDataException, ProviderException, RasterFormatException, SecurityException, SystemException, UndeclaredThrowableException, UnmodifiableSetException, UnsupportedOperationException<br /><br /><br /><strong>34、接口是否可继承接口? 抽象类是否可实现(implements)接口? 抽象类是否可继承实体类(concrete class)?<br /></strong>接口可以继承接口。抽象类可以实现(implements)接口，抽象类是否可继承实体类，但前提是实体类必须有明确的构造函数。<br /><br /><br /><strong>35、List, Set, Map是否继承自Collection接口?</strong><br />    List，Set是，Map不是<br /><br /><br /><strong>36、说出数据连接池的工作机制是什么?</strong><br />J2EE服务器启动时会建立一定数量的池连接，并一直维持不少于此数目的池连接。客户端程序需要连接时，池驱动程序会返回一个未使用的池连接并将其表记为忙。如果当前没有空闲连接，池驱动程序就新建一定数量的连接，新建连接的数量有配置参数决定。当使用的池连接调用完成后，池驱动程序将此连接表记为空闲，其他调用就可以使用这个连接。<br /><br /><br /><strong>37、abstract的method是否可同时是static,是否可同时是native，是否可同时是synchronized?</strong><br />    都不能<br /><br /><br /><strong>38、数组有没有length()这个方法? String有没有length()这个方法？</strong><br />数组没有length()这个方法，有length的属性。String有有length()这个方法。<br /><br /><br /><strong>39、Set里的元素是不能重复的，那么用什么方法来区分重复与否呢? 是用==还是equals()? 它们有何区别?<br />Set里的元素是不能重复的，那么用iterator()方法来区分重复与否。equals()是判读两个Set是否相等。</strong><br />    equals()和==方法决定引用值是否指向同一对象equals()在类中被覆盖，为的是当两个分离的对象的内容和类型相配的话，返回真值。<br /><br /><br /><strong>40、构造器Constructor是否可被override?<br /></strong>构造器Constructor不能被继承，因此不能重写Overriding，但可以被重载Overloading。<br /> <br /> <br /><strong>41、是否可以继承String类?</strong><br />String类是final类故不可以继承。<br /><br /><br /><strong>42、swtich是否能作用在byte上，是否能作用在long上，是否能作用在String上?</strong><br />switch（expr1）中，expr1是一个整数表达式。因此传递给 switch 和 case 语句的参数应该是 int、 short、 char 或者 byte。long,string 都不能作用于swtich。<br /><br /><br /><strong>43、try {}里有一个return语句，那么紧跟在这个try后的finally {}里的code会不会被执行，什么时候被执行，在return前还是后?<br /></strong>会执行，在return前执行。<br /><br /><br /><strong>44、编程题: 用最有效率的方法算出2乘以8等於几?</strong> <br />2 &lt;&lt; 3<br /><br /><br /><strong>45、两个对象值相同(x.equals(y) == true)，但却可有不同的hash code，这句话对不对?</strong><br />不对，有相同的hash code。<br /><br /><br />46、<strong>当一个对象被当作参数传递到一个方法后，此方法可改变这个对象的属性，并可返回变化后的结果，那么这里到底是值传递还是引用传递? <br /></strong>是值传递。Java 编程语言只有值传递参数。当一个对象实例作为一个参数被传递到方法中时，参数的值就是对该对象的引用。对象的内容可以在被调用的方法中改变，但对象的引用是永远不会改变的。<br /><br /><br /><strong>47、当一个线程进入一个对象的一个synchronized方法后，其它线程是否可进入此对象的其它方法?<br /></strong>不能，一个对象的一个synchronized方法只能由一个线程访问。<br /><br /><br /><strong>48、编程题: 写一个Singleton出来。</strong><br />Singleton模式主要作用是保证在Java应用程序中，一个类Class只有一个实例存在。<br />一般Singleton模式通常有几种种形式:<br />第一种形式: 定义一个类，它的构造函数为private的，它有一个static的private的该类变量，在类初始化时实例话，通过一个public的getInstance方法获取对它的引用,继而调用其中的方法。<br />public class Singleton {<br />private Singleton(){}<br />　　    file://在自己内部定义自己一个实例，是不是很奇怪？<br />　　    file://注意这是private 只供内部调用<br />　　    private static Singleton instance = new Singleton();<br />　　    file://这里提供了一个供外部访问本class的静态方法，可以直接访问　　<br />　　    public static Singleton getInstance() {<br />　　　　    return instance; 　　<br />　　    } <br />    } <br />    第二种形式: <br />public class Singleton { <br />　　private static Singleton instance = null;<br />　　public static synchronized Singleton getInstance() {<br />　　file://这个方法比上面有所改进，不用每次都进行生成对象，只是第一次　　　 　<br />　　file://使用时生成实例，提高了效率！<br />　　if (instance==null)<br />　　　　instance＝new Singleton();<br />return instance; 　　} <br />} <br />其他形式:<br />定义一个类，它的构造函数为private的，所有方法为static的。<br />一般认为第一种形式要更加安全些 <br /><br /><br /><strong>49、Java的接口和C++的虚类的相同和不同处。</strong><br />由于Java不支持多继承，而有可能某个类或对象要使用分别在几个类或对象里面的方法或属性，现有的单继承机制就不能满足要求。与继承相比，接口有更高的灵活性，因为接口中没有任何实现代码。当一个类实现了接口以后，该类要实现接口里面所有的方法和属性，并且接口里面的属性在默认状态下面都是public static,所有方法默认情况下是public.一个类可以实现多个接口。<br /><br /><br /><strong>50、Java中的异常处理机制的简单原理和应用。</strong><br />当JAVA程序违反了JAVA的语义规则时，JAVA虚拟机就会将发生的错误表示为一个异常。违反语义规则包括2种情况。一种是JAVA类库内置的语义检查。例如数组下标越界,会引发IndexOutOfBoundsException;访问null的对象时会引发NullPointerException。另一种情况就是JAVA允许程序员扩展这种语义检查，程序员可以创建自己的异常，并自由选择在何时用throw关键字引发异常。所有的异常都是java.lang.Thowable的子类。<br /></p></div>
								</td>
						</tr>
						<tr>
								<td>
										<table cellspacing="0" border="0">
												<tbody>
												</tbody>
										</table>
								</td>
						</tr>
						<tr>
								<td class="bvh8">
								</td>
						</tr>
						<tr>
								<td width="100%">
								</td>
						</tr>
				</tbody>
		</table>
<img src ="http://www.blogjava.net/nbtymm/aggbug/51696.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/nbtymm/" target="_blank">nbt</a> 2006-06-09 15:21 <a href="http://www.blogjava.net/nbtymm/archive/2006/06/09/51696.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>抽象类与接口的区别(转载)</title><link>http://www.blogjava.net/nbtymm/archive/2006/06/09/51648.html</link><dc:creator>nbt</dc:creator><author>nbt</author><pubDate>Fri, 09 Jun 2006 03:31:00 GMT</pubDate><guid>http://www.blogjava.net/nbtymm/archive/2006/06/09/51648.html</guid><wfw:comment>http://www.blogjava.net/nbtymm/comments/51648.html</wfw:comment><comments>http://www.blogjava.net/nbtymm/archive/2006/06/09/51648.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/nbtymm/comments/commentRss/51648.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/nbtymm/services/trackbacks/51648.html</trackback:ping><description><![CDATA[abstract class和<font color="#000000">interface</font>是Java语言中对于抽象类定义进行支持的两种机制，正是由于这两种机制的存在，才赋予了Java强大的面向对象能力。 abstract class和interface之间在对于抽象类定义的支持方面具有很大的相似性，甚至可以相互替换，因此很多开发者在进行抽象类定义时对于 abstract class和interface的选择显得比较随意。<br />其实，两者之间还是有很大的区别的，对于它们的选择甚至反映出对于问题领域本质的理解、对于设计意图的理解是否正确、合理。本文将对它们之间的区别进行一番剖析，试图给开发者提供一个在二者之间进行选择的依据。<br />一、理解抽象类<br />abstract class和interface在Java语言中都是用来进行抽象类（本文中的抽象类并非从abstract class翻译而来，它表示的是一个抽象体，而abstract class为Java语言中用于定义抽象类的一种方法，请读者注意区分）定义的，那么什么是抽象类，使用抽象类能为我们带来什么好处呢？<br />在面向对象的概念中，我们知道所有的对象都是通过类来描绘的，但是反过来却不是这样。并不是所有的类都是用来描绘对象的，如果一个类中没有包含足够的信息来描绘一个具体的对象，这样的类就是抽象类。抽象类往往用来表征我们在对问题领域进行分析、设计中得出的抽象概念，是对一系列看上去不同，但是本质上相同的具体概念的抽象。<br />比如：如果我们进行一个图形编辑软件的开发，就会发现问题领域存在着圆、三角形这样一些具体概念，它们是不同的，但是它们又都属于形状这样一个概念，形状这个概念在问题领域是不存在的，它就是一个抽象概念。正是因为抽象的概念在问题领域没有对应的具体概念，所以用以表征抽象概念的抽象类是不能够实例化的。<br />在面向对象领域，抽象类主要用来进行类型隐藏。我们可以构造出一个固定的一组行为的抽象描述，但是这组行为却能够有任意个可能的具体实现方式。这个抽象描述就是抽象类，而这一组任意个可能的具体实现则表现为所有可能的派生类。模块可以操作一个抽象体。由于模块依赖于一个固定的抽象体，因此它可以是不允许修改的；同时，通过从这个抽象体派生，也可扩展此模块的行为功能。熟悉OCP的读者一定知道，为了能够实现面向对象设计的一个最核心的原则OCP(Open-Closed Principle)，抽象类是其中的关键所在。<br />二、从语法定义层面看abstract class和interface<br />在语法层面，Java语言对于abstract class和interface给出了不同的定义方式，下面以定义一个名为Demo的抽象类为例来说明这种不同。使用abstract class的方式定义Demo抽象类的方式如下：<br /><br />abstract class Demo ｛<br />abstract void method1();<br />abstract void method2();<br />…<br />｝<br /><br /><br />使用interface的方式定义Demo抽象类的方式如下：<br /><br />interface Demo {<br />void method1();<br />void method2();<br />…<br />}<br /><br /><br />在abstract class方式中，Demo可以有自己的数据成员，也可以有非abstarct的成员方法，而在interface方式的实现中，Demo只能够有静态的不能被修改的数据成员（也就是必须是static final的，不过在interface中一般不定义数据成员），所有的成员方法都是abstract的。从某种意义上说，interface是一种特殊形式的abstract class。<br />从编程的角度来看，abstract class和interface都可以用来实现"design by contract"的思想。但是在具体的使用上面还是有一些区别的。<br />首先，abstract class在Java语言中表示的是一种继承关系，一个类只能使用一次继承关系。但是，一个类却可以实现多个interface。也许，这是Java语言的设计者在考虑Java对于多重继承的支持方面的一种折中考虑吧。<br />其次，在abstract class的定义中，我们可以赋予方法的默认行为。但是在interface的定义中，方法却不能拥有默认行为，为了绕过这个限制，必须使用委托，但是这会 增加一些复杂性，有时会造成很大的麻烦。<br />在抽象类中不能定义默认行为还存在另一个比较严重的问题，那就是可能会造成维护上的麻烦。因为如果后来想修改类的界面（一般通过abstract class或者interface来表示）以适应新的情况（比如，添加新的方法或者给已用的方法中添加新的参数）时，就会非常的麻烦，可能要花费很多的时间（对于派生类很多的情况，尤为如此）。但是如果界面是通过abstract class来实现的，那么可能就只需要修改定义在abstract class中的默认行为就可以了。<br />同样，如果不能在抽象类中定义默认行为，就会导致同样的方法实现出现在该抽象类的每一个派生类中，违反了 "one rule，one place"原则，造成代码重复，同样不利于以后的维护。因此，在abstract class和interface间进行选择时要非常的小心。<br />三、从设计理念层面看abstract class和interface<br />上面主要从语法定义和编程的角度论述了abstract class和interface的区别，这些层面的区别是比较低层次的、非本质的。本文将从另一个层面：abstract class和interface所反映出的设计理念，来分析一下二者的区别。作者认为，从这个层面进行分析才能理解二者概念的本质所在。<br />前面已经提到过，abstarct class在Java语言中体现了一种继承关系，要想使得继承关系合理，父类和派生类之间必须存在"is a"关系，即父类和派生类在概念本质上应该是相同的。对于interface 来说则不然，并不要求interface的实现者和interface定义在概念本质上是一致的，仅仅是实现了interface定义的契约而已。为了使论述便于理解，下面将通过一个简单的实例进行说明。<br />考虑这样一个例子，假设在我们的问题领域中有一个关于Door的抽象概念，该Door具有执行两个动作open和close，此时我们可以通过abstract class或者interface来定义一个表示该抽象概念的类型，定义方式分别如下所示：<br /><br />使用abstract class方式定义Door：<br /><br />abstract class Door {<br />abstract void open();<br />abstract void close()；<br />}<br /><br />使用interface方式定义Door：<br /><br />interface Door {<br />void open();<br />void close();<br />}<br /><br /><br />其他具体的Door类型可以extends使用abstract class方式定义的Door或者implements使用interface方式定义的Door。看起来好像使用abstract class和interface没有大的区别。<br />如果现在要求Door还要具有报警的功能。我们该如何设计针对该例子的类结构呢（在本例中，主要是为了展示abstract class和interface反映在设计理念上的区别，其他方面无关的问题都做了简化或者忽略）下面将罗列出可能的解决方案，并从设计理念层面对这些不同的方案进行分析。<br />解决方案一：<br />简单的在Door的定义中增加一个alarm方法，如下：<br /><br />abstract class Door {<br />abstract void open();<br />abstract void close()；<br />abstract void alarm();<br />}<br /><br /><br />或者<br /><br />interface Door {<br />void open();<br />void close();<br />void alarm();<br />}<br /><br /><br />那么具有报警功能的AlarmDoor的定义方式如下：<br /><br />class AlarmDoor extends Door {<br />void open() { … }<br />void close() { … }<br />void alarm() { … }<br />}<br /><br /><br />或者<br /><br />class AlarmDoor implements Door ｛<br />void open() { … }<br />void close() { … }<br />void alarm() { … }<br />｝<br /><br /><br />这种方法违反了面向对象设计中的一个核心原则ISP（Interface Segregation Priciple），在Door的定义中把Door概念本身固有的行为方法和另外一个概念"报警器"的行为方法混在了一起。这样引起的一个问题是那些仅仅依赖于Door这个概念的模块会因为"报警器"这个概念的改变（比如：修改alarm方法的参数）而改变，反之依然。<br />解决方案二：<br />既然open、close和alarm属于两个不同的概念，根据ISP原则应该把它们分别定义在代表这两个概念的抽象类中。定义方式有：这两个概念都使用 abstract class方式定义；两个概念都使用interface方式定义；一个概念使用abstract class方式定义，另一个概念使用interface方式定义。<br />显然，由于Java语言不支持多重继承，所以两个概念都使用abstract class方式定义是不可行的。后面两种方式都是可行的，但是对于它们的选择却反映出对于问题领域中的概念本质的理解、对于设计意图的反映是否正确、合理。我们一一来分析、说明。<br />如果两个概念都使用interface方式来定义，那么就反映出两个问题：<br />1、我们可能没有理解清楚问题领域，AlarmDoor在概念本质上到底是Door还是报警器？<br />2、如果我们对于问题领域的理解没有问题，比如：我们通过对于问题领域的分析发现AlarmDoor在概念本质上和Door是一致的，那么我们在实现时就没有能够正确的揭示我们的设计意图，因为在这两个概念的定义上（均使用interface方式定义）反映不出上述含义。<br />如果我们对于问题领域的理解是：AlarmDoor在概念本质上是Door，同时它有具有报警的功能。我们该如何来设计、实现来明确的反映出我们的意思呢？前面已经说过， abstract class在Java语言中表示一种继承关系，而继承关系在本质上是"is a"关系。所以对于Door这个概念，我们应该使用abstarct class方式来定义。另外，AlarmDoor又具有报警功能，说明它又能够完成报警概念中定义的行为，所以报警概念可以通过interface方式定义。如下所示：<br /><br />abstract class Door {<br />abstract void open();<br />abstract void close()；<br />}<br />interface Alarm {<br />void alarm();<br />}<br />class AlarmDoor extends Door implements Alarm {<br />void open() { … }<br />void close() { … }<br />void alarm() { … }<br />}<br /><br /><br />这种实现方式基本上能够明确的反映出我们对于问题领域的理解，正确的揭示我们的设计意图。其实abstract class表示的是"is a"关系，interface表示的是"like a"关系，大家在选择时可以作为一个依据，当然这是建立在对问题领域的理解上的，比如：如果我们认为AlarmDoor在概念本质上是报警器，同时又具有 Door的功能，那么上述的定义方式就要反过来了。<br />abstract class和interface是Java语言中的两种定义抽象类的方式，它们之间有很大的相似性。但是对于它们的选择却又往往反映出对于问题领域中的概念本质的理解、对于设计意图的反映是否正确、合理，因为它们表现了概念间的不同的关系（虽然都能够实现需求的功能）。这其实也是语言的一种的惯用法，希望读者朋友能够细细体会 <img src ="http://www.blogjava.net/nbtymm/aggbug/51648.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/nbtymm/" target="_blank">nbt</a> 2006-06-09 11:31 <a href="http://www.blogjava.net/nbtymm/archive/2006/06/09/51648.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>彻底明白Java的IO系统(转载)</title><link>http://www.blogjava.net/nbtymm/archive/2006/06/09/51630.html</link><dc:creator>nbt</dc:creator><author>nbt</author><pubDate>Fri, 09 Jun 2006 02:30:00 GMT</pubDate><guid>http://www.blogjava.net/nbtymm/archive/2006/06/09/51630.html</guid><wfw:comment>http://www.blogjava.net/nbtymm/comments/51630.html</wfw:comment><comments>http://www.blogjava.net/nbtymm/archive/2006/06/09/51630.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/nbtymm/comments/commentRss/51630.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/nbtymm/services/trackbacks/51630.html</trackback:ping><description><![CDATA[
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
								</td>
						</tr>
						<!-- end of article title -->
						<tr>
								<td valign="top" align="middle" width="100%">
										<!--start of article content -->
										<table width="98%" border="0">
												<tbody>
														<tr>
																<td class="text" align="left" width="100%">一． Input和Output<br />1. stream代表的是任何有能力产出数据的数据源，或是任何有能力接收数据的接收源。在Java的IO中，所有的stream（包括Input和Out stream）都包括两种类型：<br />1.1 以字节为导向的stream<br />以字节为导向的stream，表示以字节为单位从stream中读取或往stream中写入信息。以字节为导向的stream包括下面几种类型：<br />1) input　stream：<br />1) ByteArrayInputStream：把内存中的一个缓冲区作为InputStream使用<br />2) StringBufferInputStream：把一个String对象作为InputStream<br />3) FileInputStream：把一个文件作为InputStream，实现对文件的读取操作<br />4) PipedInputStream：实现了pipe的概念，主要在线程中使用<br />5) SequenceInputStream：把多个InputStream合并为一个InputStream<br />2) Out　stream<br />1) ByteArrayOutputStream：把信息存入内存中的一个缓冲区中<br />2) FileOutputStream：把信息存入文件中<br />3) PipedOutputStream：实现了pipe的概念，主要在线程中使用<br />4) SequenceOutputStream：把多个OutStream合并为一个OutStream<br />1.2 以Unicode字符为导向的stream<br />以Unicode字符为导向的stream，表示以Unicode字符为单位从stream中读取或往stream中写入信息。以Unicode字符为导向的stream包括下面几种类型：<br />1) Input　Stream<br />1) CharArrayReader：与ByteArrayInputStream对应<br />2) StringReader：与StringBufferInputStream对应<br />3) FileReader：与FileInputStream对应<br />4) PipedReader：与PipedInputStream对应<br />2) Out　Stream<br />1) CharArrayWrite：与ByteArrayOutputStream对应<br />2) StringWrite：无与之对应的以字节为导向的stream<br />3) FileWrite：与FileOutputStream对应<br />4) PipedWrite：与PipedOutputStream对应<br /><br />以字符为导向的stream基本上对有与之相对应的以字节为导向的stream。两个对应类实现的功能相同，字是在操作时的导向不同。如CharArrayReader：和ByteArrayInputStream的作用都是把内存中的一个缓冲区作为InputStream使用，所不同的是前者每次从内存中读取一个字节的信息，而后者每次从内存中读取一个字符。<br />1.3 两种不现导向的stream之间的转换<br />InputStreamReader和OutputStreamReader：把一个以字节为导向的stream转换成一个以字符为导向的stream。<br />2. stream添加属性<br />2.1 “为stream添加属性”的作用<br />运用上面介绍的Java中操作IO的API，我们就可完成我们想完成的任何操作了。但通过FilterInputStream和FilterOutStream的子类，我们可以为stream添加属性。下面以一个例子来说明这种功能的作用。<br />如果我们要往一个文件中写入数据，我们可以这样操作：<br />FileOutStream fs = new FileOutStream(“test.txt”);<br />然后就可以通过产生的fs对象调用write()函数来往test.txt文件中写入数据了。但是，如果我们想实现“先把要写入文件的数据先缓存到内存中，再把缓存中的数据写入文件中”的功能时，上面的API就没有一个能满足我们的需求了。但是通过FilterInputStream和FilterOutStream的子类，为FileOutStream添加我们所需要的功能。<br />2.2 FilterInputStream的各种类型<br />2.2.1 用于封装以字节为导向的InputStream<br />1) DataInputStream：从stream中读取基本类型（int、char等）数据。<br />2) BufferedInputStream：使用缓冲区<br />3) LineNumberInputStream：会记录input stream内的行数，然后可以调用getLineNumber()和setLineNumber(int)<br />4) PushbackInputStream：很少用到，一般用于编译器开发<br />2.2.2 用于封装以字符为导向的InputStream<br />1) 没有与DataInputStream对应的类。除非在要使用readLine()时改用BufferedReader，否则使用DataInputStream<br />2) BufferedReader：与BufferedInputStream对应<br />3) LineNumberReader：与LineNumberInputStream对应<br />4) PushBackReader：与PushbackInputStream对应<br />2.3 FilterOutStream的各种类型<br />2.2.3 用于封装以字节为导向的OutputStream<br />1) DataIOutStream：往stream中输出基本类型（int、char等）数据。<br />2) BufferedOutStream：使用缓冲区<br />3) PrintStream：产生格式化输出<br />2.2.4 用于封装以字符为导向的OutputStream<br />1) BufferedWrite：与对应<br />2) PrintWrite：与对应<br />3. RandomAccessFile<br />1) 可通过RandomAccessFile对象完成对文件的读写操作<br />2) 在产生一个对象时，可指明要打开的文件的性质：r，只读；w，只写；rw可读写<br />3) 可以直接跳到文件中指定的位置<br />4. I/O应用的一个例子<br /><br />import java.io.*;<br />public class TestIO{<br />public static void main(String[] args)<br />throws IOException{<br />//1.以行为单位从一个文件读取数据<br />BufferedReader in = <br />new BufferedReader(<br />new FileReader("F:\\nepalon\\TestIO.java"));<br />String s, s2 = new String();<br />while((s = in.readLine()) != null)<br />s2 += s + "\n";<br />in.close();<br /><br />//1b. 接收键盘的输入<br />BufferedReader stdin = <br />new BufferedReader(<br />new InputStreamReader(System.in));<br />System.out.println("Enter a line:");<br />System.out.println(stdin.readLine());<br /><br />//2. 从一个String对象中读取数据<br />StringReader in2 = new StringReader(s2);<br />int c;<br />while((c = in2.read()) != -1)<br />System.out.println((char)c);<br />in2.close();<br /><br />//3. 从内存取出格式化输入<br />try{<br />DataInputStream in3 = <br />new DataInputStream(<br />new ByteArrayInputStream(s2.getBytes()));<br />while(true)<br />System.out.println((char)in3.readByte()); <br />}<br />catch(EOFException e){<br />System.out.println("End of stream");<br />}<br /><br />//4. 输出到文件<br />try{<br />BufferedReader in4 =<br />new BufferedReader(<br />new StringReader(s2));<br />PrintWriter out1 =<br />new PrintWriter(<br />new BufferedWriter(<br />new FileWriter("F:\\nepalon\\ TestIO.out")));<br />int lineCount = 1;<br />while((s = in4.readLine()) != null)<br />out1.println(lineCount++ + "：" + s);<br />out1.close();<br />in4.close();<br />}<br />catch(EOFException ex){<br />System.out.println("End of stream");<br />}<br /><br />//5. 数据的存储和恢复<br />try{<br />DataOutputStream out2 = <br />new DataOutputStream(<br />new BufferedOutputStream(<br />new FileOutputStream("F:\\nepalon\\ Data.txt")));<br />out2.writeDouble(3.1415926);<br />out2.writeChars("\nThas was pi:writeChars\n");<br />out2.writeBytes("Thas was pi:writeByte\n");<br />out2.close();<br />DataInputStream in5 =<br />new DataInputStream(<br />new BufferedInputStream(<br />new FileInputStream("F:\\nepalon\\ Data.txt")));<br />BufferedReader in5br =<br />new BufferedReader(<br />new InputStreamReader(in5));<br />System.out.println(in5.readDouble());<br />System.out.println(in5br.readLine());<br />System.out.println(in5br.readLine());<br />}<br /><br />catch(EOFException e){<br />System.out.println("End of stream");<br />}<br /><br />//6. 通过RandomAccessFile操作文件<br />RandomAccessFile rf =<br />new RandomAccessFile("F:\\nepalon\\ rtest.dat", "rw");<br />for(int i=0; i&lt;10; i++)<br />rf.writeDouble(i*1.414);<br />rf.close();<br /><br />rf = new RandomAccessFile("F:\\nepalon\\ rtest.dat", "r");<br />for(int i=0; i&lt;10; i++)<br />System.out.println("Value " + i + "：" + rf.readDouble());<br />rf.close();<br /><br />rf = new RandomAccessFile("F:\\nepalon\\ rtest.dat", "rw");<br />rf.seek(5*8);<br />rf.writeDouble(47.0001);<br />rf.close();<br /><br />rf = new RandomAccessFile("F:\\nepalon\\ rtest.dat", "r");<br />for(int i=0; i&lt;10; i++)<br />System.out.println("Value " + i + "：" + rf.readDouble());<br />rf.close();<br />}<br />}<br />关于代码的解释（以区为单位）：<br />1区中，当读取文件时，先把文件内容读到缓存中，当调用in.readLine()时，再从缓存中以字符的方式读取数据（以下简称“缓存字节读取方式”）。<br />1b区中，由于想以缓存字节读取方式从标准IO（键盘）中读取数据，所以要先把标准IO（System.in）转换成字符导向的stream，再进行BufferedReader封装。<br />2区中，要以字符的形式从一个String对象中读取数据，所以要产生一个StringReader类型的stream。<br />4区中，对String对象s2读取数据时，先把对象中的数据存入缓存中，再从缓冲中进行读取；对TestIO.out文件进行操作时，先把格式化后的信息输出到缓存中，再把缓存中的信息输出到文件中。<br />5区中，对Data.txt文件进行输出时，是先把基本类型的数据输出屋缓存中，再把缓存中的数据输出到文件中；对文件进行读取操作时，先把文件中的数据读取到缓存中，再从缓存中以基本类型的形式进行读取。注意in5.readDouble()这一行。因为写入第一个writeDouble()，所以为了正确显示。也要以基本类型的形式进行读取。<br />6区是通过RandomAccessFile类对文件进行操作。<br /></td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
<img src ="http://www.blogjava.net/nbtymm/aggbug/51630.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/nbtymm/" target="_blank">nbt</a> 2006-06-09 10:30 <a href="http://www.blogjava.net/nbtymm/archive/2006/06/09/51630.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JavaMail API详解(转自duduwjf )</title><link>http://www.blogjava.net/nbtymm/archive/2006/06/09/51627.html</link><dc:creator>nbt</dc:creator><author>nbt</author><pubDate>Fri, 09 Jun 2006 02:19:00 GMT</pubDate><guid>http://www.blogjava.net/nbtymm/archive/2006/06/09/51627.html</guid><wfw:comment>http://www.blogjava.net/nbtymm/comments/51627.html</wfw:comment><comments>http://www.blogjava.net/nbtymm/archive/2006/06/09/51627.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/nbtymm/comments/commentRss/51627.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/nbtymm/services/trackbacks/51627.html</trackback:ping><description><![CDATA[
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
								</td>
						</tr>
						<!-- end of article title -->
						<tr>
								<td valign="top" align="middle" width="100%">
										<!--start of article content -->
										<table width="98%" border="0">
												<tbody>
														<tr>
																<td class="text" align="left" width="100%">摘要:<br />JavaMail API是读取、撰写、发送电子信息的可选包。我们可用它来建立如Eudora、Foxmail、MS Outlook Express一般的邮件用户代理程序（Mail User Agent,简称MUA）。让我们看看JavaMail API是如何提供信息访问功能的吧！JavaMail API被设计用于以不依赖协议的方式去发送和接收电子信息，文中着重：如何以不依赖于协议的方式发送接收电子信息，这也是本文所要描述的. 文章工具<br />收藏<br />投票评分<br />发表评论<br />复制链接<br />版权声明：本文可以自由转载，转载时请务必以超链接形式标明文章原始出处和作者信息及本声明<br />作者:cleverpig(作者的Blog:<a href="http://blog.matrix.org.cn/page/cleverpig">http://blog.matrix.org.cn/page/cleverpig</a>)<br />原文:<a href="http://www.matrix.org.cn/resource/article/44/44101_JavaMail.html">http://www.matrix.org.cn/resource/article/44/44101_JavaMail.html</a><br />关键字:java,mail,pop,smtp<br /><br />一、JavaMail API简介<br />JavaMail API是读取、撰写、发送电子信息的可选包。我们可用它来建立如Eudora、Foxmail、MS Outlook Express一般的邮件用户代理程序（Mail User Agent,简称MUA）。而不是像sendmail或者其它的邮件传输代理（Mail Transfer Agent，简称MTA）程序那样可以传送、递送、转发邮件。从另外一个角度来看，我们这些电子邮件用户日常用MUA程序来读写邮件，而MUA依赖着MTA处理邮件的递送。<br />在清楚了到MUA与MTA之间的关系后，让我们看看JavaMail API是如何提供信息访问功能的吧！JavaMail API被设计用于以不依赖协议的方式去发送和接收电子信息，这个API被分为两大部分：<br /><br />基本功能：如何以不依赖于协议的方式发送接收电子信息，这也是本文所要描述的，不过在下文中，大家将看到这只是一厢情愿而已。<br />第二个部分则是依赖特定协议的，比如SMTP、POP、IMAP、NNTP协议。在这部分的JavaMail API是为了和服务器通讯，并不在本文的内容中。<br /><br />二、相关协议一览<br />在我们步入JavaMail API之前，先看一下API所涉及的协议。以下便是大家日常所知、所乐于使用的4大信息传输协议：<br />SMTP<br />POP<br />IMAP<br />MIME<br />当然，上面的4个协议，并不是全部，还有NNTP和其它一些协议可用于传输信息，但是由于不常用到，所以本文便不提及了。理解这4个基本的协议有助于我们更好的使用JavaMail API。然而JavaMail API是被设计为与协议无关的，目前我们并不能克服这些协议的束缚。确切的说，如果我们使用的功能并不被我们选择的协议支持，那么JavaMail API并不可能如魔术师一样神奇的赋予我们这种能力。<br /><br />1．SMTP<br />简单邮件传输协议定义了递送邮件的机制。在下文中，我们将使用基于Java-Mail的程序与公司或者ISP的SMTP服务器进行通讯。这个SMTP服务器将邮件转发到接收者的SMTP服务器，直至最后被接收者通过POP或者IMAP协议获取。这并不需要SMTP服务器使用支持授权的邮件转发，但是却的确要注意SMTP服务器的正确设置（SMTP服务器的设置与JavaMail API无关）。<br /><br />2．POP<br />POP是一种邮局协议，目前为第3个版本，即众所周知的POP3。POP定义了一种用户如何获得邮件的机制。它规定了每个用户使用一个单独的邮箱。大多数人在使用POP时所熟悉的功能并非都被支持，例如查看邮箱中的新邮件数量。而这个功能是微软的Outlook内建的，那么就说明微软Outlook之类的邮件客户端软件是通过查询最近收到的邮件来计算新邮件的数量来实现前面所说的功能。因此在我们使用JavaMail API时需要注意，当需要获得如前面所讲的新邮件数量之类的信息时，我们不得不自己进行计算。<br /><br />3．IMAP<br />IMAP使用在接收信息的高级协议，目前版本为第4版，所以也被称为IMAP4。需要注意的是在使用IMAP时，邮件服务器必须支持该协议。从这个方面讲，我们并不能完全使用IMAP来替代POP，不能期待IMAP在任何地方都被支持。假如邮件服务器支持IMAP，那么我们的邮件程序将能够具有以下被IMAP所支持的特性：每个用户在服务器上可具有多个目录，这些目录能在多个用户之间共享。<br />其与POP相比高级之处显而易见，但是在尝试采取IMAP时，我们认识到它并不是十分完美的：由于IMAP需要从其它服务器上接收新信息，将这些信息递送给用户，维护每个用户的多个目录，这都为邮件服务器带来了高负载。并且IMAP与POP的一个不同之处是POP用户在接收邮件时将从邮件服务器上下载邮件，而IMAP允许用户直接访问邮件目录，所以在邮件服务器进行备份作业时，由于每个长期使用此邮件系统的用户所用的邮件目录会占有很大的空间，这将直接导致邮件服务器上磁盘空间暴涨。<br /><br />4．MIME<br />MIME并不是用于传送邮件的协议，它作为多用途邮件的扩展定义了邮件内容的格式：信息格式、附件格式等等。一些RFC标准都涉及了MIME：RFC 822, RFC 2045, RFC 2046, RFC 2047，有兴趣的Matrixer可以阅读一下。而作为JavaMail API的开发者，我们并不需关心这些格式定义，但是这些格式被用在了程序中。<br /><br />5．NNTP和其它的第三方协议<br />正因为JavaMail API在设计时考虑到与第三方协议实现提供商之间的分离，故我们可以很容易的添加一些第三方协议。SUN维护着一个第三方协议实现提供商的列表：<a href="http://java.sun.com/products/javamail/Third_Party.html">http://java.sun.com/products/javamail/Third_Party.html</a>，通过此列表我们可以找到所需要的而又不被SUN提供支持的第三方协议：比如NNTP这个新闻组协议和S/MIME这个安全的MIME协议。<br /><br />三、安装<br />1．安装JavaMail<br />为了使用JavaMail API，需要从<a href="http://java.sun.com/products/javamail/downloads/index.html">http://java.sun.com/products/javamail/downloads/index.html</a>下载文件名格式为javamail-[version].zip的文件（这个文件中包括了JavaMail实现），并将其中的mail.jar文件添加到CLASSPATH中。这个实现提供了对SMTP、IMAP4、POP3的支持。<br />注意：在安装JavaMail实现之后，我们将在demo目录中发现许多有趣的简单实例程序。<br />在安装了JavaMail之后,我们还需要安装JavaBeans Activation Framework，因为这个框架是JavaMail API所需要的。如果我们使用J2EE的话，那么我们并无需单独下载JavaMail，因为它存在于J2EE.jar中，只需将J2EE.jar加入到CLASSPATH即可。<br /><br />2．安装JavaBeans Activation Framework<br />从<a href="http://java.sun.com/products/javabeans/glasgow/jaf.html">http://java.sun.com/products/javabeans/glasgow/jaf.html</a>下载JavaBeans Activation Framework，并将其添加到CLASSPATH中。此框架增加了对任何数据块的分类、以及对它们的处理的特性。这些特性是JavaMail API需要的。虽然听起来这些特性非常模糊，但是它对于我们的JavaMail API来说只是提供了基本的MIME类型支持。<br />到此为止，我们应当把mail.jar和activation.jar都添加到了CLASSPATH中。<br />当然如果从方便的角度讲，直接把这两个Jar文件复制到JRE目录的lib/ext目录中也可以。<br /><br />四、初次认识JavaMail API<br />1．了解我们的JavaMail环境<br />A．纵览JavaMail核心类结构<br />打开JavaMail.jar文件，我们将发现在javax.mail的包下面存在着一些核心类：Session、Message、Address、Authenticator、Transport、Store、Folder。而且在javax.mail.internet包中还有一些常用的子类。<br />B．Session<br />Session类定义了基本的邮件会话。就像Http会话那样，我们进行收发邮件的工作都是基于这个会话的。Session对象利用了java.util.Properties对象获得了邮件服务器、用户名、密码信息和整个应用程序都要使用到的共享信息。<br />Session类的构造方法是私有的，所以我们可以使用Session类提供的getDefaultInstance()这个静态工厂方法获得一个默认的Session对象：<br />Properties props = new Properties();// fill props with any informationSession session = Session.getDefaultInstance(props, null);<br />或者使用getInstance()这个静态工厂方法获得自定义的Session: <br />Properties props = new Properties();// fill props with any informationSession session = Session.getInstance(props, null);<br />从上面的两个例子中不难发现，getDefaultInstance()和getInstance()方法的第二个参数都是null，这是因为在上面的例子中并没有使用到邮件授权，下文中将对授权进行详细介绍。<br />从很多的实例看，在对mail server进行访问的过程中使用共享的Session是足够的，即使是工作在多个用户邮箱的模式下也不例外。<br /><br />C．Message<br />当我们建立了Session对象后，便可以被发送的构造信息体了。在这里SUN提供了Message类型来帮助开发者完成这项工作。由于Message是一个抽象类，大多数情况下，我们使用javax.mail.internet.MimeMessage这个子类，该类是使用MIME类型、MIME信息头的邮箱信息。信息头只能使用US-ASCII字符，而非ASCII字符将通过编码转换为ASCII的方式使用。<br />为了建立一个MimeMessage对象，我们必须将Session对象作为MimeMessage构造方法的参数传入：<br />MimeMessage message = new MimeMessage(session);<br />注意：对于MimeMessage类来讲存在着多种构造方法，比如使用输入流作为参数的构造方法。<br /><br />在建立了MimeMessage对象后，我们需要设置它的各个part，对于MimeMessage类来说，这些part就是MimePart接口。最基本的设置信息内容的方法就是通过表示信息内容和米么类型的参数调用setContent()方法：<br />message.setContent("Hello", "text/plain");<br />然而，如果我们所使用的MimeMessage中信息内容是文本的话，我们便可以直接使用setText()方法来方便的设置文本内容。<br />message.setText("Hello");<br />前面所讲的两种方法，对于文本信息，后者更为合适。而对于其它的一些信息类型，比如HTML信息，则要使用前者。<br />别忘记了，使用setSubject()方法对邮件设置邮件主题：<br />message.setSubject("First");<br /><br />D．Address<br />到这里，我们已经建立了Session和Message，下面将介绍如何使用邮件地址类：Address。像Message一样，Address类也是一个抽象类，所以我们将使用javax.mail.internet.InternetAddress这个子类。<br />通过传入代表邮件地址的字符串，我们可以建立一个邮件地址类：<br />Address address = new InternetAddress("president@whitehouse.gov"); <br />如果要在邮件地址后面增加名字的话，可以通过传递两个参数：代表邮件地址和名字的字符串来建立一个具有邮件地址和名字的邮件地址类：<br />Address address = new InternetAddress("president@whitehouse.gov", "George Bush"); <br />本文在这里所讲的邮件地址类是为了设置邮件信息的发信人和收信人而准备的，在建立了邮件地址类后，我们通过message的setFrom()和setReplyTo()两种方法设置邮件的发信人：<br />message.setFrom(address);message.setReplyTo(address);<br />若在邮件中存在多个发信人地址，我们可用addForm()方法增加发信人：<br />Address address[] = ...;message.addFrom(address);<br />为了设置收信人，我们使用addRecipient()方法增加收信人，此方法需要使用Message.RecipientType的常量来区分收信人的类型：<br />message.addRecipient(type, address)<br />下面是Message.RecipientType的三个常量:<br />Message.RecipientType.TO<br />Message.RecipientType.CC<br />Message.RecipientType.BCC<br />因此，如果我们要发送邮件给总统，并发用一个副本给第一夫人的话，下面的方法将被用到：<br />Address toAddress = new InternetAddress("vice.president@whitehouse.gov");Address ccAddress = new InternetAddress("first.lady@whitehouse.gov");message.addRecipient(Message.RecipientType.TO, toAddress);message.addRecipient(Message.RecipientType.CC, ccAddress);<br />JavaMail API并没有提供检查邮件地址有效性的机制。当然我们可以自己完成这个功能：验证邮件地址的字符是否按照RFC822规定的格式书写或者通过DNS服务器上的MX记录验证等。<br /><br />E．Authenticator<br />像java.net类那样，JavaMail API通过使用授权者类（Authenticator）以用户名、密码的方式访问那些受到保护的资源，在这里“资源”就是指邮件服务器。在javax.mail包中可以找到这个JavaMail的授权者类（Authenticator）。<br />在使用Authenticator这个抽象类时，我们必须采用继承该抽象类的方式，并且该继承类必须具有返回PasswordAuthentication对象（用于存储认证时要用到的用户名、密码）getPasswordAuthentication()方法。并且要在Session中进行注册，使Session能够了解在认证时该使用哪个类。<br />下面代码片断中的MyAuthenticator就是一个Authenticator的子类。<br />Properties props = new Properties();// fill props with any informationAuthenticator auth = new MyAuthenticator();Session session = Session.getDefaultInstance(props, auth);<br /><br />F．Transport<br />在发送信息时，Transport类将被用到。这个类实现了发送信息的协议（通称为SMTP），此类是一个抽象类，我们可以使用这个类的静态方法send()来发送消息：<br />Transport.send(message);<br />当然，方法是多样的。我们也可由Session获得相应协议对应的Transport实例。并通过传递用户名、密码、邮件服务器主机名等参数建立与邮件服务器的连接，并使用sendMessage()方法将信息发送，最后关闭连接：<br />message.saveChanges(); // implicit with send()Transport transport = session.getTransport("smtp");transport.connect(host, username, password);transport.sendMessage(message, message.getAllRecipients());transport.close();<br />评论：上面的方法是一个很好的方法，尤其是在我们在同一个邮件服务器上发送多个邮件时。因为这时我们将在连接邮件服务器后连续发送邮件，然后再关闭掉连接。send()这个基本的方法是在每次调用时进行与邮件服务器的连接的，对于在同一个邮件服务器上发送多个邮件来讲可谓低效的方式。<br />注意：如果需要在发送邮件过程中监控mail命令的话，可以在发送前设置debug标志：<br />session.setDebug(true)。<br /><br />G．Store和Folder<br />接收邮件和发送邮件很类似都要用到Session。但是在获得Session后，我们需要从Session中获取特定类型的Store，然后连接到Store，这里的Store代表了存储邮件的邮件服务器。在连接Store的过程中，极有可能需要用到用户名、密码或者Authenticator。<br />// Store store = session.getStore("imap");Store store = session.getStore("pop3");store.connect(host, username, password);<br />在连接到Store后，一个Folder对象即目录对象将通过Store的getFolder()方法被返回，我们可从这个Folder中读取邮件信息：<br />Folder folder = store.getFolder("INBOX");folder.open(Folder.READ_ONLY);Message message[] = folder.getMessages();<br />上面的例子首先从Store中获得INBOX这个Folder（对于POP3协议只有一个名为INBOX的Folder有效），然后以只读（Folder.READ_ONLY）的方式打开Folder，最后调用Folder的getMessages()方法得到目录中所有Message的数组。<br /><br />注意：对于POP3协议只有一个名为INBOX的Folder有效，而对于IMAP协议，我们可以访问多个Folder（想想前面讲的IMAP协议）。而且SUN在设计Folder的getMessages()方法时采取了很智能的方式：首先接收新邮件列表，然后再需要的时候（比如读取邮件内容）才从邮件服务器读取邮件内容。<br />在读取邮件时，我们可以用Message类的getContent()方法接收邮件或是writeTo()方法将邮件保存，getContent()方法只接收邮件内容（不包含邮件头），而writeTo()方法将包括邮件头。<br />System.out.println(((MimeMessage)message).getContent());<br />在读取邮件内容后，别忘记了关闭Folder和Store。<br />folder.close(aBoolean);store.close();<br />传递给Folder.close()方法的boolean 类型参数表示是否在删除操作邮件后更新Folder。 <br /><br />H．继续向前进！<br />在讲解了以上的七个Java Mail核心类定义和理解了简单的代码片断后，下文将详细讲解怎样使用这些类实现JavaMail API所要完成的高级功能。<br /><br />五、使用JavaMail API<br />在明确了JavaMail API的核心部分如何工作后，本人将带领大家学习一些使用Java Mail API任务案例。<br />1．发送邮件<br />在获得了Session后，建立并填入邮件信息，然后发送它到邮件服务器。这便是使用Java Mail API发送邮件的过程，在发送邮件之前，我们需要设置SMTP服务器：通过设置Properties的mail.smtp.host属性。<br />String host = ...;String from = ...;String to = ...;// Get system propertiesProperties props = System.getProperties();// Setup mail serverprops.put("mail.smtp.host", host);// Get sessionSession session = Session.getDefaultInstance(props, null);// Define messageMimeMessage message = new MimeMessage(session);message.setFrom(new InternetAddress(from));message.addRecipient(Message.RecipientType.TO,   new InternetAddress(to));message.setSubject("Hello JavaMail");message.setText("Welcome to JavaMail");// Send messageTransport.send(message);<br />由于建立邮件信息和发送邮件的过程中可能会抛出异常，所以我们需要将上面的代码放入到try-catch结构块中。<br /><br />2．接收邮件<br />为了在读取邮件，我们获得了session，并且连接到了邮箱的相应store，打开相应的Folder，然后得到我们想要的邮件，当然别忘记了在结束时关闭连接。<br />String host = ...;String username = ...;String password = ...;// Create empty propertiesProperties props = new Properties();// Get sessionSession session = Session.getDefaultInstance(props, null);// Get the storeStore store = session.getStore("pop3");store.connect(host, username, password);// Get folderFolder folder = store.getFolder("INBOX");folder.open(Folder.READ_ONLY);// Get directoryMessage message[] = folder.getMessages();for (int i=0, n=message.length; i&lt;n; i++) {   System.out.println(i + ": " + message[i].getFrom()[0]      + "\t" + message[i].getSubject());}// Close connection folder.close(false);store.close();<br />上面的代码所作的是从邮箱中读取每个邮件，并且显示邮件的发信人地址和主题。从技术角度讲，这里存在着一个异常的可能：当发信人地址为空时，getFrom()[0]将抛出异常。<br /><br />下面的代码片断有效的说明了如何读取邮件内容，在显示每个邮件发信人和主题后，将出现用户提示从而得到用户是否读取该邮件的确认，如果输入YES的话，我们可用Message.writeTo(java.io.OutputStream os)方法将邮件内容输出到控制台上，关于Message.writeTo()的具体用法请看JavaMail API。<br />BufferedReader reader = new BufferedReader (  new InputStreamReader(System.in));// Get directoryMessage message[] = folder.getMessages();for (int i=0, n=message.length; i&lt;n; i++) {  System.out.println(i + ": " + message[i].getFrom()[0]     + "\t" + message[i].getSubject());  System.out.println("Do you want to read message? " +    "[YES to read/QUIT to end]");  String line = reader.readLine();  if ("YES".equals(line)) {    message[i].writeTo(System.out);  } else if ("QUIT".equals(line)) {    break;  }}<br /><br />3．删除邮件和标志<br />设置与message相关的Flags是删除邮件的常用方法。这些Flags表示了一些系统定义和用户定义的不同状态。在Flags类的内部类Flag中预定义了一些标志：<br />Flags.Flag.ANSWERED<br />Flags.Flag.DELETED<br />Flags.Flag.DRAFT<br />Flags.Flag.FLAGGED<br />Flags.Flag.RECENT<br />Flags.Flag.SEEN<br />Flags.Flag.USER<br />但需要在使用时注意的：标志存在并非意味着这个标志被所有的邮件服务器所支持。例如，对于删除邮件的操作，POP协议不支持上面的任何一个。所以要确定哪些标志是被支持的??通过访问一个已经打开的Folder对象的getPermanetFlags()方法，它将返回当前被支持的Flags类对象。<br />删除邮件时，我们可以设置邮件的DELETED标志： <br />message.setFlag(Flags.Flag.DELETED, true);<br />但是首先要采用READ_WRITE的方式打开Folder：<br />folder.open(Folder.READ_WRITE);<br />在对邮件进行删除操作后关闭Folder时，需要传递一个true作为对删除邮件的擦除确认。<br />folder.close(true);<br />Folder类中另一种用于删除邮件的方法expunge()也同样可删除邮件，但是它并不为sun提供的POP3实现支持，而其它第三方提供的POP3实现支持或者并不支持这种方法。<br />另外，介绍一种检查某个标志是否被设置的方法：Message.isSet(Flags.Flag flag)方法，其中参数为被检查的标志。<br /><br />4．邮件认证<br />我们在前面已经学会了如何使用Authenticator类来代替直接使用用户名和密码这两字符串作为Session.getDefaultInstance()或者Session.getInstance()方法的参数。在前面的小试牛刀后，现在我们将了解到全面认识一下邮件认证。<br />我们在此取代了直接使用邮件服务器主机名、用户名、密码这三个字符串作为连接到POP3 Store的方式，使用存储了邮件服务器主机名信息的属性文件，并在获得Session时传入自定义的Authenticator实例：<br />// Setup propertiesProperties props = System.getProperties();props.put("mail.pop3.host", host);// Setup authentication, get sessionAuthenticator auth = new PopupAuthenticator();Session session = Session.getDefaultInstance(props, auth);// Get the storeStore store = session.getStore("pop3");store.connect();<br /><br />PopupAuthenticator类继承了抽象类Authenticator，并且通过重载Authenticator类的getPasswordAuthentication()方法返回PasswordAuthentication类对象。而getPasswordAuthentication()方法的参数param是以逗号分割的用户名、密码组成的字符串。<br />import javax.mail.*;import java.util.*;public class PopupAuthenticator extends Authenticator {  public PasswordAuthentication getPasswordAuthentication(String param) {    String username, password;    StringTokenizer st = new StringTokenizer(param, ",");    username = st.nextToken();    password = st.nextToken();    return new PasswordAuthentication(username, password);  }}<br /><br />5．回复邮件<br />回复邮件的方法很简单：使用Message类的reply()方法，通过配置回复邮件的收件人地址和主题（如果没有提供主题的话，系统将默认将“Re：”作为邮件的主体），这里不需要设置任何的邮件内容，只要复制发信人或者reply-to到新的收件人。而reply()方法中的boolean参数表示是否将邮件回复给发送者（参数值为false），或是恢复给所有人（参数值为true）。<br />补充一下，reply-to地址需要在发信时使用setReplyTo()方法设置。<br />MimeMessage reply = (MimeMessage)message.reply(false);reply.setFrom(new InternetAddress("president@whitehouse.gov"));reply.setText("Thanks");Transport.send(reply);<br /><br />6．转发邮件<br />转发邮件的过程不如前面的回复邮件那样简单，它将建立一个转发邮件，这并非一个方法就能做到。<br />每个邮件是由多个部分组成，每个部分称为一个邮件体部分，是一个BodyPart类对象，对于MIME类型邮件来讲就是MimeBodyPart类对象。这些邮件体包含在成为Multipart的容器中对于MIME类型邮件来讲就是MimeMultiPart类对象。在转发邮件时，我们建立一个文字邮件体部分和一个被转发的文字邮件体部分，然后将这两个邮件体放到一个Multipart中。说明一下，复制一个邮件内容到另一个邮件的方法是仅复制它的DataHandler（数据处理者）即可。这是由JavaBeans Activation Framework定义的一个类，它提供了对邮件内容的操作命令的访问、管理了邮件内容操作，是不同的数据源和数据格式之间的一致性接口。<br />// Create the message to forwardMessage forward = new MimeMessage(session);// Fill in headerforward.setSubject("Fwd: " + message.getSubject());forward.setFrom(new InternetAddress(from));forward.addRecipient(Message.RecipientType.TO,   new InternetAddress(to));// Create your new message partBodyPart messageBodyPart = new MimeBodyPart();messageBodyPart.setText(  "Here you go with the original message:\n\n");// Create a multi-part to combine the partsMultipart multipart = new MimeMultipart();multipart.addBodyPart(messageBodyPart);// Create and fill part for the forwarded contentmessageBodyPart = new MimeBodyPart();messageBodyPart.setDataHandler(message.getDataHandler());// Add part to multi partmultipart.addBodyPart(messageBodyPart);// Associate multi-part with messageforward.setContent(multipart);// Send messageTransport.send(forward);<br /><br />7．使用附件<br />附件作为与邮件相关的资源经常以文本、表格、图片等格式出现，如流行的邮件客户端一样，我们可以用JavaMail API从邮件中获取附件或是发送带有附件的邮件。<br /><br />A．发送带有附件的邮件<br />发送带有附件的邮件的过程有些类似转发邮件，我们需要建立一个完整邮件的各个邮件体部分，在第一个部分（即我们的邮件内容文字）后，增加一个具有DataHandler的附件而不是在转发邮件时那样复制第一个部分的DataHandler。<br /><br />如果我们将文件作为附件发送，那么要建立FileDataSource类型的对象作为附件数据源；如果从URL读取数据作为附件发送，那么将要建立URLDataSource类型的对象作为附件数据源。<br /><br />然后将这个数据源（FileDataSource或是URLDataSource）对象作为DataHandler类构造方法的参数传入，从而建立一个DataHandler对象作为数据源的DataHandler。<br /><br />接着将这个DataHandler设置为邮件体部分的DataHandler。这样就完成了邮件体与附件之间的关联工作，下面的工作就是BodyPart的setFileName()方法设置附件名为原文件名。<br /><br />最后将两个邮件体放入到Multipart中，设置邮件内容为这个容器Multipart，发送邮件。<br />// Define messageMessage message = new MimeMessage(session);message.setFrom(new InternetAddress(from));message.addRecipient(Message.RecipientType.TO,   new InternetAddress(to));message.setSubject("Hello JavaMail Attachment");// Create the message part BodyPart messageBodyPart = new MimeBodyPart();// Fill the messagemessageBodyPart.setText("Pardon Ideas");Multipart multipart = new MimeMultipart();multipart.addBodyPart(messageBodyPart);// Part two is attachmentmessageBodyPart = new MimeBodyPart();DataSource source = new FileDataSource(filename);messageBodyPart.setDataHandler(new DataHandler(source));messageBodyPart.setFileName(filename);multipart.addBodyPart(messageBodyPart);// Put parts in messagemessage.setContent(multipart);// Send the messageTransport.send(message);<br />如果我们使用servlet实现发送带有附件的邮件，则必须上传附件给servlet，这时需要注意提交页面form中对编码类型的设置应为multipart/form-data。<br />&lt;FORM ENCTYPE="multipart/form-data"     method=post action="/myservlet"&gt;   &lt;INPUT TYPE="file" NAME="thefile"&gt;  &lt;INPUT TYPE="submit" VALUE="Upload"&gt;&lt;/FORM&gt;<br /><br />B．读取邮件中的附件<br />读取邮件中的附件的过程要比发送它的过程复杂一点。因为带有附件的邮件是多部分组成的，我们必须处理每一个部分获得邮件的内容和附件。<br />但是如何辨别邮件信息内容和附件呢？Sun在Part类（BodyPart类实现的接口类）中提供了getDisposition()方法让开发者获得邮件体部分的部署类型，当该部分是附件时，其返回之将是Part.ATTACHMENT。但附件也可以没有部署类型的方式存在或者部署类型为Part.INLINE，无论部署类型为Part.ATTACHMENT还是Part.INLINE，我们都能把该邮件体部分导出保存。<br />Multipart mp = (Multipart)message.getContent();for (int i=0, n=multipart.getCount(); i&lt;n; i++) {  Part part = multipart.getBodyPart(i));  String disposition = part.getDisposition();  if ((disposition != null) &amp;&amp;       ((disposition.equals(Part.ATTACHMENT) ||        (disposition.equals(Part.INLINE))) {    saveFile(part.getFileName(), part.getInputStream());  }}<br />下列代码中使用了saveFile方法是自定义的方法，它根据附件的文件名建立一个文件，如果本地磁盘上存在名为附件的文件，那么将在文件名后增加数字表示区别。然后从邮件体中读取数据写入到本地文件中（代码省略）。<br />// from saveFile()File file = new File(filename);for (int i=0; file.exists(); i++) {  file = new File(filename+i);}<br />以上是邮件体部分被正确设置的简单例子，如果邮件体部分的部署类型为null，那么我们通过获得邮件体部分的MIME类型来判断其类型作相应的处理，代码结构框架如下：<br />if (disposition == null) {  // Check if plain  MimeBodyPart mbp = (MimeBodyPart)part;  if (mbp.isMimeType("text/plain")) {    // Handle plain  } else {    // Special non-attachment cases here of     // image/gif, text/html, ...  }...}<br /><br />8．处理HTML邮件<br />前面的例子中发送的邮件都是以文本为内容的（除了附件），下面将介绍如何接收和发送基于HTML的邮件。<br />A．发送HTML邮件<br />假如我们需要发送一个HTML文件作为邮件内容，并使邮件客户端在读取邮件时获取相关的图片或者文字的话，只要设置邮件内容为html代码，并设置内容类型为text/html即可：<br />String htmlText = "&lt;H1&gt;Hello&lt;/H1&gt;" +   "&lt;img src=\"http://www.jguru.com/images/logo.gif\"&gt;";message.setContent(htmlText, "text/html"));<br />请注意：这里的图片并不是在邮件中内嵌的，而是在URL中定义的。邮件接收者只有在线时才能看到。<br />在接收邮件时，如果我们使用JavaMail API接收邮件的话是无法实现以HTML方式显示邮件内容的。因为JavaMail API邮件内容视为二进制流。所以要显示HTML内容的邮件，我们必须使用JEditorPane或者第三方HTML展现组件。<br /><br />以下代码显示了如何使用JEditorPane显示邮件内容：<br />if (message.getContentType().equals("text/html")) {  String content = (String)message.getContent();  JFrame frame = new JFrame();  JEditorPane text = new JEditorPane("text/html", content);  text.setEditable(false);  JScrollPane pane = new JScrollPane(text);  frame.getContentPane().add(pane);  frame.setSize(300, 300);  frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);  frame.show();}<br /><br />B．在邮件中包含图片<br />如果我们在邮件中使用HTML作为内容，那么最好将HTML中使用的图片作为邮件的一部分，这样无论是否在线都会正确的显示HTML中的图片。处理方法就是将HTML中用到的图片作为邮件附件并使用特殊的cid URL作为图片的引用，这个cid就是对图片附件的Content-ID头的引用。<br />处理内嵌图片就像向邮件中添加附件一样，不同之处在于我们必须通过设置图片附件所在的邮件体部分的header中Content-ID为一个随机字符串，并在HTML中img的src标记中设置为该字符串。这样就完成了图片附件与HTML的关联。<br />String file = ...;// Create the messageMessage message = new MimeMessage(session);// Fill its headersmessage.setSubject("Embedded Image");message.setFrom(new InternetAddress(from));message.addRecipient(Message.RecipientType.TO,   new InternetAddress(to));// Create your new message partBodyPart messageBodyPart = new MimeBodyPart();String htmlText = "&lt;H1&gt;Hello&lt;/H1&gt;" +   "&lt;img src=\"cid:memememe\"&gt;";messageBodyPart.setContent(htmlText, "text/html");// Create a related multi-part to combine the partsMimeMultipart multipart = new MimeMultipart("related");multipart.addBodyPart(messageBodyPart);// Create part for the imagemessageBodyPart = new MimeBodyPart();// Fetch the image and associate to partDataSource fds = new FileDataSource(file);messageBodyPart.setDataHandler(new DataHandler(fds));messageBodyPart.setHeader("Content-ID","&lt;memememe&gt;");// Add part to multi-partmultipart.addBodyPart(messageBodyPart);// Associate multi-part with messagemessage.setContent(multipart);<br /><br />9．在邮件中搜索短语<br />JavaMail API提供了过滤器机制，它被用来建立搜索短语。这个短语由javax.mail.search包中的SearchTerm抽象类来定义，在定义后我们便可以使用Folder的Search()方法在Folder中查找邮件：<br />SearchTerm st = ...;Message[] msgs = folder.search(st);<br />下面有22个不同的类（继承了SearchTerm类）供我们使用：<br />AND terms (class AndTerm)<br />OR terms (class OrTerm)<br />NOT terms (class NotTerm)<br />SENT DATE terms (class SentDateTerm)<br />CONTENT terms (class BodyTerm)<br />HEADER terms (FromTerm / FromStringTerm, RecipientTerm / RecipientStringTerm, SubjectTerm, etc.)<br />使用这些类定义的断语集合，我们可以构造一个逻辑表达式，并在Folder中进行搜索。下面是一个实例：在Folder中搜索邮件主题含有“ADV”字符串或者发信人地址为friend@public.com的邮件。<br />SearchTerm st =   new OrTerm(    new SubjectTerm("ADV:"),     new FromStringTerm("friend@public.com"));Message[] msgs = folder.search(st);<br /><br />六、参考资源<br />JavaMail API Home<br />Sun’s JavaMail API基础<br />JavaBeans Activation Framework Home<br />javamail-interest mailing list<br />Sun's JavaMail FAQ<br />jGuru's JavaMail FAQ<br />Third Party Products List<br />七、代码下载<br />http://java.sun.com/developer/onlineTraining/JavaMail/exercises.html  </td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
<img src ="http://www.blogjava.net/nbtymm/aggbug/51627.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/nbtymm/" target="_blank">nbt</a> 2006-06-09 10:19 <a href="http://www.blogjava.net/nbtymm/archive/2006/06/09/51627.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java Reflection (JAVA反射)    ----转载</title><link>http://www.blogjava.net/nbtymm/archive/2006/06/05/50439.html</link><dc:creator>nbt</dc:creator><author>nbt</author><pubDate>Mon, 05 Jun 2006 03:05:00 GMT</pubDate><guid>http://www.blogjava.net/nbtymm/archive/2006/06/05/50439.html</guid><wfw:comment>http://www.blogjava.net/nbtymm/comments/50439.html</wfw:comment><comments>http://www.blogjava.net/nbtymm/archive/2006/06/05/50439.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/nbtymm/comments/commentRss/50439.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/nbtymm/services/trackbacks/50439.html</trackback:ping><description><![CDATA[
		<div class="postText">
				<br />    Reflection 是 Java 程序开发语言的特征之一，它允许运行中的 Java 程序对自身进行检查，或者说“自审”，并能直接操作程序的内部属性。例如，使用它能获得 Java 类中各成员的名称并显示出来。Java 的这一能力在实际应用中也许用得不是很多，但是在其它的程序设计语言中根本就不存在这一特性。例如，Pascal、C 或者 C++ 中就没有办法在程序中获得函数定义相关的信息。<br />JavaBean 是 reflection 的实际应用之一，它能让一些工具可视化的操作软件组件。这些工具通过 reflection 动态的载入并取得 Java 组件(类) 的属性。<br /><br />1. 一个简单的例子<br />考虑下面这个简单的例子，让我们看看 reflection 是如何工作的。<br />import java.lang.reflect.*;<br />public class DumpMethods {<br />    public static void main(String args[]) {<br />        try {<br />            Class c = Class.forName(args[0]);<br />            Method m[] = c.getDeclaredMethods();<br />            for (int i = 0; i &lt; m.length; i++)<br />                System.out.println(m[i].toString());<br />        } catch (Throwable e) {<br />            System.err.println(e);<br />        }<br />    }<br />}<br /><p><br />按如下语句执行：<br />java DumpMethods java.util.Stack<br /><br />它的结果输出为：<br />public java.lang.Object java.util.Stack.push(java.lang.Object)<br />public synchronized java.lang.Object java.util.Stack.pop()<br />public synchronized java.lang.Object java.util.Stack.peek()<br />public boolean java.util.Stack.empty()<br />public synchronized int java.util.Stack.search(java.lang.Object)</p><p>这样就列出了java.util.Stack 类的各方法名以及它们的限制符和返回类型。</p><p>这个程序使用 Class.forName 载入指定的类，然后调用 getDeclaredMethods 来获取这个类中定义了的方法列表。java.lang.reflect.Methods 是用来描述某个类中单个方法的一个类。</p><br /><p>2.开始使用 Reflection<br />用于 reflection 的类，如 Method，可以在 java.lang.relfect 包中找到。使用这些类的时候必须要遵循三个步骤：第一步是获得你想操作的类的 java.lang.Class 对象。在运行中的 Java 程序中，用 java.lang.Class 类来描述类和接口等。</p><p>下面就是获得一个 Class 对象的方法之一：<br />Class c = Class.forName("java.lang.String");<br />这条语句得到一个 String 类的类对象。还有另一种方法，如下面的语句：<br />Class c = int.class;   或者   Class c = Integer.TYPE;</p><p>它们可获得基本类型的类信息。其中后一种方法中访问的是基本类型的封装类 (如 Integer) 中预先定义好的 TYPE 字段。<br /><br />第二步是调用诸如 getDeclaredMethods 的方法，以取得该类中定义的所有方法的列表。<br /><br />一旦取得这个信息，就可以进行第三步了——使用 reflection API 来操作这些信息，如下面这段代码：<br />Class c = Class.forName("java.lang.String");<br />Method m[] = c.getDeclaredMethods();<br />System.out.println(m[0].toString());<br />它将以文本方式打印出 String 中定义的第一个方法的原型。<br />在下面的例子中，这三个步骤将为使用 reflection 处理特殊应用程序提供例证。</p><br /><p><br />模拟 instanceof 操作符<br />得到类信息之后，通常下一个步骤就是解决关于 Class 对象的一些基本的问题。例如，Class.isInstance 方法可以用于模拟 instanceof 操作符：<br />class A {<br />}<br /><br />public class instance1 {<br />    public static void main(String args[]) {<br />        try {<br />            Class cls = Class.forName("A");<br />            boolean b1 = cls.isInstance(new Integer(37));<br />            System.out.println(b1);<br />            boolean b2 = cls.isInstance(new A());<br />            System.out.println(b2);<br />        } catch (Throwable e) {<br />            System.err.println(e);<br />        }<br />    }<br />}<br /><br />在这个例子中创建了一个 A 类的 Class 对象，然后检查一些对象是否是 A 的实例。Integer(37) 不是，但 new A() 是。</p><p><br />3.找出类的方法<br />找出一个类中定义了些什么方法，这是一个非常有价值也非常基础的 reflection 用法。下面的代码就实现了这一用法：<br />import java.lang.reflect.*;<br />public class method1 {<br />    private int f1(Object p, int x) throws NullPointerException {<br />        if (p == null)<br />            throw new NullPointerException();<br />        return x;<br />    }<br />    public static void main(String args[]) {<br />        try {<br />            Class cls = Class.forName("method1");<br />            Method methlist[] = cls.getDeclaredMethods();<br />            for (int i = 0; i &lt; methlist.length; i++) {<br />                Method m = methlist[i];<br />                System.out.println("name = " + m.getName());<br />                System.out.println("decl class = " + m.getDeclaringClass());<br />                Class pvec[] = m.getParameterTypes();<br />                for (int j = 0; j &lt; pvec.length; j++)<br />                    System.out.println("param #" + j + " " + pvec[j]);<br />                Class evec[] = m.getExceptionTypes();<br />                for (int j = 0; j &lt; evec.length; j++)<br />                    System.out.println("exc #" + j + " " + evec[j]);<br />                System.out.println("return type = " + m.getReturnType());<br />                System.out.println("-----");<br />            }<br />        } catch (Throwable e) {<br />            System.err.println(e);<br />        }<br />    }<br />}</p><p><br />这个程序首先取得 method1 类的描述，然后调用 getDeclaredMethods 来获取一系列的 Method 对象，它们分别描述了定义在类中的每一个方法，包括 public 方法、protected 方法、package 方法和 private 方法等。如果你在程序中使用 getMethods 来代替 getDeclaredMethods，你还能获得继承来的各个方法的信息。<br /><br />取得了 Method 对象列表之后，要显示这些方法的参数类型、异常类型和返回值类型等就不难了。这些类型是基本类型还是类类型，都可以由描述类的对象按顺序给出。<br /><br />输出的结果如下：<br />name = f1<br />decl class = class method1<br />param #0 class java.lang.Object<br />param #1 int<br />exc #0 class java.lang.NullPointerException<br />return type = int<br />-----<br />name = main<br />decl class = class method1<br />param #0 class [Ljava.lang.String;<br />return type = void<br />-----</p><br /><p>4.获取构造器信息<br />获取类构造器的用法与上述获取方法的用法类似，如：<br />import java.lang.reflect.*;<br />public class constructor1 {<br />    public constructor1() {<br />    }<br /><br />    protected constructor1(int i, double d) {<br />    }<br /><br />    public static void main(String args[]) {<br />        try {<br />            Class cls = Class.forName("constructor1");<br />            Constructor ctorlist[] = cls.getDeclaredConstructors();<br />            for (int i = 0; i &lt; ctorlist.length; i++) {<br />                Constructor ct = ctorlist[i];<br />                System.out.println("name = " + ct.getName());<br />                System.out.println("decl class = " + ct.getDeclaringClass());<br />                Class pvec[] = ct.getParameterTypes();<br />                for (int j = 0; j &lt; pvec.length; j++)<br />                    System.out.println("param #" + j + " " + pvec[j]);<br />                Class evec[] = ct.getExceptionTypes();<br />                for (int j = 0; j &lt; evec.length; j++)<br />                    System.out.println("exc #" + j + " " + evec[j]);<br />                System.out.println("-----");<br />            }<br />        } catch (Throwable e) {<br />            System.err.println(e);<br />        }<br />    }<br />}</p><p><br />这个例子中没能获得返回类型的相关信息，那是因为构造器没有返回类型。<br />这个程序运行的结果是：<br />name = constructor1<br />decl class = class constructor1<br />-----<br />name = constructor1<br />decl class = class constructor1<br />param #0 int<br />param #1 double<br />-----<br /><br />5.获取类的字段(域)<br />找出一个类中定义了哪些数据字段也是可能的，下面的代码就在干这个事情：<br />import java.lang.reflect.*;<br /><br />public class field1 {<br />    private double d;<br />    public static final int i = 37;<br />    String s = "testing";<br /><br />     public static void main(String args[]) {<br />        try {<br />            Class cls = Class.forName("field1");<br />            Field fieldlist[] = cls.getDeclaredFields();<br />            for (int i = 0; i &lt; fieldlist.length; i++) {<br />                Field fld = fieldlist[i];<br />                System.out.println("name = " + fld.getName());<br />                System.out.println("decl class = " + fld.getDeclaringClass());<br />                System.out.println("type = " + fld.getType());<br />                int mod = fld.getModifiers();<br />                System.out.println("modifiers = " + Modifier.toString(mod));<br />                System.out.println("-----");<br />            }<br />        } catch (Throwable e) {<br />            System.err.println(e);<br />        }<br />    }<br />}</p><p><br />这个例子和前面那个例子非常相似。例中使用了一个新东西 Modifier，它也是一个 reflection 类，用来描述字段成员的修饰语，如“private int”。这些修饰语自身由整数描述，而且使用 Modifier.toString 来返回以“官方”顺序排列的字符串描述 (如“static”在“final”之前)。这个程序的输出是：<br />name = d<br />decl class = class field1<br />type = double<br />modifiers = private<br />-----<br />name = i<br />decl class = class field1<br />type = int<br />modifiers = public static final<br />-----<br />name = s<br />decl class = class field1<br />type = class java.lang.String<br />modifiers =<br />-----<br /><br />和获取方法的情况一下，获取字段的时候也可以只取得在当前类中申明了的字段信息 (getDeclaredFields)，或者也可以取得父类中定义的字段 (getFields) 。</p><br /><p>6.根据方法的名称来执行方法<br />文本到这里，所举的例子无一例外都与如何获取类的信息有关。我们也可以用 reflection 来做一些其它的事情，比如执行一个指定了名称的方法。下面的示例演示了这一操作：<br />import java.lang.reflect.*;<br />public class method2 {<br />    public int add(int a, int b) {<br />        return a + b;<br />    }<br />    public static void main(String args[]) {<br />        try {<br />            Class cls = Class.forName("method2");<br />            Class partypes[] = new Class[2];<br />            partypes[0] = Integer.TYPE;<br />            partypes[1] = Integer.TYPE;<br />            Method meth = cls.getMethod("add", partypes);<br />            method2 methobj = new method2();<br />            Object arglist[] = new Object[2];<br />            arglist[0] = new Integer(37);<br />            arglist[1] = new Integer(47);<br />            Object retobj = meth.invoke(methobj, arglist);<br />            Integer retval = (Integer) retobj;<br />            System.out.println(retval.intValue());<br />        } catch (Throwable e) {<br />            System.err.println(e);<br />        }<br />    }<br />}</p><p><br />假如一个程序在执行的某处的时候才知道需要执行某个方法，这个方法的名称是在程序的运行过程中指定的 (例如，JavaBean 开发环境中就会做这样的事)，那么上面的程序演示了如何做到。</p><p><br />上例中，getMethod 用于查找一个具有两个整型参数且名为 add 的方法。找到该方法并创建了相应的 Method 对象之后，在正确的对象实例中执行它。执行该方法的时候，需要提供一个参数列表，这在上例中是分别包装了整数 37 和 47 的两个 Integer 对象。执行方法的返回的同样是一个 Integer 对象，它封装了返回值 84。</p><p><br />7.创建新的对象<br />对于构造器，则不能像执行方法那样进行，因为执行一个构造器就意味着创建了一个新的对象 (准确的说，创建一个对象的过程包括分配内存和构造对象)。所以，与上例最相似的例子如下：<br />import java.lang.reflect.*;<br />public class constructor2 {<br />    public constructor2() {<br />    }<br /><br />    public constructor2(int a, int b) {<br />        System.out.println("a = " + a + " b = " + b);<br />    }<br /><br />    public static void main(String args[]) {<br />        try {<br />            Class cls = Class.forName("constructor2");<br />            Class partypes[] = new Class[2];<br />            partypes[0] = Integer.TYPE;<br />            partypes[1] = Integer.TYPE;<br />            Constructor ct = cls.getConstructor(partypes);<br />            Object arglist[] = new Object[2];<br />            arglist[0] = new Integer(37);<br />            arglist[1] = new Integer(47);<br />            Object retobj = ct.newInstance(arglist);<br />        } catch (Throwable e) {<br />            System.err.println(e);<br />        }<br />    }<br />}<br /><br />根据指定的参数类型找到相应的构造函数并执行它，以创建一个新的对象实例。使用这种方法可以在程序运行时动态地创建对象，而不是在编译的时候创建对象，这一点非常有价值。</p><p><br />8.改变字段(域)的值<br />reflection 的还有一个用处就是改变对象数据字段的值。reflection 可以从正在运行的程序中根据名称找到对象的字段并改变它，下面的例子可以说明这一点：<br />import java.lang.reflect.*;<br />public class field2 {<br />    public double d;<br />    public static void main(String args[]) {<br />        try {<br />            Class cls = Class.forName("field2");<br />            Field fld = cls.getField("d");<br />            field2 f2obj = new field2();<br />            System.out.println("d = " + f2obj.d);<br />            fld.setDouble(f2obj, 12.34);<br />            System.out.println("d = " + f2obj.d);<br />        } catch (Throwable e) {<br />            System.err.println(e);<br />        }<br />    }<br />}</p><p><br />这个例子中，字段 d 的值被变为了 12.34。<br />9.使用数组<br />本文介绍的 reflection 的最后一种用法是创建的操作数组。数组在 Java 语言中是一种特殊的类类型，一个数组的引用可以赋给 Object 引用。观察下面的例子看看数组是怎么工作的：<br />import java.lang.reflect.*;<br />public class array1 {<br />    public static void main(String args[]) {<br />        try {<br />            Class cls = Class.forName("java.lang.String");<br />            Object arr = Array.newInstance(cls, 10);<br />            Array.set(arr, 5, "this is a test");<br />            String s = (String) Array.get(arr, 5);<br />            System.out.println(s);<br />        } catch (Throwable e) {<br />            System.err.println(e);<br />        }<br />    }<br />}</p><p><br />例中创建了 10 个单位长度的 String 数组，为第 5 个位置的字符串赋了值，最后将这个字符串从数组中取得并打印了出来。<br /><br />下面这段代码提供了一个更复杂的例子：<br />import java.lang.reflect.*;<br />public class array2 {<br />    public static void main(String args[]) {<br />        int dims[] = new int[]{5, 10, 15};<br />        Object arr = Array.newInstance(Integer.TYPE, dims);<br />        Object arrobj = Array.get(arr, 3);<br />        Class cls = arrobj.getClass().getComponentType();<br />        System.out.println(cls);<br />        arrobj = Array.get(arrobj, 5);<br />        Array.setInt(arrobj, 10, 37);<br />        int arrcast[][][] = (int[][][]) arr;<br />        System.out.println(arrcast[3][5][10]);<br />    }<br />}<br />例中创建了一个 5 x 10 x 15 的整型数组，并为处于 [3][5][10] 的元素赋了值为 37。注意，多维数组实际上就是数组的数组，例如，第一个 Array.get 之后，arrobj 是一个 10 x 15 的数组。进而取得其中的一个元素，即长度为 15 的数组，并使用 Array.setInt 为它的第 10 个元素赋值。<br /><br />注意创建数组时的类型是动态的，在编译时并不知道其类型。</p></div>
<img src ="http://www.blogjava.net/nbtymm/aggbug/50439.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/nbtymm/" target="_blank">nbt</a> 2006-06-05 11:05 <a href="http://www.blogjava.net/nbtymm/archive/2006/06/05/50439.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>