﻿<?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>IT博客-sunnywang-随笔分类-language-java</title><link>http://www.cnitblog.com/sunnywang/category/6595.html</link><description>      smile forever.
        
 </description><language>zh-cn</language><lastBuildDate>Mon, 26 Sep 2011 10:42:32 GMT</lastBuildDate><pubDate>Mon, 26 Sep 2011 10:42:32 GMT</pubDate><ttl>60</ttl><item><title>如何生成.jar文件</title><link>http://www.cnitblog.com/sunnywang/archive/2009/04/22/56617.html</link><dc:creator>sunnywang   </dc:creator><author>sunnywang   </author><pubDate>Wed, 22 Apr 2009 07:06:00 GMT</pubDate><guid>http://www.cnitblog.com/sunnywang/archive/2009/04/22/56617.html</guid><wfw:comment>http://www.cnitblog.com/sunnywang/comments/56617.html</wfw:comment><comments>http://www.cnitblog.com/sunnywang/archive/2009/04/22/56617.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/sunnywang/comments/commentRss/56617.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/sunnywang/services/trackbacks/56617.html</trackback:ping><description><![CDATA[生成jar文件 <br>10:52自己找了很多网上的说明,发觉都说的不是很清楚,所以我总结了下,自己来写一篇关于如何生成jar的教程. <br>例子就以我以前写的那个哲学家就餐问题模拟(图形界面)为例,这些代码在我的空间上已经给出了. <br>编译完哲学家就餐问题模拟的代码后生成三个class文件,分别是Main.class, Philosopher.class, <br>Chopsticks.class. <br>接下来把这三个文件放在同一个文件夹下,启动cmd,进入到那个目录.这里假设生成后的jar文件名为Test.jar,先运行 <br><span style="COLOR: #ff0000">jar cvf Test.jar Main.class Philosopher.class Chopsticks.class</span> <br><br>运行命令后得到以下输出信息: <br>标明清单(manifest) <br>增加：Main.class(读入= 4833) (写出= 2541)(压缩了 47%) <br>增加：Philosopher.class(读入= 1857) (写出= 1071)(压缩了 42%) <br>增加：Chopsticks.class(读入= 946) (写出= 574)(压缩了 39%) <br>在当前目录下会生成一个Test.jar的文件.接下来,用解压缩工具(如WinRAR)解压Test.jar,在解压出来的文件中有一个名为 <br>META-INF 的文件来,打开它后会看到名为 MANIFEST.MF 的文件,用<span style="COLOR: #ff0000">记事本</span>打开它,在它的最后面加入一行,内容为: <br><span style="COLOR: #ff0000">Main-Class: Main</span> <br>(说明:在<span style="COLOR: #ff0000">Main-Class:和Main之间有个空格</span>,行的末尾不能有多余的空格,也不在最后面有多余的空行) <br><br>Main-Class: 后面的内容要按实际情况来写,因为我这里的可执行class文件名为Main.class,所以我才在后面写Main. <br>假如你的可执行class的名为HelloWorld.class,那么最后一行的内容该写为 Main-Class: HelloWorld <br><br>接下来,把修改好的MANIFEST.MF文件拷贝,放在以前的那个文件夹(就是放有Main.class, Philosopher.class, Chopsticks.class这三个文件的文件夹)下,那么现在该文件来下就有四个文件,分别为Main.class, Philosopher.class, Chopsticks.class 和MANIFEST.MF. <br>在cmd中进入到那个文件夹目录,运行以下命令,这里假设要生成的jar文件还叫做Test.jar,你也可用其它名字: <br><span style="COLOR: #ff0000">jar cvfm Test .jar MANIFEST.MF Main.class Philosopher.class Chopsticks.class <br></span>运行后得到以下输出信息: <br>标明清单(manifest) <br>增加：Main.class(读入= 4833) (写出= 2541)(压缩了 47%) <br>增加：Philosopher.class(读入= 1857) (写出= 1071)(压缩了 42%) <br>增加：Chopsticks.class(读入= 946) (写出= 574)(压缩了 39%) <br>可在文件夹下看到生成了Test.jar文件,双击它即可运行你的Java程序了.至此,所有步骤就完成了. 
<img src ="http://www.cnitblog.com/sunnywang/aggbug/56617.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/sunnywang/" target="_blank">sunnywang   </a> 2009-04-22 15:06 <a href="http://www.cnitblog.com/sunnywang/archive/2009/04/22/56617.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MyEclipse下开发web service </title><link>http://www.cnitblog.com/sunnywang/archive/2009/04/14/56360.html</link><dc:creator>sunnywang   </dc:creator><author>sunnywang   </author><pubDate>Tue, 14 Apr 2009 09:55:00 GMT</pubDate><guid>http://www.cnitblog.com/sunnywang/archive/2009/04/14/56360.html</guid><wfw:comment>http://www.cnitblog.com/sunnywang/comments/56360.html</wfw:comment><comments>http://www.cnitblog.com/sunnywang/archive/2009/04/14/56360.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/sunnywang/comments/commentRss/56360.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/sunnywang/services/trackbacks/56360.html</trackback:ping><description><![CDATA[<br><br><strong>开发环境<br></strong>Sun Java 5+ Eclipse 3.2 +MyEclipse 5.0.0. <br><br><strong>概述</strong> <br><br>本文介绍了使用MyEclipse Web Service来迅速开发和测试一个HelloWorld Web Service,其中包括: <br>1. 介绍了MyEclipse Web Services的基本概念 <br>2. 创建一个MyEclipse Web Services工程 <br>3. 创建一个简单的HelloWorld Web Service <br>4. 在Web容器中,如Tomcat 5中部署Web Service <br>5. 使用Web Services Explorer来测试部署的Web Services <br><br>XFire Java SOAP框架概述 <br>MyEclipse Web Services是建立在XFire Java SOAP框架和工具基础上的, <strong style="COLOR: red">XFire是一款开源的Java SOAP框架。</strong>它拥有一个轻量级的信息处理模块，通过STAX来与SOAP信息相结合。提供了一个工作在Web Services下的简单API，支持POJO和schema开发. XFire支持 Web Services standards,Spring 整合, 支持JBI , 支持 JAXB ,XMLBeans,Java 5 和JAX-WS.并支持HTTP, JMS, XMPP, In-memory传输协议. <br><br><strong>一. 创建Web Service工程</strong> <br><br>在MyEclipse 5.0中引入了一个新的工程类型即Web Service工程,该工程扩展了MyEclipse Web Project来支持额外的Web Service配置,开发和部署.本部分将使用Web Services Project wizard来创建和配置一个新的Web Service Projects Web Service Wizard将完成下列的动作: <br>创建MyEclipse J2EE Web Project <br>在工程中的web.xml文件中配置XFire Servlet <br>创建XFire services.xml配置文件 <br>在工程中的构建路径中添加MyEclipse-XFire类库 <br>添加一个指定的MyEclipse web project builder到.projects文件,以便部署services.xml文件到它合适的位置.如: <webroot>/WEB-INF/classes/META-INF/xfire/ <br><br>运行Web Service Project Wizard <br>该向导包括三个页面, Page-1搜集Web Project配置细节, Page-2搜集XFire配置细节, Page-3在新建的构建路径中配置XFire类库 <br>1. 执行Web Services Project Wizard. <br>1). 选择File&gt;New&gt;Other <br>2). 扩展MyEclipse种类按照J2EE工程的种类 <br>3). 选择Web Services Project然后点击Next,如图所示<br>
<p align=center><img height=429 alt="" src="http://images.e800.com.cn/articles/2009/3/26/12380532446540610281328.jpg" width=355></p>
<br>Figure-1: New Project Wizard Launcher <br>2. 添加Project Name,点击Next <br>
<p align=center><img height=402 alt="" src="http://images.e800.com.cn/articles/2009/3/26/12380532447260610281390.gif" width=450></p>
<br>Figure-2: Page-2, Collecting web configuration details <br>3.在向导的Page-2中添加XFire servlet和service.xml文件的配置信息,按照默认的值即可. <br>
<p align=center><img height=402 alt="" src="http://images.e800.com.cn/articles/2009/3/26/12380532448010610281387.gif" width=450></p>
<br>Figure-3: XFire servlet and services.xml configuration <br><br><br><br><br><br><br><br>4.在向导的Page-3中选择类库添加到工程的构建路径中,其中XFire Core Library是需要的,如果要在工程中开发一个客户端应用, XFire HTTP Client Libraries也是需要的.<br>
<p align=center><img height=402 alt="" src="http://images.e800.com.cn/articles/2009/3/26/12380532448790610281341.gif" width=450></p>
<br>Figure-4: Selecting XFire libraries to add to new web service project buildpath <br><br>5选择Finish完成Web Service工程的创建过程 <br>Figure-5,显示了新创建的HelloWorld Web Service工程的组织结构,Web Service 工程和一个标准的MyEclipse Web工程很相似. XFire Web Service配置元素如图红色区域显示: <br>
<p align=center><img height=345 alt="" src="http://images.e800.com.cn/articles/2009/3/26/12380532449440610281313.jpg" width=450></p>
<br>Figure-5: Web services artifacts of a new web service project <br><br><strong>二. 创建Web Service-Code-first Strategy <br></strong>在这部分将用MyEclipse Web Service Wizard并通过使用Code-first Strategy来创建一个HelloWorldService示例. <br><br>1. 执行MyEclipse Web Service Wizard,有两种方法来执行MyEclipse Web Service Wizard <br>方法1.从MyEclipse perspective toolbar中来执行向导 <br>在打开的Web Service Wizard上的workbench上来选择新Web Service按钮 <br>方法2.从workbench menubar执行向导 <br>1. 从workbench menubar选择: File&gt;New&gt;Other&gt;MyEclipse&gt;Web Service <br>
<p align=center><img height=598 alt="" src="http://images.e800.com.cn/articles/2009/3/26/12380532450080610281383.gif" width=394></p>
<br>Figure-6: Launching Web Service Wizard <br><br>2. 在Page-1选择HelloWorld 工程并选择Create web service from Java bean <br>3. 选择Next到Page-2 <br>
<p align=center><img height=418 alt="" src="http://images.e800.com.cn/articles/2009/3/26/12380532450690610281375.jpg" width=450></p>
<br>Figure-7: Page-1 of new web service wizard <br><br>
<table>
    <tbody>
        <tr>
            <td>4. 填写Web Service的名字HelloWorldService <br>5. 选择Java Source folder或者选择New按钮来新建一个source folder <br>6. 填写Java package或者通过选择Browse按钮来选择一个已经存在的package.也可以选择New按钮来新建一个Java package <br>注意:对Service接口和Service执行的类的默认值是基于所填入Web Service名字来产生的. <br>7. 选择Next来初始化Web Service的创建过程<br>
            <p align=center><img height=417 alt="" src="http://images.e800.com.cn/articles/2009/3/26/12380532451740610281370.jpg" width=450></p>
            <br>Figure-8: Page-2 of new web service wizard. <br>该向导产生了IHelloWorldService Java接口和HelloWorldServiceImpl Java类.并且在services.xml配置文件中创建了一个<service>实体(如图所示),注意到example(String message)方法在接口类中产生,当Web Service部署后作为一个测试操作. <br>
            <p align=center><img height=254 alt="" src="http://images.e800.com.cn/articles/2009/3/26/12380532452430610281316.jpg" width=450></p>
            <br>Figure-9: Newly created HelloWorld interface and implementation class <br><br><strong>三. 部署Web Service Project</strong> <br>Web Service可以部署在任何MyEclipse支持的J2EE应用服务器上,该部分将演示如何在Tomcat 5 Web容器上部署HelloWorld工程. <br><br>3.1部署HelloWorld Web Service Project <br><br>Figure-10显示了如何部署HelloWorld应用. <br>1. 从Server Manager中选择Deployer按钮(step-1) <br>2. 在Server Deployments对话框中选择Add to create a new deployment (step-2) <br>3. 在New Deployment对话框中选择HelloWorld工程并选择Exploded Archive选项 <br>4. 在New Deployment对话框选择Finish来将HelloWorld在Tomcat 5默认的位置中打包为WAR <br>5. 选择OK完成部署 <br>
            <p align=center><img height=350 alt="" src="http://images.e800.com.cn/articles/2009/3/26/12380532453260610281437.jpg" width=450></p>
            <br>Figure-10: Three-step deployment process <br>新HelloWorld WAR部署将出现在Server Manager视图中Tomcat 5节点下. <br>
            <p align=center><img height=115 alt="" src="http://images.e800.com.cn/articles/2009/3/26/12380532453930610281480.jpg" width=450></p>
            <br>Figure-11: Servers Manager View depicting deployed HelloWorld web service project </td>
        </tr>
    </tbody>
</table>
四. 启动Tomcat服务器 <br>五. 使用Web Service Explorer测试Web Service <br>MyEclipse提供了一个Web Service Explorer来测试Web Service. <br>1. 在MyEclipse perspective中选择toolbar button来执行Web Service Explorer <br>
<p align=center><img height=119 alt="" src="http://image.it168.com/cms/2006-10-28/image/Image00007(1).jpg" width=263></p>
<br>Figure-15: Web Services Explorer launch button on workbench toolbar <br><br>2. 选择WSDL模式(Figure-16) <br>3. 在活动面板中键入HelloWorldService WSDL文档的URLhttp://localhost:8080/HelloWorld/services/HelloWorldService?WSDL,Web Service Explorer将下载自动产生的WSDL文档,该WSDL文档由XFire framework,并产生一系列的操作能够调用service. <br>4. 在活动面板中选择example操作并在in0域中键入HelloWorld <br>5. 选择Go按钮来调用在HelloWorldService上的example操作,,结果出现在Status面板上 <br>
<p align=center><img height=356 alt="" src="http://images.e800.com.cn/articles/2009/3/26/12380532455590610281421.gif" width=450></p>
<br>Figure-16: Web Services Explorer testing HelloWorldService <br><br><strong>六. 创建Java Test客户端</strong> <br>XFire提供了一个动态的代理框架,能够读取WSDL文档和创建潜在的消息服务使Java类来执行在Web Service的行为.该部分将为HelloWorld Web Service写一个Java Web Service客户端 <br>6.1增加XFire类库配置 <br>为了使example client能够在HelloWorld工程中运行,需要增加XFire HTTP Client类库到工程的构建路径中. <br>1. 在Package Explore视图中右击HelloWorld工程选择Build Path&gt;Add Library <br>2. 选择MyEclipse Libraries <br>3. 选择XFire HTTP Client Libraries <br>
<p align=center><img height=484 alt="" src="http://images.e800.com.cn/articles/2009/3/26/12380532456480610281407.jpg" width=370></p>
<br>Figure-17: Choosing the XFire HTTP Client Libraries <br>4. 选择Finish <br>6.2创建HelloWorldClient类 <br>执行Java类向导来创建HelloWorldClient类 <br>
<p align=center><img height=500 alt="" src="http://images.e800.com.cn/articles/2009/3/26/12380532457240610281417.jpg" width=450></p>
<br>Figure-18: HelloWorldClient defined in New Java Class Wizard. <br>代码如下: <br>
<div style="SCROLLBAR-HIGHLIGHT-COLOR: buttonhighlight; OVERFLOW: auto; WIDTH: 756px; HEIGHT: 644px">
<pre style="BORDER-RIGHT: black 1px solid; PADDING-RIGHT: 4px; BORDER-TOP: black 1px solid; PADDING-LEFT: 4px; PADDING-BOTTOM: 4px; BORDER-LEFT: black 1px solid; PADDING-TOP: 4px; BORDER-BOTTOM: black 1px solid; BACKGROUND-COLOR: #ededed">
<div><!--
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
--><img id=Codehighlighter_39_608_Open_Image onclick="this.style.display=''none''; Codehighlighter_39_608_Open_Text.style.display=''none''; Codehighlighter_39_608_Closed_Image.style.display=''inline''; Codehighlighter_39_608_Closed_Text.style.display=''inline'';" alt="" src="http://images.e800.com.cn/articles/2009/3/26/1238053245797ExpandedBlockStart.gif" align=top><img id=Codehighlighter_39_608_Closed_Image style="DISPLAY: none" onclick="this.style.display=''none''; Codehighlighter_39_608_Closed_Text.style.display=''none''; Codehighlighter_39_608_Open_Image.style.display=''inline''; Codehighlighter_39_608_Open_Text.style.display=''inline'';" alt="" src="http://images.e800.com.cn/articles/2009/3/26/1238053245866ContractedBlock.gif" align=top><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=Codehighlighter_39_608_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=Codehighlighter_39_608_Open_Text><span style="COLOR: #000000">{
<img alt="" src="http://images.e800.com.cn/articles/2009/3/26/1238053245930InBlock.gif" align=top>    Service srvcModel </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">
<img alt="" src="http://images.e800.com.cn/articles/2009/3/26/1238053245930InBlock.gif" align=top>    ObjectServiceFactory().create(IHelloWorldService.</span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">);
<img alt="" src="http://images.e800.com.cn/articles/2009/3/26/1238053245930InBlock.gif" align=top>    XFireProxyFactory factory </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">
<img alt="" src="http://images.e800.com.cn/articles/2009/3/26/1238053245930InBlock.gif" align=top>       </span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> XFireProxyFactory(XFireFactory.newInstance().getXFire());
<img alt="" src="http://images.e800.com.cn/articles/2009/3/26/1238053245930InBlock.gif" align=top>    String helloWorldURL </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">
<img alt="" src="http://images.e800.com.cn/articles/2009/3/26/1238053245930InBlock.gif" align=top>       </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">http://localhost:8080/HelloWorld/services/HelloWorldService</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;
<img id=Codehighlighter_344_534_Open_Image onclick="this.style.display=''none''; Codehighlighter_344_534_Open_Text.style.display=''none''; Codehighlighter_344_534_Closed_Image.style.display=''inline''; Codehighlighter_344_534_Closed_Text.style.display=''inline'';" alt="" src="http://images.e800.com.cn/articles/2009/3/26/1238053246343ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter_344_534_Closed_Image style="DISPLAY: none" onclick="this.style.display=''none''; Codehighlighter_344_534_Closed_Text.style.display=''none''; Codehighlighter_344_534_Open_Image.style.display=''inline''; Codehighlighter_344_534_Open_Text.style.display=''inline'';" alt="" src="http://images.e800.com.cn/articles/2009/3/26/1238053246403ContractedSubBlock.gif" align=top>    </span><span style="COLOR: #0000ff">try</span><span style="COLOR: #000000"> </span><span id=Codehighlighter_344_534_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=Codehighlighter_344_534_Open_Text><span style="COLOR: #000000">{
<img alt="" src="http://images.e800.com.cn/articles/2009/3/26/1238053245930InBlock.gif" align=top>       IHelloWorldService srvc </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> (IHelloWorldService)factory.create(srvcModel, helloWorldURL);
<img alt="" src="http://images.e800.com.cn/articles/2009/3/26/1238053245930InBlock.gif" align=top>       String result </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> srvc.example(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">hello world</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);
<img alt="" src="http://images.e800.com.cn/articles/2009/3/26/1238053245930InBlock.gif" align=top>       System.</span><span style="COLOR: #0000ff">out</span><span style="COLOR: #000000">.print(result);
<img id=Codehighlighter_568_604_Open_Image onclick="this.style.display=''none''; Codehighlighter_568_604_Open_Text.style.display=''none''; Codehighlighter_568_604_Closed_Image.style.display=''inline''; Codehighlighter_568_604_Closed_Text.style.display=''inline'';" alt="" src="http://images.e800.com.cn/articles/2009/3/26/1238053246664ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter_568_604_Closed_Image style="DISPLAY: none" onclick="this.style.display=''none''; Codehighlighter_568_604_Closed_Text.style.display=''none''; Codehighlighter_568_604_Open_Image.style.display=''inline''; Codehighlighter_568_604_Open_Text.style.display=''inline'';" alt="" src="http://images.e800.com.cn/articles/2009/3/26/1238053246723ContractedSubBlock.gif" align=top>    }</span></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">catch</span><span style="COLOR: #000000"> (MalformedURLException e) </span><span id=Codehighlighter_568_604_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=Codehighlighter_568_604_Open_Text><span style="COLOR: #000000">{
<img alt="" src="http://images.e800.com.cn/articles/2009/3/26/1238053245930InBlock.gif" align=top>       e.printStackTrace();
<img alt="" src="http://images.e800.com.cn/articles/2009/3/26/1238053246856ExpandedSubBlockEnd.gif" align=top>    }</span></span><span style="COLOR: #000000">
<img alt="" src="http://images.e800.com.cn/articles/2009/3/26/1238053246924ExpandedBlockEnd.gif" align=top>  }</span></span></div>
</pre>
</div>
该段代码定义了创建一个XFire web service proxy的过程,该代理支持POJO IHelloWorldService接口 <br><br>右键点击Run As&gt;Java Application或者Debug As&gt;JavaApplication来运行或调试该程序 
<img src ="http://www.cnitblog.com/sunnywang/aggbug/56360.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/sunnywang/" target="_blank">sunnywang   </a> 2009-04-14 17:55 <a href="http://www.cnitblog.com/sunnywang/archive/2009/04/14/56360.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>tomcat web应用服务器，不是应用服务器， 也有别于web服务器</title><link>http://www.cnitblog.com/sunnywang/archive/2009/04/14/56350.html</link><dc:creator>sunnywang   </dc:creator><author>sunnywang   </author><pubDate>Tue, 14 Apr 2009 07:12:00 GMT</pubDate><guid>http://www.cnitblog.com/sunnywang/archive/2009/04/14/56350.html</guid><wfw:comment>http://www.cnitblog.com/sunnywang/comments/56350.html</wfw:comment><comments>http://www.cnitblog.com/sunnywang/archive/2009/04/14/56350.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/sunnywang/comments/commentRss/56350.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/sunnywang/services/trackbacks/56350.html</trackback:ping><description><![CDATA[Tomcat 服务器是一个免费的开放源代码的web 应用服务器。<br>&nbsp;&nbsp;&nbsp; &nbsp; 用纯java语言编写，所以处理速度远远比不上WEB服务器，功能也不如WEB服务器丰富。<br>&nbsp;&nbsp;&nbsp;&nbsp; Tomcat支持动态网页和静态网页， <br><br>&nbsp;Tomcat不支持大多数的J2EE API，所以不是应用服务器。<br><br><br>一：Tomcat与应用服务器<br>&nbsp; 一直被认为是Servlet/JSP&nbsp;API的执行器，也就所谓的servlet容器。<br><br>但是tomcat并不仅仅如此，它还提供了JNDI和JMX API的实现机制。尽管如此，<br><br>Tomcat仍然不能算是应用服务器，因为它不提供大多数J2EE API的支持。<br><br><br>
<p style="TEXT-INDENT: 2em">很有意思的是，目前许多的应用服务器通常把Tomcat作为它们Servlet和JSP API的容器。由于Tomcat允许开发者只需通过加入一行致谢，就可以把Tomcat嵌入到它们的应用中。遗憾的是，许多商业应用服务器并没有遵守此规则。
<p style="TEXT-INDENT: 2em">
<p style="TEXT-INDENT: 2em">对于开发者来说，如果是为了寻找利用Servlet、JSP、JNDI和JMX技术来生成<a class=channel_keylink href="http://java.chinaitlab.com/" target=_blank><font color=#0000ff size=3><u>Java</u></font></a> Web应用的话，选择Tomcat是一个优秀的解决方案；但是为了寻找支持其他的J2EE API，那么寻找一个应用服务器或者把Tomcat作为应用服务器的辅助，将是一个不错的解决方案；第三种方式是找到独立的J2EE API实现，然后把它们跟Tomcat结合起来使用。虽然整合会带来相关的问题，但是这种方式是最为有效的。。&nbsp;</p>
<p style="TEXT-INDENT: 2em"><br><strong>二、Tomcat与Web服务器</strong>&nbsp;<br><br>&nbsp; Tomcat是提供一个支持Servlet和JSP运行的容器。Servlet和JSP能根据实时需要，产生动态网页内容。而对于Web服务器来说，Apache仅仅支持静态网页，对于支持动态网页就会显得无能为力。<br>Tomcat则既能为动态网页服务，同时也能为静态网页提供支持。尽管它没有通常的Web服务器快、功能也不如web服务器丰富，但是Tomcat逐渐为支持静态内容不断扩充。大多数的Web服务器都是用底层语言编写，如C，利用了相应平台的特征，因此用纯Java编写的Tomcat执行速度不可能与它们相提并论。<br>&nbsp;&nbsp; 一般来说，大的站点都是将Tomcat与Apache的结合，Apache负责接收所有来自客户端的HTTP请求， 然后将Servlet和JSP的请求转发给Tomcat来处理。Tomcat完成处理后，将响应传回给Apache,最后Apache将响应返回给客户端。<br><br><br>&nbsp; 它与 web服务器、应用服务器 的区别是什么？<br></p>
<img src ="http://www.cnitblog.com/sunnywang/aggbug/56350.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/sunnywang/" target="_blank">sunnywang   </a> 2009-04-14 15:12 <a href="http://www.cnitblog.com/sunnywang/archive/2009/04/14/56350.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>双击就可以运行的．ｊａｒ文件——java中jar文件的编写和应用</title><link>http://www.cnitblog.com/sunnywang/archive/2009/04/14/56343.html</link><dc:creator>sunnywang   </dc:creator><author>sunnywang   </author><pubDate>Tue, 14 Apr 2009 06:22:00 GMT</pubDate><guid>http://www.cnitblog.com/sunnywang/archive/2009/04/14/56343.html</guid><wfw:comment>http://www.cnitblog.com/sunnywang/comments/56343.html</wfw:comment><comments>http://www.cnitblog.com/sunnywang/archive/2009/04/14/56343.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/sunnywang/comments/commentRss/56343.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/sunnywang/services/trackbacks/56343.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我想ＪＡＶＡ的爱好者，尤其是初学者大都有过这样的经历，就是喜欢ＪＡＶＡ编程语言（这个人的情况可能不一样），但是有时候总会觉得JAVA的优点便是她的&#8220;致命&#8221;的缺点。 <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 大家的信念依旧是&#8220;一次编译，到处运行&#8221;但是就是因为至一点ＪＡＶＡ失去了好多，我们也失去了好多。也许大家都知道，现在业界最推崇的还是微软的技术微软的产品。．ｎｅｔ／ｃ＃/．ｖｂ／ｖｂ．ｎｅｔ还是最流行的语言，最受欢迎的软件开发语言。因为这些语言都太好学太好用了。不像ＪＡＶＡ语言那么难懂难用。<br>&nbsp;&nbsp;&nbsp;&nbsp; 在软件开发提出高效的组件开发的时候，人们都很难想象用JAVA的ＥＪＢ就行开发，因为不成熟的技术和不健全的ＡＰＩ，让程序员很难入手。虽然有JBuilder这样优秀的开发工具，但是有时还是很难着手的（因为他们的体系太复杂，对于一般人来说会有一点的难度，当想开发应用程序的时候）。JAVA的体系够复杂了。因为&#8220;跨平台性&#8221;所以JAVA语言或者说JDK不支持产生.exe文件的相应的ＡＰＩ（<span style="COLOR: #339966">因为生成．ｅｘｅ文件总要和系统的硬件相关，这是JAVA语言所不允许的</span>）。不过你也没有必要失望，你可以使用JBuilder 或者IBM和软软支持的ＪＡＶＡ语言开发的工具进行程序开发与设计，或者采用ＪＡＶＡ的．ｊａｒ技术进行相关的操作，即生成&#8220;双击就可以运行的．ｊａｒ文件&#8221;，这不失一件很好的事情。（据我了解JBuilder是不能运行在256内存的机器上的，可见实在太耗内存）。<br>&nbsp;&nbsp; 好了，现在咱们言归正传。总之，.jar 文件还是很管用的。下让面咱们开始进入主题。<br>&nbsp;<br>&nbsp;一、制作jar文件&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #ff0000">&nbsp; 在制作.jar 文件之前你必须先编译好你的.java文件。</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 假设我们的文件目录是c:\java\myJava\hello\Hello.java <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 现在假设Hello.java的文件内容为：<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* * * Hello.java * */<br>&nbsp;&nbsp;&nbsp;&nbsp; public class Hello { <br>&nbsp;&nbsp; public static void mian(String[] args){<br>&nbsp;<br>System.out.println("Hello, World !"); <br>&nbsp;}<br>&nbsp;}&nbsp;<br>&nbsp;&nbsp; <br>&nbsp;&nbsp; <span style="COLOR: #ff0000">在进行.jar 制作的时候你必须把路径切换到Hello.java 所在的文件目录的外一层文件夹</span><span style="COLOR: #993300"><strong>(.jar文件要在Dos才能创建（windows平台）)，</strong></span>即myJava <br><br>&nbsp;&nbsp;&nbsp; 运行如下的命令可以把当前文件夹下的所有内容都包含在.jar 文件内。<br>&nbsp;&nbsp;&nbsp;&nbsp; c:\java\myJava&gt;jar cf Hello.jar . <br><br>&nbsp;&nbsp;&nbsp; 说明一下：命令行中 jar 是生成.jar文件的程序的调用接口。&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;cf 是一对可选项（options）<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 后面的Hello.jar 就是我们给文件取的名字了，<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; 最后一个点号（.）指示工具将当前目录下的所有文件都放进jar文件，jar工具进行地归操作，当文件夹中含有不止一个文件时。 <br><br><br>二、察看jar文件 <br><br>&nbsp;&nbsp;&nbsp;&nbsp; 其实，jar文件是采用WinZip 的格式进行文件压缩的，所以你可采用WinZip 解压缩文件的，还可以利用如下的命令行察看： <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c:\java\myJava&gt;jar tf Hello.jar<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 你会看到本地机子里的jvm 的版本以及其生产厂家信息还有 <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Main-Class: Hello.Hello <br>等信息。<br>&nbsp;<br><br>三、把文件移到你喜欢的目录 <br>&nbsp;&nbsp;&nbsp;&nbsp; 假设你想把jar 文件移到目录：d:\Java2\myFirst 下面，请运行如下的命令： <br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; d:\Java2\myFirst&gt; jar xf c:\java\Hello.jar&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 说明一下：jar 文件可以封闭，就意味着指定的包中的每一个类必须包含在同一个目录下。 <br><br>四：内容清单 manifest.fm&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; manifest.fm 文件是由键值对组成的。其中包含前面所说的jvm 的版本号 / 创建他的厂商等。 <br><br><br>五、增加清单的内容 <br><br><br>当若我们编辑了如下的一个addContents.txt 文件<br>&nbsp;Name: myJava\Hello\ Sealed: true <br><br>则可以通过如下命令把其加入到我们的清单文件中：<br>&nbsp;c:\java\myJava&gt;jar umf addContents.txt Hello.jar<br>&nbsp;<br>六、运行jar文件 <br><br>&nbsp;&nbsp;&nbsp;&nbsp; 你可以通过以下的方式来运行jar文件：<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c:\java\myJava&gt;java -classpath . -jar Hello.jar <br>&nbsp;&nbsp;&nbsp;&nbsp; 说明：需要命令的 -classpath . 部分是因为类的路径环境变量中没有（.）路径。<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 也可以 c:\java\myJava\Hello&gt;java -jar Hello.jar&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="COLOR: #993300">如果你的电脑是windows xp 版本 ,你还可以直接到你的c:\java\myJava\Hello 下双击Hello.jar 文件 但是你看不到运行的结果（图形界面程序可以这样运行），</span><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在windows 2000 上面,jar 文件被视作.zip 文件所以你一双击他就会把你的文件解压，而不是运行文件。所以你只有采用命令行的方式了。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;运行命令之后，你会看到在你的屏幕上显示的 Hello, World ! 字样。 <br><br><br><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>结束语：</strong> 到这里我们jar 文件的创建和运行等相关的介绍算结束了。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 你可以试着去验证一下。然后创建复杂的程序，比如具有界面的高级程序。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果你对jar 文件 很感兴趣 或者 想对她有更深刻的了解那么你可以在dos 下敲 jar 察看更多的帮助信息和许多options 的解释。<br>&nbsp;<br>jar 帮组文档内容：<br>&nbsp;<br>C:\&gt;jar 用法：<br>jar {ctxu}[vfm0Mi] [jar-文件] [manifest-文件] [-C 目录] 文件名 ...<br>&nbsp;<br>选项： -c 创建新的存档 <br>-t 列出存档内容的列表<br>&nbsp;-x 展开存档中的命名的（或所有的〕文件 <br>-u 更新已存在的存档<br>&nbsp;-v 生成详细输出到标准输出上<br>&nbsp;-f 指定存档文件名 <br>-m 包含来自标明文件的标明信息 <br>-0 只存储方式；未用ZIP压缩格式<br>&nbsp;-M 不产生所有项的清单（manifest〕文件 <br>-i 为指定的jar文件产生索引信息 <br>-C 改变到指定的目录，并且包含下列文件：如果一个文件名是一个目录，它将被递归处理。<br>清单（manifest〕文件名和存档文件名都需要被指定，按'm' 和 'f'标志指定的相同顺序。<br><br>示例1：将两个class文件存档到一个名为 'classes.jar' 的存档文件中：<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; jar cvf classes.jar Foo.class Bar.class <br><br>示例2：用一个存在的清单（manifest）文件 'mymanifest' 将 foo/ 目录下的所有文件存档到一个名为 'classes.jar' 的存档文件中：<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; jar cvfm classes.jar mymanifest -C foo/ . 
<img src ="http://www.cnitblog.com/sunnywang/aggbug/56343.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/sunnywang/" target="_blank">sunnywang   </a> 2009-04-14 14:22 <a href="http://www.cnitblog.com/sunnywang/archive/2009/04/14/56343.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>jdk 安装环境变量配置</title><link>http://www.cnitblog.com/sunnywang/archive/2008/06/12/45611.html</link><dc:creator>sunnywang   </dc:creator><author>sunnywang   </author><pubDate>Thu, 12 Jun 2008 05:55:00 GMT</pubDate><guid>http://www.cnitblog.com/sunnywang/archive/2008/06/12/45611.html</guid><wfw:comment>http://www.cnitblog.com/sunnywang/comments/45611.html</wfw:comment><comments>http://www.cnitblog.com/sunnywang/archive/2008/06/12/45611.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/sunnywang/comments/commentRss/45611.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/sunnywang/services/trackbacks/45611.html</trackback:ping><description><![CDATA[<p>运行eclipse需要java运行环境（简称JRE）且需要 JRE 1.4.2以上版本。 将其安装在c:\jdk目录下。</p>
<p>CLASSPATH变量设置为： .;c:\jdk\lib;</p>
<p>PATH变量设置为：c:\jdk\bin;(且要放到path变量值的最前面）（以确保当有多个版本时使用当前版本）</p>
<p>JAVA_HOME变量设置为：c:\jdk;</p>
<p>在&#8220;运行&#8221;中输入java -version 命令检查java的版本是不是当前安装的版本号， 如果是当前安装的版本号， 说明安装成功。</p>
<p>&nbsp;<br><br><br>=========================================================转载======================================<br>windows xp下配置JDK环境变量：<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.安装JDK，安装过程中可以自定义安装目录等信息，例如我们选择安装目录为D:\java\jdk1.5.0_08；</p>
<p>　 2.安装完成后，右击&#8220;我的电脑&#8221;，点击&#8220;属性&#8221;； </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3.选择&#8220;高级&#8221;选项卡，点击&#8220;环境变量&#8221;； </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4.在&#8220;系统变量&#8221;中，设置3项属性，JAVA_HOME,PATH,CLASSPATH(大小写无所谓),若已存在则点击&#8220;编辑&#8221;，不存在则点击&#8220;新建&#8221;； </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5.JAVA_HOME指明JDK安装路径，就是刚才安装时所选择的路径D:\java\jdk1.5.0_08，此路径下包括lib，bin，jre等文件夹（此变量最好设置，因为以后运行tomcat，eclipse等都需要依*此变量）；<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Path使得系统可以在任何路径下识别java命令，设为： </p>
<p>%JAVA_HOME%\bin;%JAVA_HOME%\jre\bin </p>
<p>　&nbsp;&nbsp; CLASSPATH为java加载类(class or lib)路径，只有类在classpath中，java命令才能识别，设为： </p>
<p>.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar (要加.表示当前路径) </p>
<p>　　%JAVA_HOME%就是引用前面指定的JAVA_HOME； </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 6.&#8220;开始&#8221;－&gt;;&#8220;运行&#8221;，键入&#8220;cmd&#8221;； </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 7.键入命令&#8220;java -version&#8221;，&#8220;java&#8221;，&#8220;javac&#8221;几个命令，出现画面，说明环境变量配置成功； </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8.好了，打完收工。下面开始你的第一个java程序吧。</p>
<p>下面讲讲java几个环境变量的含义和linux下的配置方法：</p>
<p>通常，我们需要设置三个环境变量：JAVA_HOME、PATH 和 CLASSPATH。</p>
<p>JAVA_HOME：该环境变量的值就是 Java 所在的目录，一些 Java 版的软件和一些 Java 的工具需要用到该变量，设置 PATH 和 CLASSPATH 的时候，也可以使用该变量以方便设置。</p>
<p>PATH：指定一个路径列表，用于搜索可执行文件的。执行一个可执行文件时，如果该文件不能在当前路径下找到，则依次寻找 PATH 中的每一个路径，直至找到。或者找完 PATH 中的路径也不能找到，则报错。Java 的编译命令 (javac)，执行命令 (java) 和一些工具命令 (javadoc, jdb 等) 都在其安装路径下的 bin 目录中。因此我们应该将该路径添加到 PATH 变量中。</p>
<p>CLASSPATH：也指定一个路径列表，是用于搜索 Java 编译或者运行时需要用到的类。在 CLASSPATH 列表中除了可以包含路径外，还可以包含 .jar 文件。Java 查找类时会把这个 .jar 文件当作一个目录来进行查找。通常，我们需要把 JDK 安装路径下的 jre\lib\rt.jar (Linux: jre/lib/rt.jar) 包含在 CLASSPATH 中。</p>
<p>PATH 和 CLASSPATH 都指定路径列表，列表中的各项 (即各个路径) 之间使用分隔符分隔。在 Windows 下，分隔符是分号 (;)，而在 Linux 下，分隔符是冒号 (:)。</p>
<p>下面分别说明三个环境变量在 Windows 和 Linux 下如何设置，不过在此之前，我们需要做个假设。假设 JDK 在 Windows 下的安装路径是 C:\jdk\，在 Linux 下的安装路径是 /usr/local/jdk/。那么，安装后的 JDK 至少会包括如下内容：</p>
<p>C:\jdk (/usr/local/jdk)<br>|-- bin<br>|-- demo<br>|-- include<br>|-- jre<br>| |-- bin<br>| `-- lib<br>`-- lib</p>
<p>***** 在 Windows 下设置</p>
<p>Windows 下使用 set 命令设置环境变量，为了使每一次启动计算机都设置这些环境变量，应该在系统盘根目录下的 autoexec.bat 文件中进行设置，如：</p>
<p>set JAVA_HOME=C:\jdk<br>set PATH=%JAVA_HOME%\bin;C:\Windows;C:\Windows\Command<br>set CLASSPATH=%JAVA_HOME%\jre\lib\rt.jar;.</p>
<p>有些版本的 Windows 不能用 %变量名% 来替换环境变量的内容，那么就只好直接写 C:\jdk 而不是 %JAVA_HOME% 了。另外，C:\Windows 和 C:\Windows\Command 是 Windows 会自动加入路径的，所以可以从设置中去掉。如果在 autoexec.bat 中已经设置了 PATH，那只需要将 %JAVA_HOME%\bin 加到原来设置 PATH 的那条语句中就行了。</p>
<p>CLASSPATH 也可以根据需要设置或者加入其它的路径，比如你想把自己写的一些类放在 C:\java 中，就可以把 C:\java 也添加到 CLASSPATH 中去，set CLASSPATH=%JAVA_HOME%\jre\lib\rt.jar;C:\java;.。</p>
<p>注意，在 CLASSPATH 中包含了一个&#8220;当前目录 (.)&#8221;。包含了该目录后，就可以到任意目录下去执行需要用到该目录下某个类的 Java 程序，即使该路径并未包含在 CLASSPATH 中也可以。原因很简单：虽然没有明确的把该路径包含在 CLASSPATH 中，但 CLASSPATH 中的 &#8220;.&#8221; 在此时就代表了该路径，如：</p>
<p>假设在 C:\java 目录下有可运行的类 HelloJava.class，那么</p>
<p>C:\&gt; set CLASSPATH=C:\jdk\jre\lib\rt.jar;. // 设置 CLASSPATH 环境变量，注意最后有一个 &#8220;.&#8221;<br>C:\&gt; cd java // 转到 C:\java 目录<br>C:\java&gt; java HelloJava // 运行 HelloJava<br>Hello, Java. // 运行结果<br>C:\java&gt; _</p>
<p>**** 在 Linux 下设置</p>
<p>Linux 下使用&#8220;变量名=变量值&#8221;设置变量，并使用 export 命令将其导出为环境变量。为了使每一次登录都自动设置好这些变量，你需要在 ~/.bash_profile 里或者 ~./bashrc 里进行设置，如</p>
<p>export JAVA_HOME=/usr/local/jdk<br>export PATH=$JAVA_HOME/bin:$PATH<br>export CLASSPATH=$JAVA_HOME/jre/lib/rt.jar:.</p>
<p>设置 PATH 时用的 $JAVA_HOME 是指替换变量 JAVA_HOME 的值到 $JAVA_HOME 所在位置。如上句实际就是 export PATH=/usr/local/jdk/bin:$PATH。这句中 $PATH 也是同样的作用，不过这里的 PATH 是指以前设置的 PATH 变量的值，而非本次设置 PATH 变量的值。</p>
<p>注意，在 CLASSPATH 中包含了一个&#8220;当前目录 (.)&#8221;。包含了该目录后，就可以到任意目录下去执行需要用到该目录下某个类的 Java 程序，即使该路径并未包含在 CLASSPATH 中也可以。原因很简单：虽然没有明确的把该路径包含在 CLASSPATH 中，但 CLASSPATH 中的 &#8220;.&#8221; 在此时就代表了该路径，例如</p>
<p>假设在 /home/fancy/java 目录下有可运行的类 HelloJava.class，那么</p>
<p>[fancy@matrix fancy]$ export CLASSPATH=/usr/local/jdk/jre/lib/rt.jar:. // 设置 CLASSPATH，注意最后的&#8220;.&#8221;<br>[fancy@matrix fancy]$ cd ~/java // 转到 /home/fancy/java<br>[fancy@matrix java]$ pwd // 显示当前目录<br>/home/fancy/java // 当前目录是 /home/fancy/java<br>[fancy@matrix java]$ java HelloJava // 运行 HelloJava<br>Hello, Java // 运行结果<br>[fancy@matrix java]$ _</p>
<p>析</p>
<p>***** 实例分析</p>
<p>只是操作系统不同，略有差别。</p>
<p>两个例子都提到一个&#8220;可运行的类&#8221;，它是指包含了 public static void main(String[] args) 方法的类，这将在下一章 HelloJava 一节中详述。例中的 CLASSPATH 均未包含 HelloJava.class 所在的目录(C:\java, /home/fancy/java)，但是均包含了当前目录 (.)。因此转到包含 HelloJava.class 的目录下去执行 java HelloJava，在 Java 寻找到 CLASSPATH 中的&#8220;. (当前目录，C:\java, /home/fancy/java)&#8221;时，找到了 HelloJava.class，运行成功。</p>
<p><br>本文来自CSDN博客，转载请标明出处：<a href="http://blog.csdn.net/huanghm88/archive/2009/03/07/3965218.aspx">http://blog.csdn.net/huanghm88/archive/2009/03/07/3965218.aspx</a></p>
<img src ="http://www.cnitblog.com/sunnywang/aggbug/45611.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/sunnywang/" target="_blank">sunnywang   </a> 2008-06-12 13:55 <a href="http://www.cnitblog.com/sunnywang/archive/2008/06/12/45611.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java 数据类型转换 string 到number，number到string</title><link>http://www.cnitblog.com/sunnywang/archive/2008/01/10/38701.html</link><dc:creator>sunnywang   </dc:creator><author>sunnywang   </author><pubDate>Thu, 10 Jan 2008 06:54:00 GMT</pubDate><guid>http://www.cnitblog.com/sunnywang/archive/2008/01/10/38701.html</guid><wfw:comment>http://www.cnitblog.com/sunnywang/comments/38701.html</wfw:comment><comments>http://www.cnitblog.com/sunnywang/archive/2008/01/10/38701.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/sunnywang/comments/commentRss/38701.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/sunnywang/services/trackbacks/38701.html</trackback:ping><description><![CDATA[<div class=paper01 id=vad>
<div class=aditem_paper01><iframe name=google_ads_frame marginWidth=0 marginHeight=0 src="http://pagead2.googlesyndication.com/pagead/ads?client=ca-pub-5361965574000615&amp;dt=1199947912185&amp;lmt=1199947912&amp;alternate_ad_url=http%3A%2F%2Fblog.sjzj.com.cn&amp;prev_fmts=468x60_as%2C468x15_0ads_al&amp;format=180x150_as&amp;output=html&amp;correlator=1199947912185&amp;url=http%3A%2F%2Fblog.sjzj.com.cn%2Farticle.asp%3Fid%3D407&amp;color_bg=F9F8F6&amp;color_text=000000&amp;color_link=FF0000&amp;color_url=FF0000&amp;color_border=F9F8F6&amp;ad_type=text_image&amp;ref=http%3A%2F%2Fwww.google.cn%2Fsearch%3Fhl%3Dzh-CN%26q%3Djava%2B%25E4%25B8%25ADstring%2B%25E5%258F%25AF%25E4%25BB%25A5%25E8%2587%25AA%25E5%258A%25A8%25E8%25BD%25AC%25E6%258D%25A2%25E4%25B8%25BAnumber%25E7%25B1%25BB%25E5%259E%258B%25E5%2590%2597%26meta%3D%26aq%3Df&amp;cc=100&amp;ga_vid=512141029.1199947912&amp;ga_sid=1199947912&amp;ga_hid=1310502956&amp;flash=9&amp;u_h=800&amp;u_w=1280&amp;u_ah=770&amp;u_aw=1280&amp;u_cd=32&amp;u_tz=480&amp;u_java=true" frameBorder=0 width=180 scrolling=no height=150 allowTransparency></iframe></div>
</div>
首先我们可以看C中间的强制类型转换，只能存在整数可表示类型和浮点数类型之间，比如(int)2.45，这是可以的，但是他们和字符串之间都没有强制转换的可能，因为字符串实际是一个指针。因此不可能出现(char&nbsp;*)2.45就可以获得"2.45"这个字符串的情况，反之也不能。<br>而在C++中，我们可以创建一个类，并且重载强制转换操作，来完成这种情况，那么就必须要求有相应的对象，但是对于基本类型，这也是不可以的。<br>然后，因为JavaScript在对象模型上主要参考了Java，我们可以再参考一下Java的类型转换：<br>在Java中，基本类型之间的强制转换也不是这样的，比如，整数要转换成字符串，必须使用Integer.toString()静态方法或者String.valueOf()静态方法，把字符串转换为整数，必须使用Integer.valueOf()。<br>可见，不能把JavaScript中的类型转换看作为&#8220;强制类型转换&#8221;。<br>在JavaScript中，Double类型和Int类型都是看作为Number对象，因此无论是typeof&nbsp;1还是typeof&nbsp;1.0，都是返回number。这样我们可以不用去管是Int还是Double类型，让JavaScript解释引擎内部去处理。<br><br><br>1.如果要把Number转换成String，可以使用Number的toString()方法，（象(1).toString()括号必须或者&nbsp;1&nbsp;.toString()空格必须，否则会编译出错，如果是变量则无需），或者调用String()函数，这两种方法都会自动调用解释引擎内部的&nbsp;NumberToString()，或者根据进制调用其它函数，基本类似。<br>2.如果要把String转换成Number，可以使用Number()函数，他会自动判断String中是整数还是浮点数，然后内部使用相应的数据类型，另外可以使用全局函数parseInt()和parseFloat()，他们根据你的要求进行转换。同样的，他们在解释引擎内部机制上是使用了&nbsp;StringToNumber，StringToInt等等内部的函数。<br>3.而如果是Double转换成Int，必须使用Math.floor()函数（截尾取整）或者Math.round()（四舍五入）<br>4.Int转换成Double，无须考虑任何问题，直接把Int当成Double进行运算<br><br>注：Number、String函数是特殊的函数，在JS引擎中，他会自动判断是作为构造函数调用还是普通调用，所以既可以使用new关键字，也可以作为函数直接调用。<br>关于JS的参考手册，微软有一个CHM十分不错，指南、API参考都有，是Windows脚本技术，中文版，我在MSDN上下载的。而关于JS解释引擎的，我参考的是Netscape的Spidermonkey，现在由Mozilla组织维护。<br><br>&lt;scriptlanguage="javascript"&gt;<br>var&nbsp;str='100';<br>var&nbsp;num=Number(100);<br>alert(typeof(num)+':'+num);<br>var&nbsp;obj=Object(str);<br>alert(typeof(obj)+':'+obj);<br>var&nbsp;bool=Boolean(str);<br>alert(typeof(bool)+':'+bool);<br><br>var&nbsp;num=100;<br>var&nbsp;str=String(num);<br>alert(typeof(str)+':'+str);<br>var&nbsp;bool=Boolean(num);<br>alert(typeof(bool)+':'+bool);<br>var&nbsp;obj=Object(num);<br>alert(typeof(obj)+':'+obj);<br><br>var&nbsp;bool=true;<br>var&nbsp;str=String(bool);<br>alert(typeof(str)+':'+str);<br>var&nbsp;num=Number(bool);<br>alert(typeof(num)+':'+num);<br>var&nbsp;obj=Object(bool);<br>alert(typeof(obj)+':'+obj);<br><br>var&nbsp;obj={};<br>var&nbsp;str=String(obj);<br>alert(typeof(str)+':'+str);<br>var&nbsp;num=Number(obj);<br>alert(typeof(num)+':'+num);<br>var&nbsp;bool=Boolean(obj);<br>alert(typeof(bool)+':'+bool);<br>&lt;/script&gt;&nbsp;<br><br><br><br>
<img src ="http://www.cnitblog.com/sunnywang/aggbug/38701.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/sunnywang/" target="_blank">sunnywang   </a> 2008-01-10 14:54 <a href="http://www.cnitblog.com/sunnywang/archive/2008/01/10/38701.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JAVA中读写配置文件</title><link>http://www.cnitblog.com/sunnywang/archive/2008/01/10/38700.html</link><dc:creator>sunnywang   </dc:creator><author>sunnywang   </author><pubDate>Thu, 10 Jan 2008 06:49:00 GMT</pubDate><guid>http://www.cnitblog.com/sunnywang/archive/2008/01/10/38700.html</guid><wfw:comment>http://www.cnitblog.com/sunnywang/comments/38700.html</wfw:comment><comments>http://www.cnitblog.com/sunnywang/archive/2008/01/10/38700.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/sunnywang/comments/commentRss/38700.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/sunnywang/services/trackbacks/38700.html</trackback:ping><description><![CDATA[<div class=blog_title>
<h5>2007-12-22</h5>
<h3><a href="http://herhun.javaeye.com/blog/150107"><span class=hilite1>java</span>中读写属性文件</a></h3>
</div>
<div class=blog_content>下面的文章来自CSDN hyde82的专栏,因为很实用,所以就摘下来放在此处,具体网址忘记啦. <br><br>无论是有图形化的选项配置对话框，或者是系统提供的注册表，文本形式的本地配置文件依然是最牢靠、应用最广泛的配置信息保存形式。配置信息的一般模式就是一个配置项对应一个值，前者一般是个字符串，后者可能是数字或者字符串或者别的什么。在传统win32编程中有系统提供的api供我们解读.ini文件，后来也有操作注册表的封装好的api，在.net中更是有解读XML形式.config文件的现成方法。在<span class=hilite1>Java</span>中，对配置文件的使用进行封装也是十分有意义的。 <br><br>　　封装应该达到这样的效果：应用只管从配置信息进行按名读取值、设置值、保存等操作，而不需要关心具体以什么文件格式保存、如何解析。文件格式(纯文本?XML?数据库?)、IO方式(本地文件?远程文件?控制台流?)在封装类内部的变更，都不会影响应用对配置信息的感知。 <br><br>　　从键名-值的对应关系以及文件的存取，我们最容易想到的就是<span class=hilite1>java</span>.util.Properties对象，他是HashTable的子类，保存的就是很多组键名-值的对应二原组，并提供快速的查询和直接的从文件读取、保存为文件的方法。具体请参考相关文档，我们直接看程序。 <br><br>　　首先自定义一个异常： <br><br>//ConfigurationException.<span class=hilite1>java</span> <br>package configuration; <br><br>public class ConfigurationException extends Exception{ <br>public ConfigurationException(){} <br>public ConfigurationException(String msg){ <br>super(msg); <br>} <br>} <br><br>　　然后是我们的封装类： <br><br>//Configuration.<span class=hilite1>java</span> <br>package configuration; <br>import <span class=hilite1>java</span>.io.*; <br>import <span class=hilite1>java</span>.util.*; <br>import configuration.*; <br><br>public class Configuration { <br>private Properties config=new Properties();//记录配置项 <br>private String fn=null;//记录配置文件名 <br><br>//此构造方法用于新建配置文件 <br>public Configuration(){} <br><br>//从指定文件名读入配置信息 <br>public Configuration(String fileName) <br>throws ConfigurationException { <br>try { <br>FileInputStream fin = new FileInputStream(fileName); <br>config.load(fin); //载入文件 <br>fin.close(); <br>} <br>catch (IOException ex) { <br>throw new ConfigurationException <br>("无法读取指定的配置文件:"+fileName); <br>} <br>fn=fileName; <br>} <br><br>//指定配置项名称，返回配置值 <br>public String getValue(String itemName){ <br>return config.getProperty(itemName); <br>} <br><br>//指定配置项名称和默认值，返回配置值 <br>public String getValue(String itemName, <br>String defaultValue){ <br>return config.getProperty(itemName,defaultValue); <br>} <br><br>//设置配置项名称及其值 <br>public void setValue(String itemName,String value){ <br>config.setProperty(itemName,value); <br>return; <br>} <br><br>//保存配置文件，指定文件名和抬头描述 <br>public void saveFile(String fileName,String description) <br>throws ConfigurationException { <br>try { <br>FileOutputStream fout <br>= new FileOutputStream(fileName); <br>config.store(fout, description);//保存文件 <br>fout.close(); <br>} <br>catch (IOExeption ex) { <br>throw new ConfigurationException <br>("无法保存指定的配置文件:"+fileName); <br>} <br>} <br><br>//保存配置文件，指定文件名 <br>public void saveFile(String fileName) <br>throws ConfigurationException { <br>saveFile(fileName,""); <br>} <br><br>//保存配置文件，采用原文件名 <br>public void saveFile() throws ConfigurationException { <br>if(fn.length()==0) <br>throw new ConfigurationException <br>("需指定保存的配置文件名"); <br>saveFile(fn); <br>} <br>} <br><br><br><br>　　从这个封装类我们可以看到，实例化对象的时候我们可以指定一个文件名使得从中读取配置信息，通过getValue方法取得属性值，setValue方法设置属性值，saveFile方法保存文件。然后我们具体来看看如何使用： <br><br>//SetConfig.<span class=hilite1>java</span> <br>import configuration.*;//包含这个包方能使用配置类 <br>import <span class=hilite1>java</span>.io.*; <br><br>public class SetConfig { <br>public static void main(String[] args) { <br>try { <br>Configuration config = new Configuration(); <br>//设置一些属性值 <br>config.setValue("Max_Users_Count", "50"); <br>config.setValue("Max_OpenedFile_Count", "20"); <br>//保存文件 <br>config.saveFile("system.conf", <br>"Sytem Global Configuration"); <br>} <br>catch (ConfigurationException ex) { <br>//捕获我们自定义的异常 <br>ex.printStackTrace(); <br>} <br>} <br>} <br><br><br>　　这段程序新建了一个配置，设置了两个配置项：Max_Users_Count为50；Max_OpenedFile_Count为20。最后将这个配置保存为system.conf文件，并加入抬头注释"Sytem Global Configuration"。执行之后，在程序所在目录下产生了一个system.conf文件，我们用纯文本编辑器打开看看内容到底是什么： <br><br>#Sytem Global Configuration <br>#Mon Aug 02 23:43:39 PDT 2004 <br>Max_OpenedFile_Count=20 <br>Max_Users_Count=50 <br><br>　　可以看到，第一行写入了我们加入的抬头注释，第二行自动产生了一个时间，后面两行用&lt;配置项名称&gt;=&lt;配置值&gt;的形式记录了配置信息。下面我们来读取这个配置文件： <br><br>//ReadConfig.<span class=hilite1>java</span> <br>import configuration.*; <br><br>public class ReadConfig { <br>public static void main(String[] args) { <br>try { <br>//读取指定文件 <br>Configuration config <br>= new Configuration("system.conf"); <br>//获取特定值 <br>System.out.println <br>(config.getValue("Max_Users_Count") + <br>" users can be actived at the same time"); <br>//指定默认值 <br>System.out.println <br>(config.getValue("Max_OpenedFile_Count", "10") + <br>" files can be opened at the same time"); <br>} <br>catch (ConfigurationException ex) { <br>ex.printStackTrace(); <br>} <br>} <br>} <br><br>　　系统输出了 <br><br>50 users can be actived at the same time <br>20 files can be opened at the same time <br><br>这样的信息。表明我们成功读取了配置信息。 <br><br>　　这样我们的封装类可以胜任普通的配置信息操作工作了。而且对于大多数的情况，这个类也足够用了。这里的代码都是可复用的，大家可以直接拷贝到自己的工程中去。最后说明：这些属性值当然可以自己在文件里面改动，而且这也是配置文件最常见的使用方式；#号开头的都表示注释，可以任意添加和删除。 <br><br>　　任务完成了，但是还并不完美。采用Properties最大的方便就是有现成的查询、设置、文件存取方法，但是这样的&lt;配置项名称&gt;=&lt;配置值&gt;格式只是方便了在<span class=hilite1>Java</span>中的使用，考虑到系统将来的扩展性或者开发平台的迁移，都是欠妥的。下一次我们来试试利用DOM封装XML格式的配置文件。 <br><br><br>下面是根据我的项目,对上面的类稍作了一些修改,大部分复制上面的代码,很多注解都还没改 <br><br>package gov.szghrs.base.utils; <br><br>import gov.szghrs.base.exception.ConfigurationException; <br><br>import <span class=hilite1>java</span>.io.FileInputStream; <br>import <span class=hilite1>java</span>.io.FileOutputStream; <br>import <span class=hilite1>java</span>.io.IOException; <br>import <span class=hilite1>java</span>.net.URL; <br>import <span class=hilite1>java</span>.util.Properties; <br><br>public class Configuration { <br>private Properties config = new Properties();// 记录配置项 <br>private String fn = null;// 记录配置文件名 <br><br><br>// 从指定文件名读入配置信息 <br>public Configuration() throws ConfigurationException { <br>try { <br>// FileInputStream fin = new FileInputStream(fileName); <br>// is = classLoader.getResourceAsStream("common-config.properties"); <br>ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); <br><br>// InputStream fin = null; <br>// fin = classLoader.getResourceAsStream("system.conf"); <br>URL URL = classLoader.getResource("system.conf"); <br>fn = URL.getFile(); <br>// FileOutputStream fout = new FileOutputStream(URL.getFile()); <br>// config.load(fin); // 载入文件 <br>// fin.close(); <br>} catch (Exception ex) { <br>throw new ConfigurationException("无法读取指定的配置文件:" + fn); <br>} <br>} <br><br>public void loadConfiguration() throws IOException, ConfigurationException{ <br>try { <br>FileInputStream fin = new FileInputStream(fn); <br>config.load(fin); <br>} catch (Exception e) { <br>throw new ConfigurationException("无法读取指定的配置文件:" + fn); <br>} <br>} <br>// 指定配置项名称，返回配置值 <br>public String getValue(String itemName)throws IOException, ConfigurationException{ <br>loadConfiguration(); <br>return config.getProperty(itemName); <br>} <br><br>// 指定配置项名称和默认值，返回配置值 <br>public String getValue(String itemName, String defaultValue)throws IOException, ConfigurationException { <br>loadConfiguration(); <br>return config.getProperty(itemName, defaultValue); <br>} <br><br>// 设置配置项名称及其值 <br>public void setValue(String itemName, String value) { <br>config.setProperty(itemName, value); <br>return; <br>} <br><br>// 保存配置文件，指定文件名和抬头描述 <br>public void saveFile(String description) throws ConfigurationException { <br>try { <br>FileOutputStream fout = new FileOutputStream(fn); <br>config.store(fout, description);// 保存文件 <br>fout.close(); <br>} catch (IOException ex) { <br>throw new ConfigurationException("无法保存指定的配置文件:" + fn); <br>} <br>} <br><br>// 保存配置文件，指定文件名 <br>public void saveFile() throws ConfigurationException { <br>if(fn.length()==0) throw new ConfigurationException("无法保存指定的配置文件:" + fn);; <br>saveFile(""); <br>} <br><br>} </div>
<img src ="http://www.cnitblog.com/sunnywang/aggbug/38700.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/sunnywang/" target="_blank">sunnywang   </a> 2008-01-10 14:49 <a href="http://www.cnitblog.com/sunnywang/archive/2008/01/10/38700.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java 编程中的一些注意规则</title><link>http://www.cnitblog.com/sunnywang/archive/2008/01/08/38599.html</link><dc:creator>sunnywang   </dc:creator><author>sunnywang   </author><pubDate>Tue, 08 Jan 2008 03:59:00 GMT</pubDate><guid>http://www.cnitblog.com/sunnywang/archive/2008/01/08/38599.html</guid><wfw:comment>http://www.cnitblog.com/sunnywang/comments/38599.html</wfw:comment><comments>http://www.cnitblog.com/sunnywang/archive/2008/01/08/38599.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/sunnywang/comments/commentRss/38599.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/sunnywang/services/trackbacks/38599.html</trackback:ping><description><![CDATA[<div class=postTitle><a href="http://blog.donews.com/imhow/articles/16048.aspx"><u><font color=#800080>JAVA规则</font></u></a></div>
<div class=postText>
<p><font color=#000080>基本篇</font></p>
<p>作者：flyingwcy 转载自：Java研究组织<br><br>本文介绍的JAVA规则的说明分为5个级别，级别1是最基本也是最重要的级别，在今后将陆续写出其他的规则。遵守了这些规则可以提高程序的效率、使代码有更好的可读性等。 <br><br>（1） 避免使用NEW关键字来创建String对象。 <br>把一个String常量copy到String 对象中通常是多余、浪费时间的 <br>Public class test{ <br>Public void method(){ <br>System.out.print (str); <br>} <br>private String str = new String ("1"); //这里新建对象是完全没有必要的 <br>private String str2=&#8221;2&#8221; //正确的应该如此 <br>} <br>参考：Joshua Bloch: "Effective Java - Programming Language Guide" <br><br><br>（2） 避免使用不必要的嵌套。 <br>过多的嵌套会使你的代码复杂化，减弱可读性。 <br>Public class test { <br>String add (){ <br>Int c=(a=a+b)+b; //过于复杂 <br>Return c <br>} <br><br>} <br><br>参考：http://java.sun.com/docs/codeconv/html/CodeConventions.doc9.html#177 <br><br>（3） 避免在同一行声明不同类型的多个变量 <br>这样可以使程序更加清晰，避免混乱 <br>private int index, index1[]; <br>正确的应该如此： <br>private int index; <br>private int index1[]; <br><br><br>参考：http://java.sun.com/docs/codeconv/html/CodeConventions.doc5.html#2992 <br><br>(4) 在每一行里写一条语句 <br>这条规则不包括for语句：比如：&#180;for (int I = 0; I &lt; 10; i++) x--;&#8217;可以增加代码的可读性。 <br>public class OSPL { <br>int method (int a, int b) { <br>int I = a + b; return I; // 可读性不强 <br>} <br>正确的： <br>public class OSPLFixed { <br>int method (int a, int b) { <br>int I = a + b; <br>return I; <br>} <br>} <br>参考：Section 7.1 of<a href="http://java.sun.com/docs/codeconv/html/CodeConventions.doc6.html" target=_blank><font color=#000000><u> http://java.sun.com/docs/codeconv/html/CodeConventions.doc6.html</u></font></a>#431 <br><br><br>（5）经常从finalize ()中调用super.finalize () <br>这里的finalize ()是java在进行垃圾收集的时候调用的，和finally不一样。如果你的父类没有定义finally（）的话，你也应该调用。这里有两个原因：（1）在不改变代码的情况下能够将父类的finally方法加到你的类中。 （2）以后你会养成习惯调用父类的finally方法，即使父类没有定义finally方法的时候。 <br>正确的方法应该如此： <br>public class parentFinalize { <br>protected void finalize () throws Throwable { <br>super.finalize(); // FIXED <br>} <br><br>参考："The Java Programming Language" by Ken Arnold and James Gosling, page 49. <br><br>（6） 不要在finalize ()中注销listeners <br>不要再finalize ()方法中中注销listeners，finalize ()只有再没有对象引用的时候调用，如果listeners从finalize()方法中去除了，被finalize的对象将不会在垃圾收集中去除。 <br>public void finalize () throws Throwable { <br>bButton.removeActionListener (act); <br>} <br><br>(7) 不要显式的调用finalize ()方法 <br>虽然显式的调用这个方法可以使你确保你的调用，但是当这个方法收集了以后垃圾收集会再收集一次。 <br><br>public class T7 { public void finalize() throws Throwable { close_resources (); super.finalize (); } public void close_resources() {}}class Test { void cleanup () throws Throwable { t71.finalize(); // 调用 t71 = null; } private t71 = new T7 ();} <br><br>对于这样的调用我们应该自己创建一个释放的方法，做最初finalize ()所作的事情，当你每次想显式的调用finalize ()的时候实际上调用了释放方法。然后再使用一个判断字段来确保这个方法只执行一次，以后再调用就没关系了。 <br><br>public class T7 { public synchronized void release () throws Throwable{ if (!_released) { close_resources (); // do what the old &#180;finalize ()&#180; did _released = true; } } public void finalize () throws Throwable { release (); super.finalize (); } public void close_resources() {} private boolean _released = false;}class TestFixed { void closeTest () throws Throwable { t71 .release (); // FIXED t71 = null; } private T7 t71 = new T7 ();} <br><br><br>参考：Nigel Warren, Philip Bishop: "Java in Practice - Design Styles and Idioms <br>for Effective Java". Addison-Wesley, 1999. pp.110-111 <br><br><br>(8)不要使用不推荐的API <br>尽量使用JDK1.3推荐的API。在类和方法或者java组件里有很多方法是陈旧的或者是可以选择的。有一些方法SUN用了"deprecated&#8220;标记。最好不要使用例如： <br>private List t_list = new List (); <br>t_list.addItem (str); <br>如果查一下javadoc的话，会发现建议用add()来代替addItem()。 <br>参考：http://java.sun.com/j2se/1.3/docs/api/index.html <br><br>（9）为所有序列化的类创建一个&#180;serialVersionUID&#180; <br>可以避免从你各种不同的类破坏序列的兼容性。如果你不特别制订一个UID的话，那么系统为自动产生一个UID（根据类的内容）。如果UID在你新版本的类中改变了，即使那个被序列化的类没改变，你也不能反序列化老的版本了。 <br><br>public class DUID implements java.io.Serializable { public void method () {}} <br>在里面加一个UID，当这个类的序列化形式改变的时候，你也改变这个UID就可以了。 <br><br>public class DUIDFixed implements java.io.Serializable { public void method () {} private static final long serialVersionUID = 1; } <br><br><br>参考：Joshua Bloch: "Effective Java - Programming Language Guide" <br>Addison Wesley, 2001, pp. 223 <br><br>（10）对于private常量的定义 <br>比较好的做法是对于这样的常量，加上final标记，这样的常量从初始化到最后结束值都不会改变。 <br>private int size = 5; <br>改变后的做法是： <br>private final int size = 5; <br><br>(11)避免把方法本地变量和参数定义成和类变量相同的名字。 <br>这样容易引起混扰，建议把任何的变量字都定义成唯一的。这样看来，SCJP里的那些题目在现实中就用不到了：） <br><br>public void method (int j) { final int I = 5; // VIOLATION } private int j = 2; <br><br><br>建议： <br>public void method (int j1) { final int I = 5; // VIOLATION } private int j = 2; <br><br>参考：Michael Daconta, Eric Monk, J Keller, Keith Bohnenberger: "Java Pitfalls" <br>John Wiley &amp; Sons, ISBN: 0-471-36174-7 pp.17 - 25</p>
<p>&nbsp;</p>
<p><font color=#000080>中级篇</font> <br><br>作者：flyingwcy 转载自：Java研究组织 <br>本文介绍的JAVA规则的说明分为3个主要级别，中级是平时开发用的比较多的级别，在今后将陆续写出其他的规则。遵守了这些规则可以提高程序的效率、使代码又更好的可读性等。 <br>（1） 在finally方法里关掉input或者output 资源 <br>再方法体里面定义了input或者output流的话，需要在finally里面把它关掉。 <br>以下这几种调用不需要遵守这条规则，因为colse()方法不起作用：） <br>java.io.StringWriter java.io.ByteArrayOutputStream java.io.ByteArrayInputStream <br>如果再方法返回的时候没有调用close()方法来释放input()和output()的资源的话，会导致一个系统资源泄漏。而且在任何情况下都要确定在返回全调用了close() 方法，包括出现异常的时候。所以需要在finally方法里面加入这个方法。这样就保证了在任何情况下都会关闭资源。 <br>错误示例： <br>public class CIO { <br>public void method (java.io.File f) { <br>java.io.FileInputStream fis = null; <br>try { <br>fis = new java.io.FileInputStream (f); <br>fis.read (); <br>fis.close (); <br>} catch (java.io.FileNotFoundException e1) { <br>System.out.println("File not found"); <br>} catch (java.io.IOException e2) { <br>System.out.println("I/O Exception"); <br>} <br>// 如果出现异常，这里就不能保证关闭资源。 <br>} <br>} <br>修正后的代码： <br>public class CIOFixed { <br>public void method (java.io.File f) { <br>java.io.FileInputStream fis = null; <br>try { <br>fis = new java.io.FileInputStream (f); <br>fis.read (); <br>} catch (java.io.FileNotFoundException e1) { <br>System.out.println("File not found"); <br>} catch (java.io.IOException e2) { <br>System.out.println("I/O Exception"); <br>} finally { <br>if (fis != null) { <br>try { <br>fis.close (); <br>} catch (java.io.IOException e) { <br>System.out.println("I/O Exception"); <br>} <br>} <br>} <br>} <br>} <br><br>（2） else的注意问题. <br>一般总认为如果if语句只有一句的话，那么{}就是可要可不要的了。可是如果if有else嵌套的话，就不一样了，{}是必需的 <br>错误示例： <br>if (I &lt; 5) <br>if (I &lt; 2) <br>i++; <br>else <br>i--; <br>修改后： <br>if (I &lt; 5) { <br>if (I &lt; 2) <br>i++; <br>} <br>else { <br>i--; <br>} <br><br>（3） 不要再catch()块里什么代码也不放 <br>在catch()块里面放入一些错误处理代码是一个好的习惯。但是如果catch()里面有有关javadoc 的代码，那也是可以的。 <br>错误示例： <br>try { <br>System.in.read (); <br>} catch (java.io.IOException e) { <br>// 错误 <br>} <br><br>正确： <br>try { <br>System.in.read (); <br>} catch (java.io.IOException e) { <br>System.out.println("Descriptive error"); <br>} <br>参考：Joshua Bloch: "Effective Java - Programming Language Guide". <br>Addison-Wesley, 2001, pp. 187 <br><br>（4）不要在if条件里面附值 <br>如果这样做的话，系统会报告错误。在java的很多条件声明里面用附值是很不明智的，而且系统也会报告错误。很容易引起异常。遵守这条规者能够使维护简单，避免不一致。 <br>错误示例： <br>if (b = true) <br>正确的： <br>if (b == true) <br>参考：Section 10.4 of<a href="http://java.sun.com/docs/codeconv/html/CodeConventions.doc9.html" target=_blank><font color=#000000><u> http://java.sun.com/docs/codeconv/html/CodeConventions.doc9.html</u></font></a>#547 <br><br>(5) for语句需要循环体。 <br>如果没有{}的话,for语句只会执行一次！ <br>错误示例： <br>for (I = 0; I &lt; 10; i++) ; <br>System.out.println (i); <br>这里print() 只会执行一次。 <br>正确： <br>for (I = 0; I &lt; 10; i++) { // FIXED <br>System.out.println (i); <br>} <br><br>（5） 不要把方法定义成main(). <br>在java里，main()方法是一个特别的方法。所以在自己定义方法的时候不要定义这样的名字，以免引起混扰。 <br><br>(6)不要直接或者间接的定义&#180;Error&#180;和&#180;Throwable&#180;的子类 <br>&#180;java.lang.Error&#180;只在JVM出现反常的时候覆盖这个方法，如果你定义了直接或者不直接的类继承了类&#180;Error&#180;，也就指出了这个错误是JVM内部的，而不是这个类的。所以对于java编译器来说是不可见的，这样就不能检查错误的异常处理了。 <br>&#180;java.lang.Throwable&#180;是&#180;java.lang.Exception&#180;和&#180;java.lang.Error&#180;的上级类，用户如果象定义异常类的话应该继承&#180;java.lang.Exception&#180;。 <br>错误示例：public class ABC extends Error <br>正确：public class ABC extends Exception <br><br>(7)有关"switch"语句里面的"case"问题 <br>最好在每一个 &#8220;case&#8221;里都定义一个&#8221;return&#8221;或者&#8220;break&#8221;来控制不要走到下面的 &#8220;case&#8221;里去。如果一个&#8221;case&#8221;语句在代码的最后没有一个&#8221;break&#8221;或者&#8221;return&#8221;句，程序就会走到下一个&#8221;case&#8221;。如果这个&#8221;case&#8221;是最后一个的话，那就没什么问题，如果后面还有&#8221;case&#8221; 的话，看起来就不太安全了。 <br>错误示例： <br>switch (i) { <br>case 1: <br>x = 10; <br>break; <br>case 2: <br>x = 20; <br>default: <br>a = 40; <br>break; <br>正确： <br>switch (i) { <br>case 1: <br>x = 10; <br>break; <br>case 2: // VIOLATION <br>x = 20; <br>break; <br>default: <br>x = 40; <br>break; <br><br>（8）建议不要使用&#180;System.getenv ()&#180; <br>不建议使用&#180;System.getenv ()&#180;，这个方法看起来很好用，不过并不是所有的系统都有环境变量的。不用这个方法也可能带来一些不方便。 <br>错误示例： <br>void method (String name) { <br>System.getenv (name); // 可以用其他方法来代替 <br>} <br>如果不用这个方法，我们可以用其它的方法来代替。比如：&#180;System.getProperty ()&#8217;，&#180;getTypeName ()&#180;等，这也可以找到java的系统属性。 <br>参考：David Flanagan: "Java in a Nutshell". O&#180;Reilly <br>November, 1999: Third Edition, pp.190-192 <br><br>（9）不要使用&#8217;\n&#8217;或者&#180;\r&#180;来分行 <br>这两个标记看来很普遍，特别是&#8217;\n&#8217;。我们经常用来作为分行用。但是不同的系统用不同的分行字符，所以这些字符在某些意义上违背了java的平台无关性。 <br>错误示例： <br>System.out.println("Hello\n" + name); <br>我们可以用其它的一些方法来代替，比如println()，这个方法在不同的系统平台上都起到相同的作用。后者推荐大家用这个方法：System.getProperty("line.separator") <br>参考：David Flanagan: "Java in a Nutshell". O&#180;Reilly, <br>November 1999: Third Edition, pp. 191-192 <br><br>(10) 使所有的内部类"private". <br>Java允许一个类包含另外一个类，带是Java byte code没有这个概念。类被编译器解释成package-private类。从更深的程度来说，包含类的任何内部私有对象能被内部类访问的也能被同一个包内的其他类访问。 <br>错误示例： <br>public class INNER { <br>class INNER_Class { <br>void setValue(int i) { <br>_value = I; // 现在包就可以访问了 <br>} <br>} <br>private int _value; <br>} <br>所以需要加上private class INNER_Class <br>参考：Statically Scanning Java Code: Finding Security Vulnerabilities. <br>John Viega, Gary McGraw, Tom Mutdosch, and Edward W. Felten <br>IEEE SOFTWARE September/October 2000 <br><br>（11）不要使接口序列化 <br>如果一个字节数组包含了一个被序列化的对象。攻击者就能读到这个对象的内部状态合字段（包括private的）。 <br>错误示例： <br>public interface sample extends java.io.Serializable</p>
<p>&nbsp;</p>
<p><font color=#000080>开发篇</font> <br><br>作者：flyingwcy 转载自：Java研究组织 <br>本文介绍的JAVA规则的说明分为3个主要级别，本篇抛弃了平时开发中很少遇到的情况，那些用得比较少的以后再高级篇里面出现。并有六个有用的国际软件开发重要注意的有关String的问题，遵守了这些规则可以提高程序的效率、使代码又更好的可读性等。 <br>（1） 如果有JDBC连接没有关掉的话，需要在"finally"方法中关掉 <br>如果数据库连接失败或者是没有释放连接，看上去无关紧要。但是其他的用户就需要用更长的时间等待连接，这样数据库利用效率就会下降。确保你的代码在任何情况下，包括出错或者程序异常终止的情况下都释放数据库连接。在"finally"方法中关掉连接，就可以确保这一点。 <br>错误示例： <br>try { <br>Statement stmt = con.createStatement(); <br>} catch(SQLException e) { <br>e.printStackTrace(); <br>} <br>正确示例： <br>try { <br>Statement stmt = con.createStatement(); <br>} finally { <br>if (con != null &amp;&amp; !con.isClosed()) { <br>con.close(); <br>} <br>} <br><br>（2） 尽量避免使用&#180;Thread.resume ()&#180;, &#180;Thread.stop ()&#180;, &#180;Thread.suspend ()&#180;和 &#180;Runtime.runFinalizersOnExit ()&#180; 方法。 <br>这些方法在平时的开发或者是教科书里面也有用到过，但是这些方法会导致四锁的倾向。一下有充足的资料来说明为什么不建议用上述方法。 <br>参考：1."java.lang.Thread" in the JDK API documentation <br>2<a href=".http://java.sun.com/j2se/1.3/docs/guide/misc/threadPrimitiveDeprecation.html" target=_blank><font color=#000000><u>.http://java.sun.com/j2se/1.3/docs/guide/misc/threadPrimitiveDeprecation.html</u></font></a> <br>3.Paul Hyde: "Java Thread Programming" <br>Sams, ISBN: 0-672-31585-8 pp. 270 <br><br>（3） 在表示长整常量的时候，用L来代替l. <br>因为l很容易和1混一起。 <br>错误示例： <br>long temp = 23434l; <br>正确示例： <br>long temp = 23434L; <br>参考：Ken Arnold, James Gosling: "The Java Programming Language Second Edition"Addison Wesley, 1997, pp.108 <br><br>（4） 最好在jsp开头写一条注释 <br>在 jsp文件头上面写一条注释，这样可以帮助别人来理解你的代码。这条规则不仅适用于jsp，更是用于任何开发的文档。 <br>正确示例：<%-- JSP comment --%> <br><br><br>(5)明确的初始化一个构造类里面的所有的字段 <br>因为没有初始化的字段会是一个潜在的bug，所以最好初始化类里面的所有的字段。特别是静态的字段，最好在一开始就分配一个初始值 <br>错误示例： <br>public class CSI { <br>public CSI () { <br>this (12); <br>k = 0; <br>} <br><br>public CSI (int val) { <br>j = val; <br>} <br><br>private int I = 5; <br>private int j; <br>private int k; <br>} <br><br>正确示例： <br>public class CSIFixed { <br>public CSIFixed () { <br>this (12); <br>} <br><br>public CSIFixed (int val) { <br>j = val; <br>k = 0; <br>} <br><br>private int I = 5; <br>private int j; <br>private int k; <br>} <br>参考：http://www.ambysoft.com/javaCodingStandards.pdf <br><br>（5） 国际化开发建议：逻辑操作符不要再一个单个的字符的前面或者后面 <br>一个单个字符的前后不要用逻辑操作符，如果代码要在一个国家环境中运行的话。我们可以使用字符比较方法，这些方法使用统一字符比较标准来定义字符的属性的。 <br>错误示例：public class CLO { <br>public boolean isLetter (char ch) { <br>boolean _isLetter = ( ch &gt;= &#180;a&#180; &amp;&amp; ch &lt;= &#180;z&#180;) //错误 <br>|| (ch &gt;= &#180;A&#180; &amp;&amp; ch &lt;= &#180;Z&#180;); <br>return _isLetter; <br>} <br>} <br><br>正确示例： <br>public class CLOFixed { <br>public boolean isLetter (char ch) { <br>boolean _isLetter = Character.isLetter(ch); <br>return _isLetter; <br>} <br>} <br>参考：<a href="http://java.sun.com/docs/books/tutorial/i18n/intro/checklist.html" target=_blank><font color=#000000><u> http://java.sun.com/docs/books/tutorial/i18n/intro/checklist.html</u></font></a> <br>更多的字符比较方法请参考：http://java.sun.com/docs/books/tutorial/i18n/text/charintro.html <br><br><br>（6） 国际化开发建议：不要对日期对象使用&#180;Date.toString ()&#180; <br>不要使用&#180;Date.toString ()&#180;方法，日期格式对于地区和语言不同的国家来说是不一样的，务必不要使用。 <br>错误示例：&#180;DateFormat&#180;类提供了一个预定义的格式类型来指定本地的格式。 <br>public void printToday () { <br>Date today = new Date (); <br>String todayStr = today.toString (); <br>System.out.println (todayStr); <br>} <br>正确示例： <br>public void printToday () { <br>Locale currentLocale = Locale.getDefault (); <br>DateFormat dateFormatter = DateFormat.getDateInstance ( <br>DateFormat.DEFAULT, currentLocale); <br>Date today = new Date (); <br>String todayStr = dateFormatter.format (today); <br>System.out.println (todayStr); <br>} <br>参考：http://java.sun.com/docs/books/tutorial/i18n/intro/checklist.html <br>http://java.sun.com/docs/books/tutorial/i18n/format/dateFormat.html <br><br>（7） 国际化开发建议：不要对数字变量使用&#180;toString ()&#180;方法 <br>在全球化的开发中，不要对数字变量使用&#180;toString ()&#180;方法，对于java.lang.Number的任何子类都适用。包括：BigDecimal, BigInteger, Byte, Double, Float, Integer, Long, and Short.对于这样的情况，java里也与定义了"NumberFormat"方法来格式化。 <br>错误示例： <br>public class NTS { <br>public void method (Double amount) { <br>String amountStr = amount.toString (); <br>System.out.println (amountStr); <br>} <br>} <br>正确示例： <br>public class NTSFixed { <br>public void method (Double amount) { <br>Locale currentLocale = Locale.getDefault (); <br>NumberFormat numberFormatter = <br>NumberFormat.getNumberInstance (currentLocale); <br>String amountStr = numberFormatter.format (amount); // <br>System.out.println (amountStr + &#180; &#180; + currentLocale.toString ()); <br>} <br>} <br>参考：http://java.sun.com/docs/books/tutorial/i18n/intro/checklist.html <br>http://java.sun.com/docs/books/tutorial/i18n/format/numberFormat.html <br><br><br>（8） 国际化开发建议:不要使用&#180;String.equals ()&#180;方法 <br>建议不要使用&#180;String.equals ()&#180;方法，因为在统一字符比较标准中不一定按照相关的顺序来比较。&#180;Collator&#180;提供的预定义整理规则来排序string，Collator类调用&#180;getInstance ()&#180;方法，一般来说，可以为默认的本地创建一个Collator。例如：Collator myCollator = Collator.getInstance ();创建Collator的时候你也可以指定一个特殊的locale。例如：Collator myFrenchCollator = Collator.getInstance (Locale.FRENCH);然后就可以调用&#180;Collator.compare ()&#180;来执行一个本地的字符比较myCollator.compare (s1,s2);从这里可以了解更多的有关Collator类的信息：http://java.sun.com/docs/books/tutorial/i18n/text/collationintro.html <br><br><br><br>错误示例： <br>public class SE { <br>public boolean compstr (String s1, String s2) { <br>boolean b = (s1.equals (s2)); <br>return b; <br>} <br>} <br>正确示例： <br>public class SEFixed { <br>public boolean compstr (String s1, String s2) { <br>Collator myCollator = Collator.getInstance (); <br>boolean b = (myCollator.compare(s1,s2) == 0); <br>return b; <br>} <br>} <br><br>参考：http://java.sun.com/docs/books/tutorial/i18n/intro/checklist.html <br>http://java.sun.com/docs/books/tutorial/i18n/text/locale.html <br><br>（9） 国际化开发建议：不要使用&#180;StringTokenizer()&#180;方法 <br>错误示例：StringTokenizer st = new StringTokenizer(str); <br>可以从这里得到更多的信息：&#8216; <br>参考：http://java.sun.com/docs/books/tutorial/i18n/intro/checklist.html <br><br><br>（10） 国际化开发建议：不要使用&#180;Time.toString ()&#180;方法 <br>因为时间的格式各个国家也不一样。如果你使用日期格式类，你的应用就能够在世界上各个地方正确的显示时间和日期了。首先，用&#180;getTimeInstance ()&#180;方法创建一个formatter。然后，调用&#180;format ()&#180;方法。 <br>错误示例： <br>public class TTS { <br>public void printTime (Time t1) { <br>String timeStr = t1.toString (); <br>System.out.println (timeStr); <br>} <br>} <br>正确示例： <br>import java.sql.Time; <br>import java.text.DateFormat; <br>import java.util.Locale; <br><br>public class TTSFixed { <br>public void printTime (Time t1) { <br>DateFormat timeFormatter = DateFormat.getTimeInstance( <br>DateFormat.DEFAULT, Locale.getDefault ()); <br>String timeStr = timeFormatter.format(t1); <br>System.out.println (timeStr); <br>} <br>}</p>
<br><br>
<p id=TBPingURL>Trackback: http://tb.donews.net/TrackBack.aspx?PostId=16048</p>
<br></div>
<img src ="http://www.cnitblog.com/sunnywang/aggbug/38599.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/sunnywang/" target="_blank">sunnywang   </a> 2008-01-08 11:59 <a href="http://www.cnitblog.com/sunnywang/archive/2008/01/08/38599.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java 的自定义异常</title><link>http://www.cnitblog.com/sunnywang/archive/2008/01/08/38598.html</link><dc:creator>sunnywang   </dc:creator><author>sunnywang   </author><pubDate>Tue, 08 Jan 2008 03:41:00 GMT</pubDate><guid>http://www.cnitblog.com/sunnywang/archive/2008/01/08/38598.html</guid><wfw:comment>http://www.cnitblog.com/sunnywang/comments/38598.html</wfw:comment><comments>http://www.cnitblog.com/sunnywang/archive/2008/01/08/38598.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/sunnywang/comments/commentRss/38598.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/sunnywang/services/trackbacks/38598.html</trackback:ping><description><![CDATA[<h3><span>3.2&nbsp; </span><span>自定义异常</span></h3>
<p><span>前面讨论了如何处理调用</span><span>Java API</span><span>的方法时产生的异常。根据需要，还可创建和使用自定义异常<span>——</span>自我构建表示错误的类。可创建全新异常，并将它们用于应用程序。</span></p>
<p><span>使用自定义异常有什么好处呢？为何要定义新异常类型？创建自定义异常是为了表示应用程序的一些错误类型，为代码可能发生的一个或多个问题提供新含义。可以显示代码多个位置之间的错误的相似性，也可区分代码运行时可能出现的相似问题的一个或多个错误，或给出应用程序中一组错误的特定含义。</span></p>
<p><span>例如，考虑任何类型的服务器。服务器的基本作用是处理与客户机的通信。若使用标准</span><span>Java API(</span><span>如</span><span>java.io</span><span>和</span><span>java.net</span><span>包中的类</span><span>)</span><span>来编写服务器，则可使编写的代码在多个位置抛</span><span>IOException</span><span>。</span> <span>在设置服务器、等待客户机连接和获取通信流时，可抛出</span><span>IOExceptions</span><span>；在通信期间及试图断开连接时，也可抛出</span><span>IOExceptions</span><span>。简言之，服务器的各个部分都可能引发</span><span>IOException</span><span>。</span></p>
<p><span>对服务器而言，这些</span><span>IOException</span><span>意义不尽相同。虽然由同一异常类型表示，但与各个异常相关的业务含义存在差异，报告和恢复操作亦有不同。可以将一个异常集与服务器配置和启动问题关联，将另一个异常集与客户机通信的实际行动关联，将第三个异常集与服务器关闭任务关联。使用自定义异常，可采用对应用程序有意义的方式来灵活地表示错误。</span></p>
<p><span>创建和使用自定义异常并不难。遵循以下</span><span>3</span><span>个步骤即可。</span></p>
<h3><span>3.2.1</span>&nbsp;<span>定义异常类</span></h3>
<p><span>一般要定义新类来表示自定义异常</span><span>。多数情况下，只需创建已有异常类的子类。</span></p>
<p><span>1 &nbsp;public class CustomerExistsException extends Exception{</span></p>
<p><span>2 &nbsp;&nbsp;&nbsp;public CustomerExistsException(){}</span></p>
<p><span>3 &nbsp;&nbsp;&nbsp;public CustomerExistsException(String message){</span></p>
<p><span>4 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;super(message);</span></p>
<p><span>5 &nbsp;&nbsp;&nbsp;}</span></p>
<p><span>6 &nbsp;}</span></p>
<p><span>至少要继承</span><span>Throwable</span><span>或</span><span>Throwable</span><span>的子类。经常需要定义一个或多个构造函数，以在对象中存储错误消息。如第</span><span>2-4</span><span>行所示。在继承任何异常时，将自动继承</span><span>Throwable</span><span>类的一些标准特性，如：</span></p>
<p><span>●<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>错误消息</span></p>
<p><span>●<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>栈跟踪</span></p>
<p><span>●<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>异常包装</span></p>
<p><span>若要在异常中添加附加信息，则可以为类添加一些变量和方法：</span></p>
<p><span>1 &nbsp;public class CustomerExistsException extends Exception{</span></p>
<p><span>2&nbsp;&nbsp; &nbsp;private String customerName;</span></p>
<p><span>3 &nbsp;&nbsp; public CustomerExistsException(){}</span></p>
<p><span>4 &nbsp;&nbsp;&nbsp; public CustomerExistsException(String message){</span></p>
<p><span>5 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;super(message);</span></p>
<p><span>6 &nbsp;&nbsp;&nbsp; }</span></p>
<p><span>7 &nbsp;&nbsp;&nbsp;&nbsp;public CustomerExistsException(String message, String customer){</span></p>
<p><span>8 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;super(message);</span></p>
<p><span>9 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;customerName = customer;</span></p>
<p><span>10 &nbsp;&nbsp;&nbsp; }</span></p>
<p><span>11 &nbsp;&nbsp;&nbsp;&nbsp;public String getCustomerName(){</span></p>
<p><span>12 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return customerName;</span></p>
<p><span>13 &nbsp;&nbsp;&nbsp;&nbsp;}</span></p>
<p><span>14 &nbsp;}</span></p>
<p><span>由本例可知，可修改</span><span>CustomerExistsException</span><span>类，以支持其他属性。例如，可将</span><span>customerName</span><span>字符串</span><span>(</span><span>引发异常的记录的客户名</span><span>)</span><span>与异常联系起来。</span></p>
<h3><span>3.2.2</span>&nbsp;<span>声明方法抛出自定义异常</span></h3>
<p><span>这实际上是&#8220;处理或声明&#8221;规则的&#8220;声明&#8221;部分。为了使用自定义异常，必须通知调用代码的类：要准备处理这个异常类型。为此，声明一个或多个方法抛出异常：</span></p>
<p><span>public void insertCustomer(Customer c) </span><strong><span>throws </span><span>CustomerExistsException{</span></strong></p>
<p><span>// The method stores customer information in the database.</span></p>
<p><span>// If the customer data already exists, the method creates</span></p>
<p><span>// and throws the CustomerExistsException.</span></p>
<p><span>}</span></p>
<h3><span>3.2.3</span>&nbsp;<span>找到故障点，新建异常并加上关键字</span><span>throw</span></h3>
<p><span>最后一步实际上是创建对象，并通过系统传送该对象。为此，需要了解代码将在方法的哪个位置出现故障。根据情况，可能要使用以下部分或所有条件，来指示代码中的故障点。</span></p>
<p><span>1. </span><span>外部问题</span></p>
<p><span>●<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>应用程序中产生的异常</span></p>
<p><span>●<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>其他方法返回的故障代码</span></p>
<p><span>2. </span><span>内部问题</span></p>
<p><span>●<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>应用程序状态不一致</span></p>
<p><span>●<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>应用程序中的处理问题</span></p>
<p><span>在本例中，当不能新建一个客户时会遇到一个故障场景。结果，创建一个异常来表示问题并抛出该问题。如下面的示例方法所示：</span></p>
<p><span>1 &nbsp;public void insertCustomer(Customer c)</span></p>
<p><span>2 &nbsp;&nbsp;&nbsp;</span><strong><span>throws CustomerExistsException</span></strong><span>, SQLException {</span></p>
<p><span>3 &nbsp;&nbsp;&nbsp;String selectSql =</span></p>
<p><span>4 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"SELECT * FROM Customer WHERE first_name=? AND last_name=?";</span></p>
<p><span>5 &nbsp;&nbsp;&nbsp;String insertSql = "INSERT INTO Customer VALUES(?, ?)";</span></p>
<p><span>6 &nbsp;&nbsp;&nbsp;try{</span></p>
<p><span>7 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Connection conn = dbmsConnectionFactory.getConnection();</span></p>
<p><span>8 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PreparedStatement selStmt = conn.prepareStatement(selectSql);</span></p>
<p><span>9 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;selectStmt.setString(1, c.getFirstName());</span></p>
<p><span>10 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;selectStmt.setString(2, c.getLastName());</span></p>
<p><span>11 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ResultSet rs = selStmt.executeQuery();</span></p>
<p><span>12 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (rs.next()){</span></p>
<p><span>13 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// In this case, the failure condition is produced if you</span></p>
<p><span>14 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// &nbsp;can already locate a metching record in the database.</span></p>
<p><span>15 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw new CustomerExistsException("Customer exists:" + c, c);</span></p>
<p><span>16 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></p>
<p><span>17 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else{</span></p>
<p><span>18 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PreparedStatement insStmt = conn.prepareStatement(insertSql);</span></p>
<p><span>19 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;insStmt.setString(1, c.getFirstName());</span></p>
<p><span>20 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;insStmt.setString(2, c.getLastName());</span></p>
<p><span>21 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int status = insStmt.executeUpdate();</span></p>
<p><span>22 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></p>
<p><span>23 &nbsp;&nbsp;}</span></p>
<p><span>24 &nbsp;&nbsp;catch (SQLException exc){</span></p>
<p><span>Java</span><span>关键字</span><span>throw</span><span>将这个新异常对象传给该方法的调用者。在执行完这</span><span>3</span><span>个步骤后，就创建了自定义异常。除非派生一个非检测异常类</span><span>(</span><span>如</span><span>RuntimeException</span><span>或</span><span>Error)</span><span>，否则调用方法的任何对象随后将按照&#8220;处理或声明&#8221;规则解决该异常。</span></p>
<p><span>这引出了一个有趣的问题：在自定义异常时，应如何派生？必须在</span><span>Throwable</span><span>类层次结构中派生，否则将不能在应用程序中传播异常。另外，不能从</span><span>Throwable</span><span>直接派生。</span><span>Throwable</span><span>为两类主要问题</span><span>(Exception</span><span>和</span><span>Error)</span><span>提供行为基础，不能为这棵继承树定义新分支。一般也不要直接继承</span><span>Error</span><span>或其任何子类，因为自定义异常通常不符合错误标准</span><span>(</span><span>即适当应用程序不应试图捕获的严重问题</span><span>)</span><span>。</span></p>
<p><span>需要从</span><span>Exception</span><span>类层次结构中派生。一般地，应将自定义异常定义为故障状态更一般的异常类型的子类。例如，</span><span>ServerConnectionException</span><span>是</span><span>java.io.IOException</span><span>的子类，因为</span><span>Server- Connec tionException</span><span>是</span><span>java.io.IOException</span><span>的更具体类型。</span></p>
<p><span>如果定义的异常从</span><span>RuntimeException</span><span>树继承，是否属于正确的编码实践？若如此，就回避了异常机制，即使声明了异常，类也不必显式处理异常</span><span>。</span></p>
<p><span>通过本例，可了解到如何创建基本的自定义异常。很多情况下，这可轻易地满足要求。自定义异常类</span><span>(</span><span>可能还有消息</span><span>)</span><span>经常是应用程序惟一需要的异常。有时，需要支持更高级的特性，在一些异常中，可能要用到两个属性：链表</span><span>(chaining)</span><span>和本地化</span><span>(localization)</span><span>。</span></p>
<!-- page -->
<img src ="http://www.cnitblog.com/sunnywang/aggbug/38598.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/sunnywang/" target="_blank">sunnywang   </a> 2008-01-08 11:41 <a href="http://www.cnitblog.com/sunnywang/archive/2008/01/08/38598.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java 正则表达式 pattern类  matcher类</title><link>http://www.cnitblog.com/sunnywang/archive/2008/01/02/38397.html</link><dc:creator>sunnywang   </dc:creator><author>sunnywang   </author><pubDate>Wed, 02 Jan 2008 14:10:00 GMT</pubDate><guid>http://www.cnitblog.com/sunnywang/archive/2008/01/02/38397.html</guid><wfw:comment>http://www.cnitblog.com/sunnywang/comments/38397.html</wfw:comment><comments>http://www.cnitblog.com/sunnywang/archive/2008/01/02/38397.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/sunnywang/comments/commentRss/38397.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/sunnywang/services/trackbacks/38397.html</trackback:ping><description><![CDATA[<strong><font size=5>、正则表达式基础知识：（此文讲的是符合perl的正则表达式匹配方法，与jdk1.4上的不一样，但讲的很清晰，可作为基础知识讲解看）<br></font></strong>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>如果你曾经用过Perl或任何其他内建正则表达式支持的语言，你一定知道用正则表达式处理文本和匹配模式是多么简单。如果你不熟悉这个术语，那么&#8220;正则表达式&#8221;（Regular Expression）就是一个字符构成的串，它定义了一个用来搜索匹配字符串的模式。 </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>许多语言，包括Perl、PHP、Python、<span class=hilite1>Java</span>Script和JScript，都支持用正则表达式处理文本，一些文本编辑器用正则表达式实现高级&#8220;搜索-替换&#8221;功能。那么<span class=hilite1>Java</span>又怎样呢？本文写作时，一个包含了用正则表达式进行文本处理的<span class=hilite1>Java</span>规范需求（Specification Request）已经得到认可，你可以期待在JDK的下一版本中看到它。</td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>然而，如果现在就需要使用正则表达式，又该怎么办呢？你可以从Apache.org下载源代码开放的Jakarta-ORO库。本文接下来的内容先简要地介绍正则表达式的入门知识，然后以Jakarta-ORO API为例介绍如何使用正则表达式。 </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14><strong><font size=4>一、正则表达式基础知识</font> </strong></td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>我们先从简单的开始。假设你要搜索一个包含字符&#8220;cat&#8221;的字符串，搜索用的正则表达式就是&#8220;cat&#8221;。如果搜索对大小写不敏感，单词&#8220;catalog&#8221;、&#8220;Catherine&#8221;、&#8220;sophisticated&#8221;都可以匹配。也就是说： </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14><img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_a.jpg" border=0 _counted="undefined"> </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14><strong>1.1 句点符号</strong> </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>假设你在玩英文拼字游戏，想要找出三个字母的单词，而且这些单词必须以&#8220;t&#8221;字母开头，以&#8220;n&#8221;字母结束。另外，假设有一本英文字典，你可以用正则表达式搜索它的全部内容。要构造出这个正则表达式，你可以使用一个通配符——句点符号&#8220;.&#8221;。这样，完整的表达式就是&#8220;t.n&#8221;，它匹配&#8220;tan&#8221;、&#8220;ten&#8221;、&#8220;tin&#8221;和&#8220;ton&#8221;，还匹配&#8220;t#n&#8221;、&#8220;tpn&#8221;甚至&#8220;t n&#8221;，还有其他许多无意义的组合。这是因为句点符号匹配所有字符，包括空格、Tab字符甚至换行符： </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14><img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_b.jpg" border=0 _counted="undefined"> </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14><strong>1.2 方括号符号</strong> </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>为了解决句点符号匹配范围过于广泛这一问题，你可以在方括号（&#8220;[]&#8221;）里面指定看来有意义的字符。此时，只有方括号里面指定的字符才参与匹配。也就是说，正则表达式&#8220;t[aeio]n&#8221;只匹配&#8220;tan&#8221;、&#8220;Ten&#8221;、&#8220;tin&#8221;和&#8220;ton&#8221;。但&#8220;Toon&#8221;不匹配，因为在方括号之内你只能匹配单个字符： </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14><img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_c.jpg" border=0 _counted="undefined"> </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14><strong>1.3 &#8220;或&#8221;符号</strong> </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>如果除了上面匹配的所有单词之外，你还想要匹配&#8220;toon&#8221;，那么，你可以使用&#8220;|&#8221;操作符。&#8220;|&#8221;操作符的基本意义就是&#8220;或&#8221;运算。要匹配&#8220;toon&#8221;，使用&#8220;t(a|e|i|o|oo)n&#8221;正则表达式。这里不能使用方扩号，因为方括号只允许匹配单个字符；这里必须使用圆括号&#8220;()&#8221;。圆括号还可以用来分组，具体请参见后面介绍。 </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14><img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_d.jpg" border=0 _counted="undefined"> </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14><strong>1.4 表示匹配次数的符号</strong> </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>表一显示了表示匹配次数的符号，这些符号用来确定紧靠该符号左边的符号出现的次数： </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>
            <p align=center><img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4n.jpg" border=0 _counted="undefined"> </p>
            </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>假设我们要在文本文件中搜索美国的社会安全号码。这个号码的格式是999-99-9999。用来匹配它的正则表达式如图一所示。在正则表达式中，连字符（&#8220;-&#8221;）有着特殊的意义，它表示一个范围，比如从0到9。因此，匹配社会安全号码中的连字符号时，它的前面要加上一个转义字符&#8220;\&#8221;。 </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>
            <p align=center><img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4a.gif" border=0 _counted="undefined"> </p>
            </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>
            <p align=center>图一：匹配所有123-12-1234形式的社会安全号码</p>
            </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>假设进行搜索的时候，你希望连字符号可以出现，也可以不出现——即，999-99-9999和999999999都属于正确的格式。这时，你可以在连字符号后面加上&#8220;？&#8221;数量限定符号，如图二所示： </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>
            <p align=center><img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4b.gif" border=0 _counted="undefined"> </p>
            </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>
            <p align=center>图二：匹配所有123-12-1234和123121234形式的社会安全号码</p>
            </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>下面我们再来看另外一个例子。美国汽车牌照的一种格式是四个数字加上二个字母。它的正则表达式前面是数字部分&#8220;[0-9]{4}&#8221;，再加上字母部分&#8220;[A-Z]{2}&#8221;。图三显示了完整的正则表达式。 </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>
            <p align=center><img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4c.gif" border=0 _counted="undefined"> </p>
            </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>
            <p align=center>图三：匹配典型的美国汽车牌照号码，如8836KV</p>
            </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>1.5 &#8220;否&#8221;符号 </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>&#8220;^&#8221;符号称为&#8220;否&#8221;符号。如果用在方括号内，&#8220;^&#8221;表示不想要匹配的字符。例如，图四的正则表达式匹配所有单词，但以&#8220;X&#8221;字母开头的单词除外。 </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>
            <p align=center><img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4d.gif" border=0 _counted="undefined"> </p>
            </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>
            <p align=center>图四：匹配所有单词，但&#8220;X&#8221;开头的除外</p>
            </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>1.6 圆括号和空白符号 </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>假设要从格式为&#8220;June 26, 1951&#8221;的生日日期中提取出月份部分，用来匹配该日期的正则表达式可以如图五所示： </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>
            <p align=center><img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4e.gif" border=0 _counted="undefined"> </p>
            </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>
            <p align=center>图五：匹配所有Moth DD,YYYY格式的日期</p>
            </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>新出现的&#8220;\s&#8221;符号是空白符号，匹配所有的空白字符，包括Tab字符。如果字符串正确匹配，接下来如何提取出月份部分呢？只需在月份周围加上一个圆括号创建一个组，然后用ORO API（本文后面详细讨论）提取出它的值。修改后的正则表达式如图六所示： </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>
            <p align=center><img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4f.gif" border=0 _counted="undefined"> </p>
            </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>
            <p align=center>图六：匹配所有Month DD,YYYY格式的日期，定义月份值为第一个组</p>
            </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14><strong>1.7 其它符号</strong> </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>为简便起见，你可以使用一些为常见正则表达式创建的快捷符号。如表二所示： </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>表二：常用符号 </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>
            <p align=center><img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4o.jpg" border=0 _counted="undefined"> </p>
            </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>例如，在前面社会安全号码的例子中，所有出现&#8220;[0-9]&#8221;的地方我们都可以使用&#8220;\d&#8221;。修改后的正则表达式如图七所示： </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>
            <p align=center><img src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4g.gif" border=0 _counted="undefined"> </p>
            </td>
        </tr>
    </tbody>
</table>
<table width=620 align=center>
    <tbody>
        <tr>
            <td class=a14>
            <p align=left>图七：匹配所有123-12-1234格式的社会安全号码<br><!--startfragment --></p>
            </td>
        </tr>
        <tr vAlign=baseline>
            <th align=left></th>
        </tr>
    </tbody>
</table>
<font size=5><strong>－－－－－－－－－－－－－－－－－－－－－－－－－<br>二、正则表达式在<span class=hilite1>java</span>中</strong>应用</font> （<span class=hilite1>java</span>编程思想第三版P565页有讲解）<a name=1><span class=atitle><font face=Arial><br><font size=4>简介：</font></font></span></a>
<p><span class=hilite1>java</span>.util.regex是一个用正则表达式所订制的模式来对字符串进行匹配工作的类库包。</p>
<p>它包括两个类： <strong>Pattern</strong>和 <strong>Matcher</strong></p>
<table cellSpacing=0 cellPadding=5 border=1>
    <tbody>
        <tr>
            <td><strong>Pattern</strong></td>
            <td>一个Pattern是一个正则表达式经编译后的表现模式。</td>
        </tr>
        <tr>
            <td><strong>Matcher</strong></td>
            <td>一个Matcher对象是一个状态机器，它依据Pattern对象做为匹配模式对字符串展开匹配检查。</td>
        </tr>
    </tbody>
</table>
<p>首先一个Pattern实例订制了一个所用语法与PERL的类似的正则表达式经编译后的模式，然后一个Matcher实例在这个给定的Pattern实例的模式控制下进行字符串的匹配工作。</p>
<p>以下我们就分别来看看这两个类：</p>
<br><br>
<p><a name=2><span class=atitle><font face=Arial size=4>Pattern类: </font></span></a></p>
<p>Pattern的方法如下：</p>
<table cellSpacing=0 cellPadding=5 width="100%" border=1>
    <tbody>
        <tr>
            <td align=right>static Pattern</td>
            <td><strong>compile</strong>(String regex) <br>将给定的正则表达式编译并赋予给Pattern类 </td>
        </tr>
        <tr>
            <td align=right>static Pattern</td>
            <td><strong>compile</strong>(String regex, int flags) <br>同上，但增加flag参数的指定，可选的flag参数包括：CASE INSENSITIVE,MULTILINE,DOTALL,UNICODE CASE， CANON EQ </td>
        </tr>
        <tr>
            <td align=right>int</td>
            <td><strong>flags</strong>() <br>返回当前Pattern的匹配flag参数. </td>
        </tr>
        <tr>
            <td align=right>Matcher</td>
            <td><strong>matcher</strong>(CharSequence input) <br>生成一个给定命名的Matcher对象 </td>
        </tr>
        <tr>
            <td align=right>static boolean</td>
            <td><strong>matches</strong>(String regex, CharSequence input) <br>编译给定的正则表达式并且对输入的字串以该正则表达式为模开展匹配,该方法适合于该正则表达式只会使用一次的情况，也就是只进行一次匹配工作，因为这种情况下并不需要生成一个Matcher实例。 </td>
        </tr>
        <tr>
            <td align=right>String</td>
            <td><strong>pattern</strong>() <br>返回该Patter对象所编译的正则表达式。 </td>
        </tr>
        <tr>
            <td align=right>String[]</td>
            <td><strong>split</strong>(CharSequence input) <br>将目标字符串按照Pattern里所包含的正则表达式为模进行分割。 </td>
        </tr>
        <tr>
            <td align=right>String[]</td>
            <td><strong>split</strong>(CharSequence input, int limit) <br>作用同上，增加参数limit目的在于要指定分割的段数，如将limi设为2，那么目标字符串将根据正则表达式分为割为两段。 </td>
        </tr>
    </tbody>
</table>
<p>一个正则表达式，也就是一串有特定意义的字符，必须首先要编译成为一个Pattern类的实例，这个Pattern对象将会使用 <strong>matcher()</strong>方法来生成一个Matcher实例，接着便可以使用该 Matcher实例以编译的正则表达式为基础对目标字符串进行匹配工作，多个Matcher是可以共用一个Pattern对象的。 </p>
<p>现在我们先来看一个简单的例子，再通过分析它来了解怎样生成一个Pattern对象并且编译一个正则表达式，最后根据这个正则表达式将目标字符串进行分割：</p>
<table cellSpacing=0 cellPadding=5 width="100%" bgColor=#eeeeee border=1>
    <tbody>
        <tr>
            <td>
            <pre><code class=section><font face="Lucida Console">import <span class=hilite1>java</span>.util.regex.*;<br>
            public class Replacement{
            public static void main(String[] args) throws Exception {
            // 生成一个Pattern,同时编译一个正则表达式
            Pattern p = Pattern.compile("[/]+");
            //用Pattern的split()方法把字符串按"/"分割
            String[] result = p.split(
            "Kevin has seen《LEON》seveal times,because it is a good film."
            +"/ 凯文已经看过《这个杀手不太冷》几次了，因为它是一部"
            +"好电影。/名词:凯文。");
            for (int i=0; i&lt;result.length; i++)
            System.out.println(result[i]);
            }
            }
            </font></code></pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p>输出结果为：</p>
<pre>Kevin has seen《LEON》seveal times,because it is a good film.
凯文已经看过《这个杀手不太冷》几次了，因为它是一部好电影。
名词:凯文。
</pre>
<p>很明显，该程序将字符串按"/"进行了分段，我们以下再使用 <strong>split</strong>(CharSequence input, int limit)方法来指定分段的段数，程序改动为： <br><code>tring[] result = p.split("Kevin has seen《LEON》seveal times,because it is a good film./ 凯文已经看过《这个杀手不太冷》几次了，因为它是一部好电影。/名词:凯文。"，2);</code></p>
<p>这里面的参数"2"表明将目标语句分为两段。</p>
<p>输出结果则为：</p>
<pre>Kevin has seen《LEON》seveal times,because it is a good film.
凯文已经看过《这个杀手不太冷》几次了，因为它是一部好电影。/名词:凯文。</pre>
<br>
<p>由上面的例子，我们可以比较出<span class=hilite1>java</span>.util.regex包在构造Pattern对象以及编译指定的正则表达式的实现手法与我们在上一篇中所介绍的Jakarta-ORO 包在完成同样工作时的差别，Jakarta-ORO 包要先构造一个PatternCompiler类对象接着生成一个Pattern对象，再将正则表达式用该PatternCompiler类的compile()方法来将所需的正则表达式编译赋予Pattern类：</p>
<p>PatternCompiler orocom=new Perl5Compiler();</p>
<p>Pattern pattern=orocom.compile("REGULAR EXPRESSIONS");</p>
<p>PatternMatcher matcher=new Perl5Matcher();</p>
<p>但是在<span class=hilite1>java</span>.util.regex包里，我们仅需生成一个Pattern类，直接使用它的compile()方法就可以达到同样的效果: <code>Pattern p = Pattern.compile("[/]+");</code></p>
<p>因此似乎<span class=hilite1>java</span>.util.regex的构造法比Jakarta-ORO更为简洁并容易理解。</p>
<br>
<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr>
            <td><img class=magplus title=点击查看原始大小图片 height=0 alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width=700 _counted="undefined"><br><img height=6 alt="" src="http://www.ibm.com/i/c.gif" width=8 border=0 _counted="undefined"></td>
        </tr>
    </tbody>
</table>
<table class=no-print cellSpacing=0 cellPadding=0 align=right>
    <tbody>
        <tr align=right>
            <td><img height=4 alt="" src="http://www.ibm.com/i/c.gif" width="100%" _counted="undefined"><br>
            <table cellSpacing=0 cellPadding=0 border=0>
                <tbody>
                    <tr>
                        <td vAlign=center><img height=16 alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width=16 border=0 _counted="undefined"><br></td>
                        <td vAlign=top align=right><a class=fbox href="http://www-128.ibm.com/developerworks/cn/java/l-regp/part2/index.html#main"><strong><font color=#996699>回页首</font><font color=#000080></font></strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br><br>
<p><a name=3><span class=atitle><font face=Arial size=4>Matcher类:</font></span></a></p>
<p>Matcher方法如下：</p>
<table cellSpacing=0 cellPadding=5 width="100%" border=1>
    <tbody>
        <tr>
            <td align=right>Matcher</td>
            <td><strong>appendReplacement</strong>(StringBuffer sb, String replacement) <br>将当前匹配子串替换为指定字符串，并且将替换后的子串以及其之前到上次匹配子串之后的字符串段添加到一个StringBuffer对象里。 </td>
        </tr>
        <tr>
            <td align=right>StringBuffer</td>
            <td><strong>appendTail</strong>(StringBuffer sb) <br>将最后一次匹配工作后剩余的字符串添加到一个StringBuffer对象里。 </td>
        </tr>
        <tr>
            <td align=right>int</td>
            <td><strong>end</strong>() <br>返回当前匹配的子串的最后一个字符在原目标字符串中的索引位置 。 </td>
        </tr>
        <tr>
            <td align=right>int</td>
            <td><strong>end</strong>(int group) <br>返回与匹配模式里指定的组相匹配的子串最后一个字符的位置。 </td>
        </tr>
        <tr>
            <td align=right>boolean</td>
            <td><strong>find</strong>() <br>尝试在目标字符串里查找下一个匹配子串。 </td>
        </tr>
        <tr>
            <td align=right>boolean</td>
            <td><strong>find</strong>(int start) <br>重设Matcher对象，并且尝试在目标字符串里从指定的位置开始查找下一个匹配的子串。 </td>
        </tr>
        <tr>
            <td align=right>String</td>
            <td><strong>group</strong>() <br>返回当前查找而获得的与组匹配的所有子串内容 </td>
        </tr>
        <tr>
            <td align=right>String</td>
            <td><strong>group</strong>(int group) <br>返回当前查找而获得的与指定的组匹配的子串内容 </td>
        </tr>
        <tr>
            <td align=right>int</td>
            <td><strong>groupCount</strong>() <br>返回当前查找所获得的匹配组的数量。 </td>
        </tr>
        <tr>
            <td align=right>boolean</td>
            <td><strong>lookingAt</strong>() <br>检测目标字符串是否以匹配的子串起始。 </td>
        </tr>
        <tr>
            <td align=right>boolean</td>
            <td><strong>matches</strong>() <br>尝试对整个目标字符展开匹配检测，也就是只有整个目标字符串完全匹配时才返回真值。 </td>
        </tr>
        <tr>
            <td align=right>Pattern</td>
            <td><strong>pattern</strong>() <br>返回该Matcher对象的现有匹配模式，也就是对应的Pattern 对象。 </td>
        </tr>
        <tr>
            <td align=right>String</td>
            <td><strong>replaceAll</strong>(String replacement) <br>将目标字符串里与既有模式相匹配的子串全部替换为指定的字符串。 </td>
        </tr>
        <tr>
            <td align=right>String</td>
            <td><strong>replaceFirst</strong>(String replacement) <br>将目标字符串里第一个与既有模式相匹配的子串替换为指定的字符串。 </td>
        </tr>
        <tr>
            <td align=right>Matcher</td>
            <td><strong>reset</strong>() <br>重设该Matcher对象。 </td>
        </tr>
        <tr>
            <td align=right>Matcher</td>
            <td><strong>reset</strong>(CharSequence input) <br>重设该Matcher对象并且指定一个新的目标字符串。 </td>
        </tr>
        <tr>
            <td align=right>int</td>
            <td><strong>start</strong>() <br>返回当前查找所获子串的开始字符在原目标字符串中的位置。 </td>
        </tr>
        <tr>
            <td align=right>int</td>
            <td><strong>start</strong>(int group) <br>返回当前查找所获得的和指定组匹配的子串的第一个字符在原目标字符串中的位置。 </td>
        </tr>
    </tbody>
</table>
<p>（光看方法的解释是不是很不好理解？不要急，待会结合例子就比较容易明白了）</p>
<p>一个Matcher实例是被用来对目标字符串进行基于既有模式（也就是一个给定的Pattern所编译的正则表达式）进行匹配查找的，所有往Matcher的输入都是通过CharSequence接口提供的，这样做的目的在于可以支持对从多元化的数据源所提供的数据进行匹配工作。</p>
<p>我们分别来看看各方法的使用：</p>
<p>★matches()/lookingAt ()/find()： <br>一个Matcher对象是由一个Pattern对象调用其matcher()方法而生成的，一旦该Matcher对象生成,它就可以进行三种不同的匹配查找操作： </p>
<ol>
    <li>matches()方法尝试对整个目标字符展开匹配检测，也就是只有整个目标字符串完全匹配时才返回真值。
    <li>lookingAt ()方法将检测目标字符串是否以匹配的子串起始。
    <li>find()方法尝试在目标字符串里查找下一个匹配子串。 </li>
</ol>
<p>以上三个方法都将返回一个布尔值来表明成功与否。</p>
<p>★replaceAll ()/appendReplacement()/appendTail()： <br>Matcher类同时提供了四个将匹配子串替换成指定字符串的方法： </p>
<ol>
    <li>replaceAll()
    <li>replaceFirst()
    <li>appendReplacement()
    <li>appendTail() </li>
</ol>
<p>replaceAll()与replaceFirst()的用法都比较简单，请看上面方法的解释。我们主要重点了解一下appendReplacement()和appendTail()方法。</p>
<p>appendReplacement(StringBuffer sb, String replacement) 将当前匹配子串替换为指定字符串，并且将替换后的子串以及其之前到上次匹配子串之后的字符串段添加到一个StringBuffer对象里，而appendTail(StringBuffer sb) 方法则将最后一次匹配工作后剩余的字符串添加到一个StringBuffer对象里。</p>
<p>例如，有字符串fatcatfatcatfat,假设既有正则表达式模式为"cat"，第一次匹配后调用appendReplacement(sb,"dog"),那么这时StringBuffer sb的内容为fatdog，也就是fatcat中的cat被替换为dog并且与匹配子串前的内容加到sb里，而第二次匹配后调用appendReplacement(sb,"dog")，那么sb的内容就变为fatdogfatdog，如果最后再调用一次appendTail（sb）,那么sb最终的内容将是fatdogfatdogfat。</p>
<p>还是有点模糊？那么我们来看个简单的程序：</p>
<table cellSpacing=0 cellPadding=5 width="100%" bgColor=#eeeeee border=1>
    <tbody>
        <tr>
            <td>
            <pre><code class=section><font face="Lucida Console">//该例将把句子里的"Kelvin"改为"Kevin"
            import <span class=hilite1>java</span>.util.regex.*;
            public class MatcherTest{
            public static void main(String[] args)
            throws Exception {
            //生成Pattern对象并且编译一个简单的正则表达式"Kelvin"
            Pattern p = Pattern.compile("Kevin");
            //用Pattern类的matcher()方法生成一个Matcher对象
            Matcher m = p.matcher("Kelvin Li and Kelvin Chan are both working <br>in Kelvin Chen's KelvinSoftShop company");
            StringBuffer sb = new StringBuffer();
            int i=0;
            //使用find()方法查找第一个匹配的对象
            boolean result = m.find();
            //使用循环将句子里所有的kelvin找出并替换再将内容加到sb里
            while(result) {
            i++;
            m.appendReplacement(sb, "Kevin");
            System.out.println("第"+i+"次匹配后sb的内容是："+sb);
            //继续查找下一个匹配对象
            result = m.find();
            }
            //最后调用appendTail()方法将最后一次匹配后的剩余字符串加到sb里；
            m.appendTail(sb);
            System.out.println("调用m.appendTail(sb)后sb的最终内容是:"+ sb.toString());
            }
            }</font></code></pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p>最终输出结果为： <br>第1次匹配后sb的内容是：Kevin <br>第2次匹配后sb的内容是：Kevin Li and Kevin <br>第3次匹配后sb的内容是：Kevin Li and Kevin Chan are both working in Kevin <br>第4次匹配后sb的内容是：Kevin Li and Kevin Chan are both working in Kevin Chen's Kevin <br>调用m.appendTail(sb)后sb的最终内容是：Kevin Li and Kevin Chan are both working in Kevin Chen's KevinSoftShop company. </p>
<p>看了上面这个例程是否对appendReplacement()，appendTail()两个方法的使用更清楚呢，如果还是不太肯定最好自己动手写几行代码测试一下。</p>
<p>★group()/group(int group)/groupCount()： <br>该系列方法与我们在上篇介绍的Jakarta-ORO中的MatchResult .group()方法类似(有关Jakarta-ORO请参考上篇的内容)，都是要返回与组匹配的子串内容，下面代码将很好解释其用法： </p>
<table cellSpacing=0 cellPadding=5 width="100%" bgColor=#eeeeee border=1>
    <tbody>
        <tr>
            <td>
            <pre><code class=section><font face="Lucida Console">import <span class=hilite1>java</span>.util.regex.*;
            public class GroupTest{
            public static void main(String[] args)
            throws Exception {
            Pattern p = Pattern.compile("(ca)(t)");
            Matcher m = p.matcher("one cat,two cats in the yard");
            StringBuffer sb = new StringBuffer();
            boolean result = m.find();
            System.out.println("该次查找获得匹配组的数量为："+m.groupCount());
            for(int i=1;i&lt;=m.groupCount();i++){
            System.out.println("第"+i+"组的子串内容为： "+m.group(i));
            }
            }
            }</font></code></pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p>输出为： <br>该次查找获得匹配组的数量为：2 <br>第1组的子串内容为：ca <br>第2组的子串内容为：t </p>
<p>Matcher对象的其他方法因比较好理解且由于篇幅有限，请读者自己编程验证。</p>
<br>
<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr>
            <td><img class=magplus title=点击查看原始大小图片 height=0 alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width=700 _counted="undefined"><br><img height=6 alt="" src="http://www.ibm.com/i/c.gif" width=8 border=0 _counted="undefined"></td>
        </tr>
    </tbody>
</table>
<table class=no-print cellSpacing=0 cellPadding=0 align=right>
    <tbody>
        <tr align=right>
            <td><img height=4 alt="" src="http://www.ibm.com/i/c.gif" width="100%" _counted="undefined"><br>
            <table cellSpacing=0 cellPadding=0 border=0>
                <tbody>
                    <tr>
                        <td vAlign=center><img height=16 alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width=16 border=0 _counted="undefined"><br></td>
                        <td vAlign=top align=right><a class=fbox href="http://www-128.ibm.com/developerworks/cn/java/l-regp/part2/index.html#main"><strong><font color=#996699>回页首</font><font color=#000080></font></strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br><br>
<p><a name=4><span class=atitle><font face=Arial size=4>一个检验Email地址的小程序：</font></span></a></p>
<p>最后我们来看一个检验Email地址的例程，该程序是用来检验一个输入的EMAIL地址里所包含的字符是否合法，虽然这不是一个完整的EMAIL地址检验程序，它不能检验所有可能出现的情况，但在必要时您可以在其基础上增加所需功能。</p>
<table cellSpacing=0 cellPadding=5 width="100%" bgColor=#eeeeee border=1>
    <tbody>
        <tr>
            <td>
            <pre><code class=section><font face="Lucida Console">import <span class=hilite1>java</span>.util.regex.*;
            public class Email {
            public static void main(String[] args) throws Exception {
            String input = args[0];
            //检测输入的EMAIL地址是否以 非法符号"."或"@"作为起始字符
            Pattern p = Pattern.compile("^\\.|^\\@");
            Matcher m = p.matcher(input);
            if (m.find()){
            System.err.println("EMAIL地址不能以'.'或'@'作为起始字符");
            }
            //检测是否以"www."为起始
            p = Pattern.compile("^www\\.");
            m = p.matcher(input);
            if (m.find()) {
            System.out.println("EMAIL地址不能以'www.'起始");
            }
            //检测是否包含非法字符
            p = Pattern.compile("[^A-Za-z0-9\\.\\@_\\-~#]+");
            m = p.matcher(input);
            StringBuffer sb = new StringBuffer();
            boolean result = m.find();
            boolean deletedIllegalChars = false;
            while(result) {
            //如果找到了非法字符那么就设下标记
            deletedIllegalChars = true;
            //如果里面包含非法字符如冒号双引号等，那么就把他们消去，加到SB里面
            m.appendReplacement(sb, "");
            result = m.find();
            }
            m.appendTail(sb);
            input = sb.toString();
            if (deletedIllegalChars) {
            System.out.println("输入的EMAIL地址里包含有冒号、逗号等非法字符，请修改");
            System.out.println("您现在的输入为: "+args[0]);
            System.out.println("修改后合法的地址应类似: "+input);
            }
            }
            }</font></code></pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p>例如，我们在命令行输入：<span class=hilite1>java</span> Email www.kevin@163.net</p>
<p>那么输出结果将会是：EMAIL地址不能以'www.'起始</p>
<p>如果输入的EMAIL为@kevin@163.net</p>
<p>则输出为：EMAIL地址不能以'.'或'@'作为起始字符</p>
<p>当输入为：cgjmail#$%@163.net</p>
<p>那么输出就是：</p>
<pre>输入的EMAIL地址里包含有冒号、逗号等非法字符，请修改
您现在的输入为: cgjmail#$%@163.net
修改后合法的地址应类似: cgjmail@163.net</pre>
<img src ="http://www.cnitblog.com/sunnywang/aggbug/38397.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/sunnywang/" target="_blank">sunnywang   </a> 2008-01-02 22:10 <a href="http://www.cnitblog.com/sunnywang/archive/2008/01/02/38397.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>我最近的任务， 或说是作业吧</title><link>http://www.cnitblog.com/sunnywang/archive/2007/12/25/38078.html</link><dc:creator>sunnywang   </dc:creator><author>sunnywang   </author><pubDate>Tue, 25 Dec 2007 09:17:00 GMT</pubDate><guid>http://www.cnitblog.com/sunnywang/archive/2007/12/25/38078.html</guid><wfw:comment>http://www.cnitblog.com/sunnywang/comments/38078.html</wfw:comment><comments>http://www.cnitblog.com/sunnywang/archive/2007/12/25/38078.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cnitblog.com/sunnywang/comments/commentRss/38078.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/sunnywang/services/trackbacks/38078.html</trackback:ping><description><![CDATA[&nbsp;&nbsp; 我最近的任务是写两个servers <br>&nbsp; 1.日志代理服务<br>&nbsp;&nbsp;2.性能代理服务<br><br><br>&nbsp;这里我都可以根据之前我有的generalsocketserver 来实例化service ， 我可以直接写simpleservice 。<br>&nbsp;<br><br>这里主要是socket 编程， 当然了在server 端我们要做这几件事情：<br>&nbsp;1.将客户端的字节流读出来， 比较是不是预先约定好的格式， 比如说6个字段， 每个字段是什么类型， 长度， 等等。<br>&nbsp;2. 无论对错都想client端返回信息， &#8220;传送的数据正确， 已经入库&#8221;&#8220;上传的数据格式不对&#8221;&#8220;上传的数据中字段类型有误 &#8221;&#8220;上传的数据字段的个数有误&#8221;<br>3.在server端建立的服务， 每次都要链接到数据库， 向数据库中的指定表插入一条数据， 这时：要考虑是建立一个seesion<br>或是JNDI, 或是JDBC 来每次和数据库链接。<br><br><br>这里的知识是java socket编程。log4j 写日志， 要考虑到性能的问题， 在server端最好先将数据存起来，最后批量的处理。<br>&nbsp;client端的传输的协议， 要采用最简单的。<br><br><br>慢慢做吧。<br>
<img src ="http://www.cnitblog.com/sunnywang/aggbug/38078.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/sunnywang/" target="_blank">sunnywang   </a> 2007-12-25 17:17 <a href="http://www.cnitblog.com/sunnywang/archive/2007/12/25/38078.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java 的同步机制-- synchronized 关键字的使用</title><link>http://www.cnitblog.com/sunnywang/archive/2007/12/25/38076.html</link><dc:creator>sunnywang   </dc:creator><author>sunnywang   </author><pubDate>Tue, 25 Dec 2007 09:06:00 GMT</pubDate><guid>http://www.cnitblog.com/sunnywang/archive/2007/12/25/38076.html</guid><wfw:comment>http://www.cnitblog.com/sunnywang/comments/38076.html</wfw:comment><comments>http://www.cnitblog.com/sunnywang/archive/2007/12/25/38076.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/sunnywang/comments/commentRss/38076.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/sunnywang/services/trackbacks/38076.html</trackback:ping><description><![CDATA[<div>Java对多线程的支持与同步机制深受大家的喜爱，似乎看起来使用了synchronized关键字就可以轻松地解决多线程共享数据同步问题。到底如何？――还得对synchronized关键字的作用进行深入了解才可定论。</div>
<div>总的说来，synchronized关键字可以作为函数的修饰符，也可作为函数内的语句，也就是平时说的同步方法和同步语句块。如果再细的分类，synchronized可作用于instance变量、object reference（对象引用）、static函数和class literals(类名称字面常量)身上。</div>
<div>在进一步阐述之前，我们需要明确几点：</div>
<div>A．无论synchronized关键字加在方法上还是对象上，它取得的锁都是对象，而不是把一段代码或函数当作锁――而且同步方法很可能还会被其他线程的对象访问。</div>
<div>B．每个对象只有一个锁（lock）与之相关联。</div>
<div>C．实现同步是要很大的系统开销作为代价的，甚至可能造成死锁，所以尽量避免无谓的同步控制。</div>
<p>接着来讨论synchronized用到不同地方对代码产生的影响：
<div></div>
<div></div>
<p>假设P1、P2是同一个类的不同对象，这个类中定义了以下几种情况的同步块或同步方法，P1、P2就都可以调用它们。
<div></div>
<div></div>
<div>1．&nbsp; 把synchronized当作函数修饰符时，示例代码如下：</div>
<div>Public synchronized void methodAAA()</div>
<div>{</div>
<div>//&#8230;.</div>
<div>}</div>
<div>这也就是同步方法，那这时synchronized锁定的是哪个对象呢？它锁定的是调用这个同步方法对象。也就是说，当一个对象P1在不同的线程中执行这个同步方法时，它们之间会形成互斥，达到同步的效果。但是这个对象所属的Class所产生的另一对象P2却可以任意调用这个被加了synchronized关键字的方法。</div>
<div>上边的示例代码等同于如下代码：</div>
<div>public void methodAAA()</div>
<div>{</div>
<div>synchronized (this)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //&nbsp; (1)</div>
<div>{</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //&#8230;..</div>
<div>}</div>
<div>}</div>
<div>&nbsp;(1)处的this指的是什么呢？它指的就是调用这个方法的对象，如P1。可见同步方法实质是将synchronized作用于object reference。――那个拿到了P1对象锁的线程，才可以调用P1的同步方法，而对P2而言，P1这个锁与它毫不相干，程序也可能在这种情形下摆脱同步机制的控制，造成数据混乱：（</div>
<div>2．同步块，示例代码如下：</div>
<div>&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void method3(SomeObject so)</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; synchronized(so)</div>
<div>{</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //&#8230;..</div>
<div>}</div>
<div>}</div>
<div>这时，锁就是so这个对象，谁拿到这个锁谁就可以运行它所控制的那段代码。当有一个明确的对象作为锁时，就可以这样写程序，但当没有明确的对象作为锁，只是想让一段代码同步时，可以创建一个特殊的instance变量（它得是一个对象）来充当锁：</div>
<div>class Foo implements Runnable</div>
<div>{</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private byte[] lock = new byte[0];&nbsp; // 特殊的instance变量</div>
<div>&nbsp;&nbsp;&nbsp; Public void methodA()</div>
<div>{</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; synchronized(lock) { //&#8230; }</div>
<div>}</div>
<div>//&#8230;..</div>
<div>}</div>
<div>注：零长度的byte数组对象创建起来将比任何对象都经济――查看编译后的字节码：生成零长度的byte[]对象只需3条操作码，而Object lock = new Object()则需要7行操作码。</div>
<div>3．将synchronized作用于static 函数，示例代码如下：</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Class Foo </div>
<div>{</div>
<div>public synchronized static void methodAAA()&nbsp;&nbsp; // 同步的static 函数</div>
<div>{</div>
<div>//&#8230;.</div>
<div>}</div>
<div>public void methodBBB()</div>
<div>{</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; synchronized(Foo.class)&nbsp;&nbsp; //&nbsp; class literal(类名称字面常量)</div>
<div>}</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</div>
<div>&nbsp;&nbsp; 代码中的methodBBB()方法是把class literal作为锁的情况，它和同步的static函数产生的效果是一样的，取得的锁很特别，是当前调用这个方法的对象所属的类（Class，而不再是由这个Class产生的某个具体对象了）。</div>
<div>记得在《Effective Java》一书中看到过将 Foo.class和 P1.getClass()用于作同步锁还不一样，不能用P1.getClass()来达到锁这个Class的目的。P1指的是由Foo类产生的对象。</div>
<p>可以推断：如果一个类中定义了一个synchronized的static函数A，也定义了一个synchronized 的instance函数B，那么这个类的同一对象Obj在多线程中分别访问A和B两个方法时，不会构成同步，因为它们的锁都不一样。A方法的锁是Obj这个对象，而B的锁是Obj所属的那个Class。
<div></div>
<div></div>
<div>小结如下：</div>
<div>搞清楚synchronized锁定的是哪个对象，就能帮助我们设计更安全的多线程程序。</div>
<p>
<div>&nbsp;</div>
<div></div>
<div>还有一些技巧可以让我们对共享资源的同步访问更加安全：</div>
<div>1．&nbsp; 定义private 的instance变量+它的 get方法，而不要定义public/protected的instance变量。如果将变量定义为public，对象在外界可以绕过同步方法的控制而直接取得它，并改动它。这也是JavaBean的标准实现方式之一。</div>
<div>2．&nbsp; 如果instance变量是一个对象，如数组或ArrayList什么的，那上述方法仍然不安全，因为当外界对象通过get方法拿到这个instance对象的引用后，又将其指向另一个对象，那么这个private变量也就变了，岂不是很危险。 这个时候就需要将get方法也加上synchronized同步，并且，只返回这个private对象的clone()――这样，调用端得到的就是对象副本的引用了。</div>
<br>
<img src ="http://www.cnitblog.com/sunnywang/aggbug/38076.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/sunnywang/" target="_blank">sunnywang   </a> 2007-12-25 17:06 <a href="http://www.cnitblog.com/sunnywang/archive/2007/12/25/38076.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java 的多线程</title><link>http://www.cnitblog.com/sunnywang/archive/2007/12/24/38038.html</link><dc:creator>sunnywang   </dc:creator><author>sunnywang   </author><pubDate>Mon, 24 Dec 2007 08:07:00 GMT</pubDate><guid>http://www.cnitblog.com/sunnywang/archive/2007/12/24/38038.html</guid><wfw:comment>http://www.cnitblog.com/sunnywang/comments/38038.html</wfw:comment><comments>http://www.cnitblog.com/sunnywang/archive/2007/12/24/38038.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/sunnywang/comments/commentRss/38038.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/sunnywang/services/trackbacks/38038.html</trackback:ping><description><![CDATA[&nbsp;&nbsp; Java 是提供了多线程机制， 但是此机制比较的麻烦， <br>&nbsp; 当符合这几个条件时我们使用多线程， 否则我们完成可以考虑使用其他比较简单的或是循环来实现那些要求循环执行的程序。<br><br>&nbsp; 使用多线程的两个条件：<br>1. 多个程序并行执行。<br>2.多个程序混乱无序的执行。<br><br>这里有关于多线程的方方面面的介绍， 可以去看一下哦<br><a href="http://www.pconline.com.cn/pcjob/process/sun/article/0509/696138_5.html">http://www.pconline.com.cn/pcjob/process/sun/article/0509/696138_5.html</a>
<img src ="http://www.cnitblog.com/sunnywang/aggbug/38038.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/sunnywang/" target="_blank">sunnywang   </a> 2007-12-24 16:07 <a href="http://www.cnitblog.com/sunnywang/archive/2007/12/24/38038.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JAVA语言的socket编程</title><link>http://www.cnitblog.com/sunnywang/archive/2007/12/24/38032.html</link><dc:creator>sunnywang   </dc:creator><author>sunnywang   </author><pubDate>Mon, 24 Dec 2007 07:08:00 GMT</pubDate><guid>http://www.cnitblog.com/sunnywang/archive/2007/12/24/38032.html</guid><wfw:comment>http://www.cnitblog.com/sunnywang/comments/38032.html</wfw:comment><comments>http://www.cnitblog.com/sunnywang/archive/2007/12/24/38032.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/sunnywang/comments/commentRss/38032.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/sunnywang/services/trackbacks/38032.html</trackback:ping><description><![CDATA[什么是Socket
<p align=justify>Socket 接口是访问 Internet 使用得最广泛的方法。 如果你有一台刚配好TCP/IP协议的主机，其IP地址是202.120.127.201， 此时在另一台主机或同一台主机上执行ftp 202.120.127.201，显然无法建立连接。因为&#8220;202.120.127.201&#8221;</p>
<p align=justify>这台主机没有运行FTP服务软件。同样在另一台或同一台主机上运行浏览软件如Netscape，输入&#8220;http://202.120.127.201&#8221;，也无法建立连接。现在，如果在这台主机上运行一个FTP服务软件（该软件将打开一个Socket，并将其绑定到21端口），再在这台主机上运行一个Web 服务软件（该软件将打开另一个Socket，并将其绑定到80端口）。这样，在另一台主机或同一台主机上执行ftp 202.120.127.201，FTP客户软件将通过21端口来呼叫主机上由FTP 服务软件提供的Socket，与其建立连接并对话。而在netscape中输入&#8220;http://202.120.127.201&#8221;时，将通过80端口来呼叫主机上由Web服务软件提供的Socket，与其建立连接并对话。</p>
<p align=justify>&nbsp; 在Internet上有很多这样的主机，这些主机一般运行了多个服务软件，同时提供几种服务。每种服务都打开一个Socket，并绑定到一个端口上，不同的端口对应于不同的服务。Socket正如其英文原意那样，象一个多孔插座。一台主机犹如布满各种插座的房间，每个插座有一个编号，有的插座提供220伏交流电， 有的提供110伏交流电，有的则提供有线电视节目。 客户软件将插头插到不同编号的插座，就可以得到不同的服务。</p>
<p align=justify>&nbsp;&nbsp;&nbsp; 在Java语言中，提供了相应的Socket编程方法。用Java既可以编写服务端的程序，又可以编写客户端的程序。</p>
<p align=justify>二、编写服务端的程序</p>
<p align=justify>Java中的ServerSocket类提供了服务端的Socket接口。为了使大家对编写服务端程序有一个感性的认识，这里提供一个模拟FTP服务器的服务软件。 为了简洁起见，该程序只提供了最简单的建立FTP连接的功能。</p>
<p align=justify>该程序如下：</p>
<p align=justify>import java.io.*;</p>
<p align=justify>import java.net.*;</p>
<p align=justify>public class ftpserver{</p>
<p align=justify>public static void main(String args[])</p>
<p align=justify>{ try{ ServerSocket ftpserver = new ServerSocket(21);</p>
<p align=justify>Socket fs=ftpserver.accept();</p>
<p align=justify>PrintStream fs_out=new PrintStream(fs.getOutputStream());</p>
<p align=justify>DataInputStream fs_in=new DataInputStream(fs.getInputStream());</p>
<p align=justify>fs_out.println("Welcome to the test server");</p>
<p align=justify>System.out.println("got follow infor from client:"+fs_in.readLine());</p>
<p align=justify>fs_out.println("331 Please send Password");</p>
<p align=justify>System.out.println("got follow infor from client:"+fs_in.readLine());</p>
<p align=justify>fs_out.println("230 Login OK");</p>
<p align=justify>System.out.println("got follow infor from client:"+fs_in.readLine());</p>
<p align=justify>}</p>
<p align=justify>catch(Exception e)</p>
<p align=justify>{ System.out.println(e);</p>
<p align=justify>}</p>
<p align=justify>}</p>
<p align=justify>}</p>
<p align=justify>为了测试该程序，可以在一台安装了Windows 95并配置了TCP/IP协议的微机上进行（不一定要连入Internet）。在该微机上安装Java编译软件如JDK1.01 或JDK1.02（可在ftp://ftp.javasoft.com/pub/JDK-102-win32-x86.exe 下载），将上述程序存入文件ftpserver.java，执行&#8220;javac ftpserver.java&#8221;将其编译为字节码文件ftpserver.class。这样，只要在该微机上执行&#8220;java ftpserver.class&#8221;以运行该Java程序，该微机便成为一个模拟的FTP服务器。</p>
<p align=justify>测试该模拟FTP服务器，既可以在另一台联网的微机上进行， 也可以直接在该模拟FTP服务器上另开一个DOS窗口进行。运行命令行形式的FTP客户软件， 如在Windows 95的DOS窗口执行：ftp 202.120.127.201（如果你的Windows 95中配置TCP/IP协议时用的IP地址是其他值，需将这里的&#8220;202.120.127.201 &#8221;改为相应的值），便可以进行对话。下图是对话过程，其中带下划线的部分为用户的输入。</p>
<p align=justify>客户端</p>
<p align=justify>C:\xyx\java\sock\bak\ftp&gt;ftp 202.120.127.201</p>
<p align=justify>Connected to 202.120.127.201.</p>
<p align=justify>Welcome to the test server</p>
<p align=justify>User (202.120.127.201:(none)): anonymous</p>
<p align=justify>331 Please send Password</p>
<p align=justify>Password:xyx@yc.shu.edu.cn</p>
<p align=justify>230 Login OK</p>
<p align=justify>ftp&gt; bye</p>
<p align=justify>模拟FTP服务器</p>
<p align=justify>C:\xyx\java\sock\bak\ftp&gt;java ftpserver</p>
<p align=justify>got follow infor from client:USER anonymous</p>
<p align=justify>got follow infor from client:PASS xyx@yc.shu.edu.cn</p>
<p align=justify>got follow infor from client:QUIT</p>
<p align=justify>下面我们来看一看该模拟FTP服务器的编程方法。在上面的程序中， 关键部分是下面四句：</p>
<p align=justify>1. ServerSocket ftpserver = new ServerSocket(21);</p>
<p align=justify>2. Socket fs=ftpserver.accept();</p>
<p align=justify>3. PrintStream fs_out=new PrintStream(fs.getOutputStream());</p>
<p align=justify>4. DataInputStream fs_in=new DataInputStream(fs.getInputStream());</p>
<p align=justify>其中，第一句创建了一个服务端的Socket，并将其绑定到21端口。这样，服务端的Socket将一直等待客户端建立连接。这里的21端口是FTP服务惯用的端口，你也可以使用其他端口来提供自己的服务。第二句利用Java提供的方法accept()接收客户端的连接。第三句和第四句则为分别建立的连接打开一个输出和输入流。这四句可以作为编写服务端程序的一个范式，接下去的操作就是按照约定的协议对输出和输入流进行读写操作了。</p>
<p align=justify>在上面的程序中，对输出流fs_out用方法println("...")向客户端发送字符串，对输入流fs_in用方法readLine()获得客户端向服务端发送的字符串， 并用System.out.println("...")在服务器上显示出来。</p>
<p align=justify>向客户端发送信息和读取客户端发送来的信息必须按协议约定进行，这样，服务端和客户端之间才能顺利通讯。在上面的程序中，信息发送顺序是这样的：</p>
<p align=justify>1. 客户端连接后，服务端向客户端发送欢迎信息。这由程序中如下一行完成：</p>
<p align=justify>fs_out.println("Welcome to the test server");</p>
<p align=justify>2. 客户端显示服务端发送的信息，并提示用户输入帐号， 发送给服务端。在本例中，这由FTP客户软件完成。</p>
<p align=justify>3. 服务端接收客户端提供的帐号，向客户端发送结果码331，并提示需要口令。这由程序中如下两行完成：:</p>
<p align=justify>System.out.println("got follow infor from client:"+fs_in.readLine());</p>
<p align=justify>fs_out.println("331 Please send Password");</p>
<p align=justify>4. 客户端提示用户输入口令，并将口令发送给服务端。在本例中，这由FTP客户软件完成。</p>
<p align=justify>5. 服务端接收客户端提供的口令，向客户端发送结果码230，并提示注册成功。读取客户端发送命令。这由程序中如下两行完成：</p>
<p align=justify>fs_out.println("230 Login OK");</p>
<p align=justify>System.out.println("got follow infor from client:"+fs_in.readLine());</p>
<p align=justify>从以上我们可以看出客户端和服务端对话的简单过程，在这里，我们省略了服务端对用户及口令的检验以及根据客户端输入的不同命令执行各种操作。事实上，在上面的例子中既可以看到服务端如何向客户端发送信息，又可以看到服务端如何接收客户端的信息。因此，只要搞清楚双方对话的协议，便不难作出相应的编程。</p>
<p align=justify>三、编写客户端的程序</p>
<p align=justify>在上面的程序中，我们借用了Windows 95本身提供的FTP 客户软件来测试我们的模拟FTP服务程序。现在，我们要自己编写一个客户端的程序。 我们先编写一个简单的服务端程序和客户端程序，以理解服务端与客户端的通讯及其编程。</p>
<p align=justify>为简明起见， 我们使用一个自己定义的简单协议：服务器使用一个空闲的端口8886，客户端连接后：1. 服务端向客户端发送一个信息；2. 客户端读取服务端的信息并显示，再向服务端发送一个反馈信息；3.服务端读取客户端的反馈信息并显示。</p>
<p align=justify>对应于此协议，服务端的程序可如下：</p>
<p align=justify>import java.io.*;</p>
<p align=justify>import java.net.*;</p>
<p align=justify>public class server{</p>
<p align=justify>public static void main(String args[])</p>
<p align=justify>{ try { Server Socket server_1 = new Server Socket(8886);</p>
<p align=justify>Socket socket_s=server_1.accept();</p>
<p align=justify>Print Stream server_out=new Print Stream(socket_s.get Output Stream());</p>
<p align=justify>Data Input Stream server_in=new Data Input Stream(socket_s. getInputStream());</p>
<p align=justify>server_out.println("This is infor sent by server \r");</p>
<p align=justify>String s1=server_in.readLine();</p>
<p align=justify>System.out.println("Got follow infor from client:"+s1);</p>
<p align=justify>}</p>
<p align=justify>catch(Exception e)</p>
<p align=justify>{ System.out.println(e);</p>
<p align=justify>}</p>
<p align=justify>}</p>
<p align=justify>}</p>
<p align=justify>该例子与前面的模拟FTP服务器类似，不同的只是服务提供方使用的是 8886端口，此外由于使用的协议不同，对输入和输出流的操作不同。相应的客户端程序可如下：</p>
<p align=justify>import java.io.*;</p>
<p align=justify>import java.net.*;</p>
<p align=justify>public class client {</p>
<p align=justify>public static void main(String args[])</p>
<p align=justify>{ try</p>
<p align=justify>{ Socket sock_1 = new Socket("202.120.127.201", 8886);</p>
<p align=justify>DataInputStream client_in = new DataInputStream(sock_1.getInputStream());</p>
<p align=justify>DataOutputStream cl_out= new DataOutputStream(sock_1.getOutputStream());</p>
<p align=justify>PrintStream client_out=new PrintStream(cl_out);</p>
<p align=justify>String s1=client_in.readLine();</p>
<p align=justify>System.out.println("Got follow infor from server:"+s1);</p>
<p align=justify>client_out.println("This is infor sent by client \r");</p>
<p align=justify>}</p>
<p align=justify>catch(Exception e)</p>
<p align=justify>{ System.out.println(e);</p>
<p align=justify>}</p>
<p align=justify>}</p>
<p align=justify>}</p>
<p align=justify>这是一个简单的客户端程序的例子，其关键部分是下面四句：</p>
<p align=justify>1. Socket sock_1 = new Socket("202.120.127.201", 8886);</p>
<p align=justify>2. DataInputStream client_in = new DataInputStream(sock_1.getInputStream());</p>
<p align=justify>3. DataOutputStream cl_out= new DataOutputStream(sock_1.getOutputStream());</p>
<p align=justify>4. PrintStream client_out=new PrintStream(cl_out);</p>
<p align=justify>其中，第一句创建了一个客户端的Socket，从而与202.120.127.201主机建立一个连接。其中的8886为端口号，与服务端的Socket所绑定到的端口号相对应。第二至四句为Socket创建输入和输出流。这四句可以作为编写客户端程序的一个范式。接下去的操作同样是按照约定的协议对输出和输入流进行操作。上一程序中同样对输入流client_in用方法readLine()读取服务端发送的字符串，对输出流client_out用方法println("...")向服务端发送字符串。</p>
<p align=justify>上面两个程序编译后执行效果如下：</p>
<p align=justify>客户端</p>
<p align=justify>C:\xyx\java\sock\bak\c-both-s&gt;java client</p>
<p align=justify>Got follow infor from server:This is infor sent by server</p>
<p align=justify>服务端</p>
<p align=justify>C:\xyx\java\sock\bak\c-both-s&gt;java server</p>
<p align=justify>Got follow infor from client:This is infor sent by client</p>
<p align=justify>测试时既可以在同一台微机上开两个DOS窗口，也可以在两台联网的微机上进行。在上面的程序基础上，我们可以为前面的模拟FTP服务程序编写一个客户端程序：</p>
<p align=justify>import java.io.*;</p>
<p align=justify>import java.net.*;</p>
<p align=justify>public class ftpc {</p>
<p align=justify>public static void main(String[] args) </p>
<p align=justify>{ try {</p>
<p align=justify>Socket sock_1 = new Socket("202.120.127.201", 21);</p>
<p align=justify>DataInputStream client_in = new DataInputStream(sock_1.getInputStream());</p>
<p align=justify>DataOutputStream cl_out= new DataOutputStream(sock_1.getOutputStream());</p>
<p align=justify>PrintStream client_out=new PrintStream(cl_out);</p>
<p align=justify>StringBuffer buf = new StringBuffer(50);</p>
<p align=justify>int c;</p>
<p align=justify>String fromServer,usertyped;</p>
<p align=justify>while ((fromServer = client_in.readLine()) != null) {</p>
<p align=justify>System.out.println("Server: " + fromServer);</p>
<p align=justify>while ((c = System.in.read()) != '\n') {</p>
<p align=justify>buf.append((char)c);</p>
<p align=justify>}</p>
<p align=justify>usertyped=buf.toString();</p>
<p align=justify>client_out.println(usertyped);</p>
<p align=justify>client_out.flush();</p>
<p align=justify>buf.setLength(0);</p>
<p align=justify>}</p>
<p align=justify>} catch (Exception e) {</p>
<p align=justify>System.out.println(e);</p>
<p align=justify>}</p>
<p align=justify>}</p>
<p align=justify>}</p>
<p align=justify>该程序与前面的程序类似，不同之处在于该程序使用循环：</p>
<p align=justify>while ((fromServer = client_in.readLine()) != null) {</p>
<p align=justify>...}</p>
<p align=justify>反复读取服务端的输入，并用：</p>
<p align=justify>while ((c = System.in.read()) != '\n') {</p>
<p align=justify>buf.append((char)c);</p>
<p align=justify>}</p>
<p align=justify>usertyped=buf.toString();</p>
<p align=justify>client_out.println(usertyped);</p>
<p align=justify>语句读取用户的键盘输入，发送至服务端。其对话如下所示：</p>
<p align=justify>客户端</p>
<p align=justify>C:\xyx\java\sock\bak\ftp&gt;java ftpc</p>
<p align=justify>Server: Welcome to the test server</p>
<p align=justify>anonymous</p>
<p align=justify>Server: 331 Please send Password</p>
<p align=justify>xyx@yc.shu.edu.cn</p>
<p align=justify>Server: 230 Login OK</p>
<p align=justify>bye</p>
<p align=justify>服务端</p>
<p align=justify>C:\xyx\java\sock\bak\ftp&gt;java ftpserver</p>
<p align=justify>got follow infor from client:anonymous</p>
<p align=justify>got follow infor from client:xyx@yc.shu.edu.cn</p>
<p align=justify>got follow infor from client:bye</p>
<p align=justify>值得一提的是，该客户软件不仅可以和前面的模拟FTP服务器进行通讯，而且可以和真正的FTP服务器通讯。如将该客户软件中IP地址&#8220;202.120.127.201&#8221;改为某FTP服务器的IP地址：&#8220;202.120.127.218&#8221;，则可作如下的通讯：</p>
<p align=justify>C:\xyx\java\sock\bak\ftp&gt;javac ftpc</p>
<p align=justify>Server: 220 sun1000E-1 FTP server (UNIX(r) System V Release 4.0) ready.</p>
<p align=justify>USER anonymous</p>
<p align=justify>Server: 331 Guest login ok, send ident as password.</p>
<p align=justify>PASS xyx@yc.shu.edu.cn</p>
<p align=justify>Server: 230 Guest login ok, access restrictions apply.</p>
<p align=justify>QUIT</p>
<p align=justify>Server: 221 Goodbye.</p>
<p align=justify>其中，USER、PASS、QUIT分别为协议规定的用户帐号、口令及退出的命令。</p>
<p align=justify>四、处理客户端请求</p>
<p align=justify>以上的例子均只在服务端与客户端相互传送信息，在实用中，服务端应能对客户端不同的输入作出不同的响应。本节给出一个服务端处理客户端请求的例子，协议如下：客户连接后，服务端发送&#8220;Welcome to Time server&#8221;信息，客户端读取用户输入发送给服务端，如果客户端输入为Hours，则发送当前小时数至客户端；如果客户端输入为Minutes、Years、Month、Day、Time、Date、down，则分别发送分钟数、年份、月份、日期、时分秒、年月日至客户端；客户端输入down则结束会话。</p>
<p align=justify>其客户端仍采用上一节编写的模拟FTP服务器的客户程序，但需将程序中的端口21改为8885，以便与下面的服务端程序对话。服务端的程序修改如下：</p>
<p align=justify>import java.net.*;</p>
<p align=justify>import java.io.*;</p>
<p align=justify>import java.util.Date;</p>
<p align=justify>class server {</p>
<p align=justify>public static void main(String args[])</p>
<p align=justify>{ try {</p>
<p align=justify>ServerSocket server_Socket = new ServerSocket(8885);</p>
<p align=justify>Socket client_Socket = server_Socket.accept();</p>
<p align=justify>DataInputStream server_in = new DataInputStream(client_Socket.getInputStream());</p>
<p align=justify>PrintStream server_out = new PrintStream(client_Socket.getOutputStream());</p>
<p align=justify>String inputLine, outputLine;</p>
<p align=justify>server_out.println("Welcome to Time server");</p>
<p align=justify>server_out.flush();</p>
<p align=justify>Date t=new Date();</p>
<p align=justify>while ((inputLine = server_in.readLine()) != null) {</p>
<p align=justify>System.out.println("got"+inputLine);</p>
<p align=justify>String hours = String.valueOf(t.getHours());</p>
<p align=justify>String minutes = String.valueOf(t.getMinutes());</p>
<p align=justify>String seconds = String.valueOf(t.getSeconds());</p>
<p align=justify>String years = String.valueOf(t.getYear());</p>
<p align=justify>String month = String.valueOf(t.getMonth());</p>
<p align=justify>String day = String.valueOf(t.getDay());</p>
<p align=justify>if(inputLine.equalsIgnoreCase("Down"))</p>
<p align=justify>break;</p>
<p align=justify>else if(inputLine.equalsIgnoreCase("Hours"))</p>
<p align=justify>server_out.println("Current Hours is:"+hours);</p>
<p align=justify>else if(inputLine.equalsIgnoreCase("Minutes"))</p>
<p align=justify>server_out.println("Current Minutes is:"+minutes);</p>
<p align=justify>else if(inputLine.equalsIgnoreCase("Years"))</p>
<p align=justify>server_out.println("Current Years is:"+years);</p>
<p align=justify>else if(inputLine.equalsIgnoreCase("Month"))</p>
<p align=justify>server_out.println("Current Month is:"+month);</p>
<p align=justify>else if(inputLine.equalsIgnoreCase("Day"))</p>
<p align=justify>server_out.println("Current Day is:"+day);</p>
<p align=justify>else if(inputLine.equalsIgnoreCase("Time"))</p>
<p align=justify>server_out.println("Current Times is:"+hours+":"+minutes+":"+seconds);</p>
<p align=justify>else if(inputLine.equalsIgnoreCase("Date"))</p>
<p align=justify>server_out.println("Current Date is:"+years+"."+month+"."+day);</p>
<p align=justify>else server_out.println("I don't know");</p>
<p align=justify>server_out.flush();</p>
<p align=justify>}</p>
<p align=justify>}</p>
<p align=justify>catch(Exception e){</p>
<p align=justify>System.out.println(e);</p>
<p align=justify>}</p>
<p align=justify>}</p>
<p align=justify>}</p>
<p align=justify>在该程序中，使用类似前面客户端的方法，用一个循环</p>
<p align=justify>while ((inputLine = server_in.readLine()) != null) {</p>
<p align=justify>...}</p>
<p align=justify>反复读取客户端的信息。在循环中根据客户端传来的不同信息作不同的处理。</p>
<p align=justify>五、程序的优化</p>
<p align=justify>为了使程序更优化，可从以下方面入手：</p>
<p align=justify>1. 进行出错处理</p>
<p align=justify>如可对每句使用try{...}catch(...){...}的形式处理程序中的例外情况，恰当地返回出错信息或进行出错处理等。</p>
<p align=justify>2. 关闭打开的Socket和流</p>
<p align=justify>结束对话时将所打开的Socket和流都关闭，Java中的SeverScoket、Socket、DataInputStream及DataOutputStream类都提供了方法close()来实现此功能。</p>
<p align=justify>3. 支持多次连接</p>
<p align=justify>前面的服务端程序在结束一次对话后都将自动结束，如果再有客户端要建立连接需要重新执行服务端的程序。为了使服务端支持多次连接，只要用一个循环即可。如对前面所有的服务端程序，都可以将执行&#8220;accept()&#8221;的语句至&#8220;}catch(Exception e)&#8221;语句的前一行包含在while(true){...}的循环体中而使其支持多次连接。</p>
<p align=justify>4. 使用线程</p>
<p align=justify>服务端程序一般使用线程，以便在等待客户端连接时可以处理其他事情。此外，通过为每个客户端的请求分配一个新的线程，可以使服务端能够同时支持多个连接，并行处理客户端的请求。</p>
<p align=justify>〖参考资料〗</p>
<p align=justify>1. Mary Campione and Kathy Walrath, </p>
<p align=justify>"The Java Tutorial", </p>
<p align=justify>last updated 4 Mar 96.</p>
<p align=justify>ftp://ftp.javasoft.com/docs/tutorial.html.zip</p>
<p align=justify>2. Laura Lemay, </p>
<p align=justify>Charles L. Perkins, </p>
<p align=justify>"Teach Yourself JAVA in 21 Days"</p>
<p align=justify>3. "The Java Language Tutorial" </p>
<p align=justify>ftp://java.sun.com/docs/progGuide.html.zip </p>
<p align=justify>4. elharo@sunsite.unc.edu, </p>
<p align=justify>"Brewing Java: A Tutorial", </p>
<p align=justify>Last-modified: 1996/9/20,</p>
<img src ="http://www.cnitblog.com/sunnywang/aggbug/38032.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/sunnywang/" target="_blank">sunnywang   </a> 2007-12-24 15:08 <a href="http://www.cnitblog.com/sunnywang/archive/2007/12/24/38032.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>第一个JDBC程序</title><link>http://www.cnitblog.com/sunnywang/archive/2007/12/24/38030.html</link><dc:creator>sunnywang   </dc:creator><author>sunnywang   </author><pubDate>Mon, 24 Dec 2007 06:50:00 GMT</pubDate><guid>http://www.cnitblog.com/sunnywang/archive/2007/12/24/38030.html</guid><wfw:comment>http://www.cnitblog.com/sunnywang/comments/38030.html</wfw:comment><comments>http://www.cnitblog.com/sunnywang/archive/2007/12/24/38030.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/sunnywang/comments/commentRss/38030.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/sunnywang/services/trackbacks/38030.html</trackback:ping><description><![CDATA[本篇通过一个简单的数据库应用的例子告诉你如何编写你的第一个JDBC程序。<br><br>
<h3>一、JDBC简介</h3>
<br>　　相信在微软平台上开发过应用程序的朋友一定对ODBC不会陌生，ODBC是一种用C语言开发的API，通过它，你可以访问不同数据库平台上的数据,目前ODBC已经成为Windows环境下访问数据库的事实上的标准，也是一种基本方法。但是，由于ODBC的设计过于复杂，造成它很难对外扩展。JDBC是SUN开发的一种用来进行数据库访问的API，它借鉴了ODBC的的某些特点而没有它的复杂性，给数据库开发带来了极大的便利性。同时，JDBC还提供了对现存数据库API（比如ODBC）的调用，使得Java应用程序可以访问任何支持ODBC的数据库管理系统。<br><br>
<h3>二、开始</h3>
<br>&nbsp;&nbsp;&nbsp;&nbsp;下面这个简单的程序演示了如何在java中连接、打开和查询一个数据库。本例中以mysql为数据库平台。<br><br>
<div class=codeStyle>
<ol>
    <li><strong><font color=#0000ff>import</font></strong>&nbsp;java.sql.*;&nbsp;;&nbsp;
    <li>
    <li><strong><font color=#0000ff>public</font></strong>&nbsp;<strong><font color=#0000ff>class</font></strong>&nbsp;JDBCDemo{&nbsp;
    <li>&nbsp;&nbsp;&nbsp;&nbsp;<strong><font color=#0000ff>public</font></strong>&nbsp;<strong><font color=#0000ff>static</font></strong>&nbsp;<strong><font color=#0000ff>void</font></strong>&nbsp;main(<strong><a href="http://www.javazy.com/source/jdk142/java/lang/String.java.html" target=_blank><font class=classLink color=#0000ff><u>String</u></font></a></strong>[]&nbsp;args)&nbsp;{&nbsp;
    <li>&nbsp;&nbsp;&nbsp;&nbsp;<strong><a href="http://www.javazy.com/source/jdk142/java/lang/String.java.html" target=_blank><font class=classLink color=#0000ff><u>String</u></font></a></strong>&nbsp;driver=<font color=#ff33ff>"com.mysql.jdbc.Driver"</font>;&nbsp;&nbsp;&nbsp;&nbsp;<em><font color=#339900>//驱动程序</font></em>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;<strong><a href="http://www.javazy.com/source/jdk142/java/lang/String.java.html" target=_blank><font class=classLink color=#0000ff><u>String</u></font></a></strong>&nbsp;url=<font color=#ff33ff>"localhost/jive"</font>;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<em><font color=#339900>//数据库服务器地址及数据库名</font></em>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;<strong><a href="http://www.javazy.com/source/jdk142/java/sql/Connection.java.html" target=_blank><font class=classLink color=#0000ff><u>Connection</u></font></a></strong>&nbsp;con=<strong><font color=#0000ff>null</font></strong>;
    <li>&nbsp;&nbsp;&nbsp;&nbsp;<strong><a href="http://www.javazy.com/source/jdk142/java/sql/Statement.java.html" target=_blank><font class=classLink color=#0000ff><u>Statement</u></font></a></strong>&nbsp;st;
    <li>&nbsp;&nbsp;&nbsp;&nbsp;<strong><a href="http://www.javazy.com/source/jdk142/java/sql/ResultSet.java.html" target=_blank><font class=classLink color=#0000ff><u>ResultSet</u></font></a></strong>&nbsp;rs;
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong><font color=#0000ff>try</font></strong>&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<em><font color=#339900>//(1)</font></em>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong><a href="http://www.javazy.com/source/jdk142/java/lang/Class.java.html" target=_blank><font class=classLink color=#0000ff><u>Class</u></font></a></strong>.forName(driver).newInstance();&nbsp;
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<strong><font color=#0000ff>catch</font></strong>&nbsp;(<strong><a href="http://www.javazy.com/source/jdk142/java/lang/Exception.java.html" target=_blank><font class=classLink color=#0000ff><u>Exception</u></font></a></strong>&nbsp;ex)&nbsp;{&nbsp;
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<em><font color=#339900>//&nbsp;在这进行错误处理</font></em>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
    <li>&nbsp;&nbsp;&nbsp;&nbsp;<strong><font color=#0000ff>try</font></strong>{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<em><font color=#339900>//(2)</font></em>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;con=<strong><a href="http://www.javazy.com/source/jdk142/java/sql/DriverManager.java.html" target=_blank><font class=classLink color=#0000ff><u>DriverManager</u></font></a></strong>.getConnection(url,<font color=#ff33ff>"test"</font>,<font color=#ff33ff>"test"</font>);
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;st=con.createStatement();
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rs=st.executeQuery(<font color=#ff33ff>"Select&nbsp;*&nbsp;from&nbsp;jiveForums"</font>);
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong><font color=#0000ff>while</font></strong>(rs.next()){&nbsp;<em><font color=#339900>//查询结果处理</font></em>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong><a href="http://www.javazy.com/source/jdk142/java/lang/System.java.html" target=_blank><font class=classLink color=#0000ff><u>System</u></font></a></strong>.out.println(<font color=#ff33ff>"ID="</font>+rs.getString(1));
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong><a href="http://www.javazy.com/source/jdk142/java/lang/System.java.html" target=_blank><font class=classLink color=#0000ff><u>System</u></font></a></strong>.out.println(<font color=#ff33ff>"Name="</font>+rs.getString(2));
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<strong><font color=#0000ff>catch</font></strong>(<strong><a href="http://www.javazy.com/source/jdk142/java/lang/Exception.java.html" target=_blank><font class=classLink color=#0000ff><u>Exception</u></font></a></strong>&nbsp;e){
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<strong><font color=#0000ff>finally</font></strong>{
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong><font color=#0000ff>if</font></strong>(con==<strong><font color=#0000ff>null</font></strong>)<strong><font color=#0000ff>return</font></strong>;
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong><font color=#0000ff>try</font></strong>{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<em><font color=#339900>//(3)</font></em>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;con.close();
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<strong><font color=#0000ff>catch</font></strong>(<strong><a href="http://www.javazy.com/source/jdk142/java/lang/Exception.java.html" target=_blank><font class=classLink color=#0000ff><u>Exception</u></font></a></strong>&nbsp;e){
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
    <li>&nbsp;&nbsp;&nbsp;&nbsp;}
    <li>&nbsp;&nbsp;&nbsp;&nbsp;}
    <li>}</li>
</ol>
</div>
<br>程序的第一句导入我们需要用到的JDBC&nbsp;API，为了方便，我以*来导入在sql中定义的所有包，你也可以只指定你用到的包，比如：java.sql.Connection等。<br>在主函数中定义的两个字符串分别是驱动程序名和数据库服务器地址及数据库名。我在这里使用的是mysql数据库，所以我用的是mysql驱动程序,不同的数据库用不同的驱动程序，如果你用的不是mysql，请替换此行。<br>服务器地址是你安装数据库的主机的IP，如果在本机，你也可以用"localhost"来连接。数据库名是你已经在数据库系统中建立过的，这里是test.接着在标识为(1)的try块中装载驱动程序。这一步是为驱动程序来装载自己，然后让驱动程序管理器来进行管理，在(2)的try块中，从驱动程序管理器中取得一个连接，第一个引数已经说过，第二个引数是数据库中的用户名，最后一个是口令。接着创建一个Statement对象来执行查询，查询结果将返回一个记录集，在这里就是rs。在接下来的while循环中来处理查询结果，在这只是简单的打印出来。<br>在finally块中，将执行连接的关闭，如果在前面没有正确得到一个连接，将直接返回。<br>好了，修改这个程序以适应你的平台，然后执行。怎么样连接数据库就这么简单。<br><br>
<h3>三、注意事项</h3>
<br>&nbsp;&nbsp;&nbsp;1&nbsp;在上面这个程序中，请注意不要写错驱动程序名，如果出现找不到驱动程序的错误，请检查你的驱动程序是否在类搜索路径即CLASSPATH中，<br>一般你下载的驱动程序可能是以.jar为扩展名，那么你要把此文件包含在CLASSPATH中，比如我用的mysql.jar，那么在claspath中有：c:\driver\mysql.jar。<br>&nbsp;&nbsp;&nbsp;2&nbsp;数据库服务器IP要填准确，如果在本机，请直接使用localhost，用户名和口令是你用来操作数据库的用户和口令，不要认为是操作系统的用户名和口令。<br>&nbsp;&nbsp;&nbsp;3&nbsp;最后要注意，用完一个连接后要及时关闭，养成好的习惯。<br>
<img src ="http://www.cnitblog.com/sunnywang/aggbug/38030.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/sunnywang/" target="_blank">sunnywang   </a> 2007-12-24 14:50 <a href="http://www.cnitblog.com/sunnywang/archive/2007/12/24/38030.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>通过JDBC链接oracle 数据库的10种技巧</title><link>http://www.cnitblog.com/sunnywang/archive/2007/12/24/38029.html</link><dc:creator>sunnywang   </dc:creator><author>sunnywang   </author><pubDate>Mon, 24 Dec 2007 06:47:00 GMT</pubDate><guid>http://www.cnitblog.com/sunnywang/archive/2007/12/24/38029.html</guid><wfw:comment>http://www.cnitblog.com/sunnywang/comments/38029.html</wfw:comment><comments>http://www.cnitblog.com/sunnywang/archive/2007/12/24/38029.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/sunnywang/comments/commentRss/38029.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/sunnywang/services/trackbacks/38029.html</trackback:ping><description><![CDATA[<br>Java数据库连接（JDBC）API是一系列能够让Java编程人员访问数据库的接口，各个开发商的接口并不完全相同。在使用多年的Oracle公司的JDBC后，我积累了许多技巧，这些技巧能够使我们更好地发挥系统的性能和实现更多的功能。&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;1、在客户端软件开发中使用Thin驱动程序&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;在开发Java软件方面，Oracle的数据库提供了四种类型的驱动程序，二种用于应用软件、applets、servlets等客户端软件，另外二种用于数据库中的Java存储过程等服务器端软件。在客户机端软件的开发中，我们可以选择OCI驱动程序或Thin驱动程序。OCI驱动程序利用Java本地化接口（JNI），通过Oracle客户端软件与数据库进行通讯。Thin驱动程序是纯Java驱动程序，它直接与数据库进行通讯。为了获得最高的性能，Oracle建议在客户端软件的开发中使用OCI驱动程序，这似乎是正确的。但我建议使用Thin驱动程序，因为通过多次测试发现，在通常情况下，Thin驱动程序的性能都超过了OCI驱动程序。&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;2、关闭自动提交功能，提高系统性能&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;在第一次建立与数据库的连接时，在缺省情况下，连接是在自动提交模式下的。为了获得更好的性能，可以通过调用带布尔值false参数的Connection类的setAutoCommit()方法关闭自动提交功能，如下所示：&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;conn.setAutoCommit(false);&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;值得注意的是，一旦关闭了自动提交功能，我们就需要通过调用Connection类的commit()和rollback()方法来人工的方式对事务进行管理。&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;3、在动态SQL或有时间限制的命令中使用Statement对象&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;在执行SQL命令时，我们有二种选择：可以使用PreparedStatement对象，也可以使用Statement对象。无论多少次地使用同一个SQL命令，PreparedStatement都只对它解析和编译一次。当使用Statement对象时，每次执行一个SQL命令时，都会对它进行解析和编译。这可能会使你认为，使用PreparedStatement对象比使用Statement对象的速度更快。然而，我进行的测试表明，在客户端软件中，情况并非如此。因此，在有时间限制的SQL操作中，除非成批地处理SQL命令，我们应当考虑使用Statement对象。&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;此外，使用Statement对象也使得编写动态SQL命令更加简单，因为我们可以将字符串连接在一起，建立一个有效的SQL命令。因此，我认为，Statement对象可以使动态SQL命令的创建和执行变得更加简单。&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;4、利用helper函数对动态SQL命令进行格式化&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;在创建使用Statement对象执行的动态SQL命令时，我们需要处理一些格式化方面的问题。例如，如果我们想创建一个将名字O'Reilly插入表中的SQL命令，则必须使用二个相连的&#8220;''&#8221;号替换O'Reilly中的&#8220;'&#8221;号。完成这些工作的最好的方法是创建一个完成替换操作的helper方法，然后在连接字符串心服用公式表达一个SQL命令时，使用创建的helper方法。与此类似的是，我们可以让helper方法接受一个Date型的值，然后让它输出基于Oracle的to_date()函数的字符串表达式。&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;5、利用PreparedStatement对象提高数据库的总体效率&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;在使用PreparedStatement对象执行SQL命令时，命令被数据库进行解析和编译，然后被放到命令缓冲区。然后，每当执行同一个PreparedStatement对象时，它就会被再解析一次，但不会被再次编译。在缓冲区中可以发现预编译的命令，并且可以重新使用。在有大量用户的企业级应用软件中，经常会重复执行相同的SQL命令，使用PreparedStatement对象带来的编译次数的减少能够提高数据库的总体性能。如果不是在客户端创建、预备、执行PreparedStatement任务需要的时间长于Statement任务，我会建议在除动态SQL命令之外的所有情况下使用PreparedStatement对象。&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;6、在成批处理重复的插入或更新操作中使用PreparedStatement对象&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;如果成批地处理插入和更新操作，就能够显著地减少它们所需要的时间。Oracle提供的Statement和&nbsp;CallableStatement并不真正地支持批处理，只有PreparedStatement对象才真正地支持批处理。我们可以使用addBatch()和executeBatch()方法选择标准的JDBC批处理，或者通过利用PreparedStatement对象的setExecuteBatch()方法和标准的executeUpdate()方法选择速度更快的Oracle专有的方法。要使用Oracle专有的批处理机制，可以以如下所示的方式调用setExecuteBatch()：&nbsp;<br><br>PreparedStatement&nbsp;pstmt3D&nbsp;null;&nbsp;<br>try&nbsp;{&nbsp;<br>((OraclePreparedStatement)&nbsp;<br>pstmt).setExecuteBatch(30);&nbsp;<br>...&nbsp;<br>pstmt.executeUpdate();&nbsp;<br>}&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;调用setExecuteBatch()时指定的值是一个上限，当达到该值时，就会自动地引发SQL命令执行，标准的executeUpdate()方法就会被作为批处理送到数据库中。我们可以通过调用PreparedStatement类的sendBatch()方法随时传输批处理任务。&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;7、使用Oracle&nbsp;locator方法插入、更新大对象（LOB）&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;Oracle的PreparedStatement类不完全支持BLOB和CLOB等大对象的处理，尤其是Thin驱动程序不支持利用PreparedStatement对象的setObject()和setBinaryStream()方法设置BLOB的值，也不支持利用setCharacterStream()方法设置CLOB的值。只有locator本身中的方法才能够从数据库中获取LOB类型的值。可以使用PreparedStatement对象插入或更新LOB，但需要使用locator才能获取LOB的值。由于存在这二个问题，因此，我建议使用locator的方法来插入、更新或获取LOB的值。&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;8、使用SQL92语法调用存储过程&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;在调用存储过程时，我们可以使用SQL92或Oracle&nbsp;PL/SQL，由于使用Oracle&nbsp;PL/SQL并没有什么实际的好处，而且会给以后维护你的应用程序的开发人员带来麻烦，因此，我建议在调用存储过程时使用SQL92。&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;9、使用Object&nbsp;SQL将对象模式转移到数据库中&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;既然可以将Oracle的数据库作为一种面向对象的数据库来使用，就可以考虑将应用程序中的面向对象模式转到数据库中。目前的方法是创建Java&nbsp;bean作为伪装的数据库对象，将它们的属性映射到关系表中，然后在这些bean中添加方法。尽管这样作在Java中没有什么问题，但由于操作都是在数据库之外进行的，因此其他访问数据库的应用软件无法利用对象模式。如果利用Oracle的面向对象的技术，可以通过创建一个新的数据库对象类型在数据库中模仿其数据和操作，然后使用JPublisher等工具生成自己的Java&nbsp;bean类。如果使用这种方式，不但Java应用程序可以使用应用软件的对象模式，其他需要共享你的应用中的数据和操作的应用软件也可以使用应用软件中的对象模式。&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;10、利用SQL完成数据库内的操作&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;我要向大家介绍的最重要的经验是充分利用SQL的面向集合的方法来解决数据库处理需求，而不是使用Java等过程化的编程语言。&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;如果编程人员要在一个表中查找许多行，结果中的每个行都会查找其他表中的数据，最后，编程人员创建了独立的UPDATE命令来成批地更新第一个表中的数据。与此类似的任务可以通过在set子句中使用多列子查询而在一个UPDATE命令中完成。当能够在单一的SQL命令中完成任务，何必要让数据在网上流来流去的？我建议用户认真学习如何最大限度地发挥SQL的功能。<br><br>
<img src ="http://www.cnitblog.com/sunnywang/aggbug/38029.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/sunnywang/" target="_blank">sunnywang   </a> 2007-12-24 14:47 <a href="http://www.cnitblog.com/sunnywang/archive/2007/12/24/38029.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用JAVA实现FTP 服务器</title><link>http://www.cnitblog.com/sunnywang/archive/2007/12/24/38028.html</link><dc:creator>sunnywang   </dc:creator><author>sunnywang   </author><pubDate>Mon, 24 Dec 2007 06:43:00 GMT</pubDate><guid>http://www.cnitblog.com/sunnywang/archive/2007/12/24/38028.html</guid><wfw:comment>http://www.cnitblog.com/sunnywang/comments/38028.html</wfw:comment><comments>http://www.cnitblog.com/sunnywang/archive/2007/12/24/38028.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/sunnywang/comments/commentRss/38028.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/sunnywang/services/trackbacks/38028.html</trackback:ping><description><![CDATA[<table class=buttomBorder cellSpacing=3 cellPadding=3 width="100%" border=0>
    <tbody>
        <tr>
            <td class=contentTitle align=middle></td>
        </tr>
        <tr>
            <td align=middle></td>
        </tr>
        <tr>
            <td class=content vAlign=top align=left>
            <table class=rtable width="98%" border=0>
                <tbody>
                    <tr>
                        <td class=text align=left width="100%"><br>FTP&nbsp;命令&nbsp;<br><br>　　FTP&nbsp;的主要操作都是基于各种命令基础之上的。常用的命令有：&nbsp;<br><br>　　◆&nbsp;设置传输模式，它包括ASCⅡ(文本)&nbsp;和BINARY&nbsp;二进制模式;&nbsp;<br><br>&nbsp;<br>　　◆&nbsp;目录操作，改变或显示远程计算机的当前目录(cd、dir/ls&nbsp;命令);&nbsp;<br><br>　　◆&nbsp;连接操作，open命令用于建立同远程计算机的连接；close命令用于关闭连接;&nbsp;<br><br>　　◆&nbsp;发送操作，put命令用于传送文件到远程计算机；mput&nbsp;命令用于传送多个文件到远程计算机;&nbsp;<br><br>　　◆&nbsp;获取操作，get命令用于接收一个文件；mget命令用于接收多个文件。&nbsp;<br><br>　　编程思路&nbsp;<br><br>　　根据FTP&nbsp;的工作原理，在主函数中建立一个服务器套接字端口，等待客户端请求，一旦客户端请求被接受，服务器程序就建立一个服务器分线程，处理客户端的命令。如果客户端需要和服务器端进行文件的传输，则建立一个新的套接字连接来完成文件的操作。&nbsp;<br><br>　　编程技巧说明&nbsp;<br><br>　　1.主函数设计&nbsp;<br><br>　　在主函数中，完成服务器端口的侦听和服务线程的创建。我们利用一个静态字符串变量initDir&nbsp;来保存服务器线程运行时所在的工作目录。服务器的初始工作目录是由程序运行时用户输入的，缺省为C盘的根目录。&nbsp;<br><br>　　具体的代码如下：&nbsp;<br><br>public&nbsp;class&nbsp;ftpServer&nbsp;extends&nbsp;Thread{&nbsp;<br>private&nbsp;Socket&nbsp;socketClient;&nbsp;<br>private&nbsp;int&nbsp;counter;&nbsp;<br>private&nbsp;static&nbsp;String&nbsp;initDir;&nbsp;<br>public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args){&nbsp;<br>if(args.length&nbsp;!=&nbsp;0)&nbsp;{&nbsp;<br>initDir&nbsp;=&nbsp;args[0];&nbsp;<br>}else{&nbsp;initDir&nbsp;=&nbsp;"c:";}&nbsp;<br>int&nbsp;i&nbsp;=&nbsp;1;&nbsp;<br>try{&nbsp;<br>System.out.println("ftp&nbsp;server&nbsp;started!");&nbsp;<br>//监听21号端口&nbsp;<br>ServerSocket&nbsp;s&nbsp;=&nbsp;new&nbsp;ServerSocket(21);&nbsp;<br>for(;;){&nbsp;<br>//接受客户端请求&nbsp;<br>Socket&nbsp;incoming&nbsp;=&nbsp;s.accept();&nbsp;<br>//创建服务线程&nbsp;<br>new&nbsp;ftpServer(incoming,i).start();&nbsp;<br>i++;&nbsp;<br>}&nbsp;<br>}catch(Exception&nbsp;e){}&nbsp;<br>}&nbsp;<br>2.&nbsp;线程类的设计&nbsp;<br><br>　　线程类的主要设计都是在run()方法中实现。用run()方法得到客户端的套接字信息，根据套接字得到输入流和输出流，向客户端发送欢迎信息。&nbsp;<br><br>　　3.&nbsp;FTP&nbsp;命令的处理&nbsp;<br><br>　　(1)&nbsp;访问控制命令&nbsp;<br><br>　　◆&nbsp;user&nbsp;name(user)&nbsp;和&nbsp;password&nbsp;(pass)&nbsp;命令处理代码如下：&nbsp;<br><br>if(str.startsWith("USER")){&nbsp;<br>user&nbsp;=&nbsp;str.substring(4);&nbsp;<br>user&nbsp;=&nbsp;user.trim();&nbsp;<br>out.println("331&nbsp;Password");}&nbsp;<br>if(str.startsWith("PASS"))&nbsp;<br>out.println("230&nbsp;User&nbsp;"+user+"&nbsp;logged&nbsp;in.");&nbsp;<br><br>　　User&nbsp;命令和&nbsp;Password&nbsp;命令分别用来提交客户端用户输入的用户名和口令。&nbsp;<br><br>　　◆&nbsp;CWD&nbsp;(CHANGE&nbsp;WORKING&nbsp;DIRECTORY)&nbsp;命令处理代码如下：&nbsp;<br><br>if(str.startsWith("CWD")){&nbsp;<br>String&nbsp;str1&nbsp;=&nbsp;str.substring(3);&nbsp;<br>dir&nbsp;=&nbsp;dir+"/"+str1.trim();&nbsp;<br>out.println("250&nbsp;CWD&nbsp;command&nbsp;succesful");&nbsp;<br>}&nbsp;<br><br>　　该命令改变工作目录到用户指定的目录。&nbsp;<br><br>　　◆&nbsp;CDUP&nbsp;(CHANGE&nbsp;TO&nbsp;PARENT&nbsp;DIRECTORY)&nbsp;命令处理代码如下：&nbsp;<br><br>if(str.startsWith("CDUP")){&nbsp;<br>int&nbsp;n&nbsp;=&nbsp;dir.lastIndexOf("/");&nbsp;<br>dir&nbsp;=&nbsp;dir.substring(0,n);&nbsp;<br>out.println("250&nbsp;CWD&nbsp;command&nbsp;succesful");&nbsp;<br>}&nbsp;<br><br>　　该命令改变当前目录为上一层目录。&nbsp;<br><br>　　◆&nbsp;QUIT命令处理代码如下：&nbsp;<br><br>if(str.startsWith("QUIT"))&nbsp;{&nbsp;<br>out.println("GOOD&nbsp;BYE");&nbsp;<br>done&nbsp;=&nbsp;true;&nbsp;<br>}&nbsp;<br><br>　　该命令退出及关闭与服务器的连接，输出GOOD&nbsp;BYE。&nbsp;<br><br>　　(2)&nbsp;传输参数命令&nbsp;<br><br>　　◆&nbsp;Port命令处理代码如下：&nbsp;<br><br>if(str.startsWith("PORT"))&nbsp;{&nbsp;<br>out.println("200&nbsp;PORT&nbsp;command&nbsp;successful");&nbsp;<br>int&nbsp;i&nbsp;=&nbsp;str.length()&nbsp;-&nbsp;1;&nbsp;<br>int&nbsp;j&nbsp;=&nbsp;str.lastIndexOf(",");&nbsp;<br>int&nbsp;k&nbsp;=&nbsp;str.lastIndexOf(",",j-1);&nbsp;<br>String&nbsp;str1,str2;&nbsp;<br>str1="";&nbsp;<br>str2="";&nbsp;<br>for(int&nbsp;l=k+1;lstr1&nbsp;=&nbsp;str2&nbsp;+&nbsp;str.charAt(l);&nbsp;<br>}&nbsp;<br>for(int&nbsp;l=j+1;l&lt;=i;l++){&nbsp;<br>str2&nbsp;=&nbsp;str2&nbsp;+&nbsp;str.charAt(l);&nbsp;<br>}&nbsp;<br>tempPort&nbsp;=&nbsp;Integer.parseInt(str1)&nbsp;*&nbsp;16&nbsp;*16&nbsp;+Integer.parseInt(str2);&nbsp;<br>}&nbsp;<br><br>　　使用该命令时，客户端必须发送客户端用于接收数据的32位IP&nbsp;地址和16位&nbsp;的TCP&nbsp;端口号。这些信息以8位为一组，使用十进制传输，中间用逗号隔开。&nbsp;<br><br>　　◆&nbsp;TYPE命令处理代码如下：&nbsp;<br><br>if(str.startsWith("TYPE")){&nbsp;<br>out.println("200&nbsp;type&nbsp;set");&nbsp;<br>}&nbsp;<br><br><br>　　TYPE&nbsp;命令用来完成类型设置。&nbsp;<br><br>　　(3)&nbsp;FTP&nbsp;服务命令&nbsp;<br><br>　　◆&nbsp;RETR&nbsp;(RETEIEVE)&nbsp;和&nbsp;STORE&nbsp;(STORE)命令处理的代码&nbsp;<br><br>if(str.startsWith("RETR")){&nbsp;<br>out.println("150&nbsp;Binary&nbsp;data&nbsp;connection");&nbsp;<br>str&nbsp;=&nbsp;str.substring(4);&nbsp;<br>str&nbsp;=&nbsp;str.trim();&nbsp;<br>RandomAccessFile&nbsp;outFile&nbsp;=&nbsp;new&nbsp;<br>RandomAccessFile(dir+"/"+str,"r");&nbsp;<br>Socket&nbsp;tempSocket&nbsp;=&nbsp;new&nbsp;Socket(host,tempPort);&nbsp;<br>OutputStream&nbsp;outSocket&nbsp;<br>=&nbsp;tempSocket.getOutputStream();&nbsp;<br>byte&nbsp;byteBuffer[]=&nbsp;new&nbsp;byte[1024];&nbsp;<br>int&nbsp;amount;&nbsp;<br>try{&nbsp;<br>while((amount&nbsp;=&nbsp;outFile.read(byteBuffer))&nbsp;!=&nbsp;-1){&nbsp;<br>outSocket.write(byteBuffer,&nbsp;0,&nbsp;amount);&nbsp;<br>}&nbsp;<br>outSocket.close();&nbsp;<br>out.println("226&nbsp;transfer&nbsp;complete");&nbsp;<br>outFile.close();&nbsp;<br>tempSocket.close();&nbsp;<br>}&nbsp;<br>catch(IOException&nbsp;e){}&nbsp;<br>}&nbsp;<br>if(str.startsWith("STOR")){&nbsp;<br>out.println("150&nbsp;Binary&nbsp;data&nbsp;connection");&nbsp;<br>str&nbsp;=&nbsp;str.substring(4);&nbsp;<br>str&nbsp;=&nbsp;str.trim();&nbsp;<br>RandomAccessFile&nbsp;inFile&nbsp;=&nbsp;new&nbsp;<br>RandomAccessFile(dir+"/"+str,"rw");&nbsp;<br>Socket&nbsp;tempSocket&nbsp;=&nbsp;new&nbsp;Socket(host,tempPort);&nbsp;<br>InputStream&nbsp;inSocket&nbsp;<br>=&nbsp;tempSocket.getInputStream();&nbsp;<br>byte&nbsp;byteBuffer[]&nbsp;=&nbsp;new&nbsp;byte[1024];&nbsp;<br>int&nbsp;amount;&nbsp;<br>try{&nbsp;<br>while((amount&nbsp;=inSocket.read(byteBuffer)&nbsp;)!=&nbsp;-1){&nbsp;<br>inFile.write(byteBuffer,&nbsp;0,&nbsp;amount);&nbsp;<br>}&nbsp;<br>inSocket.close();&nbsp;<br>out.println("226&nbsp;transfer&nbsp;complete");&nbsp;<br>inFile.close();&nbsp;<br>tempSocket.close();&nbsp;<br>}&nbsp;<br>catch(IOException&nbsp;e){}&nbsp;<br>}&nbsp;<br><br>　　文件传输命令包括从服务器中获得文件RETR和向服务器中发送文件STOR，这两个命令的处理非常类似。处理RETR命令时，首先得到用户要获得的文件的名称，根据名称创建一个文件输入流，然后和客户端建立临时套接字连接，并得到一个输出流。随后，将文件输入流中的数据读出并借助于套接字输出流发送到客户端，传输完毕以后，关闭流和临时套接字。&nbsp;<br><br>　　STOR&nbsp;命令的处理也是同样的过程，只是方向正好相反。&nbsp;<br><br>　　◆&nbsp;DELE&nbsp;(DELETE)命令处理代码如下：&nbsp;<br><br>if(str.startsWith("DELE")){&nbsp;<br>str&nbsp;=&nbsp;str.substring(4);&nbsp;<br>str&nbsp;=&nbsp;str.trim();&nbsp;<br>File&nbsp;file&nbsp;=&nbsp;new&nbsp;File(dir,str);&nbsp;<br>boolean&nbsp;del&nbsp;=&nbsp;file.delete();&nbsp;<br>out.println("250&nbsp;delete&nbsp;command&nbsp;successful");&nbsp;<br>}&nbsp;<br><br>　　DELE&nbsp;命令用于删除服务器上的指定文件。&nbsp;<br><br>　　◆&nbsp;LIST命令处理代码如下：&nbsp;<br><br>if(str.startsWith("LIST"))&nbsp;{&nbsp;<br>try{&nbsp;<br>out.println("150&nbsp;ASCII&nbsp;data");&nbsp;<br>Socket&nbsp;tempSocket&nbsp;=&nbsp;new&nbsp;Socket(host,tempPort);&nbsp;<br>PrintWriter&nbsp;out2=&nbsp;new&nbsp;PrintWriter(tempSocket.getOutputStream(),true);&nbsp;<br>File&nbsp;file&nbsp;=&nbsp;new&nbsp;File(dir);&nbsp;<br>String[]&nbsp;dirStructure&nbsp;=&nbsp;new&nbsp;String[10];&nbsp;<br>dirStructure=&nbsp;file.list();&nbsp;<br>String&nbsp;strType="";&nbsp;<br>for(int&nbsp;i=0;iif(&nbsp;dirStructure[i].indexOf(".")&nbsp;==&nbsp;-1)&nbsp;{&nbsp;<br>strType&nbsp;=&nbsp;"d&nbsp;";}&nbsp;<br>else&nbsp;<br>{strType&nbsp;=&nbsp;"-&nbsp;";}&nbsp;<br>out2.println(strType+dirStructure[i]);&nbsp;<br>}&nbsp;<br>tempSocket.close();&nbsp;<br>out.println("226&nbsp;transfer&nbsp;complete");&nbsp;<br>}&nbsp;<br>catch(IOException&nbsp;e){}&nbsp;<br><br>　　LIST&nbsp;命令用于向客户端返回服务器中工作目录下的目录结构，包括文件和目录的列表。处理这个命令时，先创建一个临时的套接字向客户端发送目录信息。这个套接字的目的端口号缺省为1，然后为当前工作目录创建File&nbsp;对象，利用该对象的list()方法得到一个包含该目录下所有文件和子目录名称的字符串数组，然后根据名称中是否含有文件名中特有的&#8220;.&#8221;来区别目录和文件。最后，将得到的名称数组通过临时套接字发送到客户端。&nbsp;<br>--<br></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<img src ="http://www.cnitblog.com/sunnywang/aggbug/38028.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/sunnywang/" target="_blank">sunnywang   </a> 2007-12-24 14:43 <a href="http://www.cnitblog.com/sunnywang/archive/2007/12/24/38028.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>DES算法保护Java 源代码</title><link>http://www.cnitblog.com/sunnywang/archive/2007/12/24/38012.html</link><dc:creator>sunnywang   </dc:creator><author>sunnywang   </author><pubDate>Mon, 24 Dec 2007 01:46:00 GMT</pubDate><guid>http://www.cnitblog.com/sunnywang/archive/2007/12/24/38012.html</guid><wfw:comment>http://www.cnitblog.com/sunnywang/comments/38012.html</wfw:comment><comments>http://www.cnitblog.com/sunnywang/archive/2007/12/24/38012.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/sunnywang/comments/commentRss/38012.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/sunnywang/services/trackbacks/38012.html</trackback:ping><description><![CDATA[<table class=p11 cellSpacing=0 cellPadding=0 width=560 border=0>
    <tbody>
        <tr>
            <td style="WORD-WRAP: break-word" align=left>
            <p class=a14c style="TEXT-INDENT: 2em"><font face=Arial color=#30569d></font><span class=a14c id=zoom>
            <p style="TEXT-INDENT: 2em"><font face=Arial color=#30569d></font>
            <p><font face="Times New Roman" size=3>摘 要：本文首先分析了Java源代码需要加密的原因，简要介绍了DES算法及Java密码体系和Java密码扩展，最后说明了利用DES加密算法保护Java源代码的方法及步骤。</font></p>
            <p><font face="Times New Roman" size=3>　　关键词 Java 加密 DES算法</font></p>
            <p><font face="Times New Roman" size=3>　　Java语言是一种非常适用于网络编程的语言，它的基本结构与C++极为相似，但抛弃了C/C++中指针等内容，同时它吸收了Smalltalk、C++面向对象的编程思想。它具有简单性、鲁棒性、可移植性、动态性等特点。这些特点使得Java成为跨平台应用开发的一种规范，在世界范围内广泛流传。</font></p>
            <p><font face="Times New Roman" size=3>　　加密Java源码的原因</font></p>
            <p><font face="Times New Roman" size=3>　　Java源代码经过编译以后在JVM中执行。由于JVM界面是完全透明的，Java类文件能够很容易通过反编译器重新转换成源代码。因此，所有的算法、类文件等都可以以源代码的形式被公开，使得软件不能受到保护，为了保护产权，一般可以有以下几种方法：</font></p>
            <p><font face="Times New Roman" size=3>　　（1）"模糊"类文件，加大反编译器反编译源代码文件的难度。然而，可以修改反编译器，使之能够处理这些模糊类文件。所以仅仅依赖"模糊类文件"来保证代码的安全是不够的。</font></p>
            <p><font face="Times New Roman" size=3>　　（2）流行的加密工具对源文件进行加密，比如PGP（Pretty Good Privacy）或GPG（GNU Privacy Guard）。这时，最终用户在运行应用之前必须先进行解密。但解密之后，最终用户就有了一份不加密的类文件，这和事先不进行加密没有什么差别。</font></p>
            <p><font face="Times New Roman" size=3>　　（3）加密类文件，在运行中JVM用定制的类装载器（Class Loader）解密类文件。Java运行时装入字节码的机制隐含地意味着可以对字节码进行修改。JVM每次装入类文件时都需要一个称为ClassLoader的对象，这个对象负责把新的类装入正在运行的JVM。JVM给ClassLoader一个包含了待装入类（例如java.lang.Object）名字的字符串，然后由ClassLoader负责找到类文件，装入原始数据，并把它转换成一个Class对象。</font></p>
            <p><font face="Times New Roman" size=3>　　用户下载的是加密过的类文件，在加密类文件装入之时进行解密，因此可以看成是一种即时解密器。由于解密后的字节码文件永远不会保存到文件系统，所以窃密者很难得到解密后的代码。 </font></p>
            <p><font face="Times New Roman" size=3>　　由于把原始字节码转换成Class对象的过程完全由系统负责，所以创建定制ClassLoader对象其实并不困难，只需先获得原始数据，接着就可以进行包含解密在内的任何转换。</font></p>
            <p><font face="Times New Roman" size=3>　　Java密码体系和Java密码扩展</font></p>
            <p><font face="Times New Roman" size=3>　　Java密码体系(JCA)和Java密码扩展(JCE)的设计目的是为Java提供与实现无关的加密函数API。它们都用factory方法来创建类的例程，然后把实际的加密函数委托给提供者指定的底层引擎,引擎中为类提供了服务提供者接口在Java中实现数据的加密/解密，是使用其内置的JCE(Java加密扩展)来实现的。Java开发工具集1.1为实现包括数字签名和信息摘要在内的加密功能，推出了一种基于供应商的新型灵活应用编程接口。Java密码体系结构支持供应商的互操作,同时支持硬件和软件实现。</font></p>
            <p><font face="Times New Roman" size=3>　　Java密码学结构设计遵循两个原则:</font></p>
            <p><font face="Times New Roman" size=3>　　(1)算法的独立性和可靠性。</font></p>
            <p><font face="Times New Roman" size=3>　　(2)实现的独立性和相互作用性。</font></p>
            <p><font face="Times New Roman" size=3>　　算法的独立性是通过定义密码服务类来获得。用户只需了解密码算法的概念,而不用去关心如何实现这些概念。实现的独立性和相互作用性通过密码服务提供器来实现。密码服务提供器是实现一个或多个密码服务的一个或多个程序包。软件开发商根据一定接口,将各种算法实现后,打包成一个提供器,用户可以安装不同的提供器。安装和配置提供器,可将包含提供器的ZIP和JAR文件放在CLASSPATH下,再编辑Java安全属性文件来设置定义一个提供器。Java运行环境Sun版本时, 提供一个缺省的提供器Sun。</font></p>
            <p><font face="Times New Roman" size=3>　　下面介绍DES算法及如何利用DES算法加密和解密类文件的步骤。</font></p>
            <p><font face="Times New Roman" size=3>　　DES算法简介</font></p>
            <p><font face="Times New Roman" size=3>　　DES（Data Encryption Standard）是发明最早的最广泛使用的分组对称加密算法。DES算法的入口参数有三个：Key、Data、Mode。其中Key为8个字节共64位，是DES算法的工作密钥；Data也为8个字节64位，是要被加密或被解密的数据；Mode为DES的工作方式，有两种：加密或解密。</font></p>
            <p><font face="Times New Roman" size=3>　　DES算法工作流程如下：若Mode为加密模式，则利用Key 对数据Data进行加密， 生成Data的密码形式（64位）作为DES的输出结果；如Mode为解密模式，则利用Key对密码形式的数据Data进行解密，还原为Data的明码形式（64位）作为DES的输出结果。在通信网络的两端，双方约定一致的Key，在通信的源点用Key对核心数据进行DES加密，然后以密码形式在公共通信网（如电话网）中传输到通信网络的终点，数据到达目的地后，用同样的Key对密码数据进行解密，便再现了明码形式的核心数据。这样，便保证了核心数据在公共通信网中传输的安全性和可靠性。</font></p>
            <p><font face="Times New Roman" size=3>　　也可以通过定期在通信网络的源端和目的端同时改用新的Key，便能更进一步提高数据的保密性。<br>　　利用DES算法加密的步骤</font></p>
            <p><font face="Times New Roman" size=3>　　（1）生成一个安全密钥。在加密或解密任何数据之前需要有一个密钥。密钥是随同被加密的应用程序一起发布的一段数据，密钥代码如下所示。</font></p>
            <p><font face="Times New Roman" size=3>　　【生成一个密钥代码】</font></p>
            <p><font face="Times New Roman" size=3>// 生成一个可信任的随机数源<br>Secure Random sr = new SecureRandom();<br>// 为我们选择的DES算法生成一个KeyGenerator对象<br>KeyGenerator kg = KeyGenerator.getInstance ("DES" );<br>Kg.init (sr);<br>// 生成密钥<br>Secret Key key = kg.generateKey();<br>// 将密钥数据保存为文件供以后使用，其中key Filename为保存的文件名<br>Util.writeFile (key Filename, key.getEncoded () ); </font></p>
            <p><font face="Times New Roman" size=3>　　（2）加密数据。得到密钥之后，接下来就可以用它加密数据。如下所示。</font></p>
            <p><font face="Times New Roman" size=3>　　【用密钥加密原始数据】</font></p>
            <p><font face="Times New Roman" size=3>// 产生一个可信任的随机数源<br>SecureRandom sr = new SecureRandom();<br>//从密钥文件key Filename中得到密钥数据<br>Byte rawKeyData [] = Util.readFile (key Filename);<br>// 从原始密钥数据创建DESKeySpec对象<br>DESKeySpec dks = new DESKeySpec (rawKeyData);<br>// 创建一个密钥工厂，然后用它把DESKeySpec转换成Secret Key对象<br>SecretKeyFactory key Factory = SecretKeyFactory.getInstance("DES" );<br>Secret Key key = keyFactory.generateSecret( dks );<br>// Cipher对象实际完成加密操作<br>Cipher cipher = Cipher.getInstance( "DES" );<br>// 用密钥初始化Cipher对象<br>cipher.init( Cipher.ENCRYPT_MODE, key, sr );<br>// 通过读类文件获取需要加密的数据<br>Byte data [] = Util.readFile (filename);<br>// 执行加密操作<br>Byte encryptedClassData [] = cipher.doFinal(data );<br>// 保存加密后的文件，覆盖原有的类文件。 <br>Util.writeFile( filename, encryptedClassData ); </font></p>
            <p><font face="Times New Roman" size=3>　　（3）解密数据。运行经过加密的程序时，ClassLoader分析并解密类文件。操作步骤如下所示。 </font></p>
            <p><font face="Times New Roman" size=3>　　【用密钥解密数据】</font></p>
            <p><font face="Times New Roman" size=3>// 生成一个可信任的随机数源<br>SecureRandom sr = new SecureRandom();<br>// 从密钥文件中获取原始密钥数据<br>Byte rawKeyData[] = Util.readFile( keyFilename );<br>// 创建一个DESKeySpec对象<br>DESKeySpec dks = new DESKeySpec (rawKeyData);<br>// 创建一个密钥工厂，然后用它把DESKeySpec对象转换成Secret Key对象 <br>SecretKeyFactory key Factory = SecretKeyFactory.getInstance( "DES" );<br>SecretKey key = keyFactory.generateSecret( dks );<br>// Cipher对象实际完成解密操作<br>Cipher cipher = Cipher.getInstance( "DES" );<br>// 用密钥初始化Cipher对象<br>Cipher.init( Cipher.DECRYPT_MODE, key, sr );<br>// 获得经过加密的数据<br>Byte encrypted Data [] = Util.readFile (Filename);<br>//执行解密操作<br>Byte decryptedData [] = cipher.doFinal( encryptedData );<br>// 然后将解密后的数据转化成原来的类文件。 </font></p>
            <p><font face="Times New Roman" size=3>　　将上述代码与自定义的类装载器结合就可以做到边解密边运行，从而起到保护源代码的作用。</font></p>
            <p><font face="Times New Roman" size=3>　　结束语</font></p>
            <p><font face="Times New Roman" size=3>　　加密/解密是数据传输中保证数据安全性和完整性的常用方法，Java语言因其平台无关性，在Internet上的应用非常之广泛。使用DES算法加密Java源码在一定程度上能保护软件的产权。</font></p>
            </span></td>
        </tr>
    </tbody>
</table>
<img src ="http://www.cnitblog.com/sunnywang/aggbug/38012.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/sunnywang/" target="_blank">sunnywang   </a> 2007-12-24 09:46 <a href="http://www.cnitblog.com/sunnywang/archive/2007/12/24/38012.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>设计模式</title><link>http://www.cnitblog.com/sunnywang/archive/2007/12/10/37555.html</link><dc:creator>sunnywang   </dc:creator><author>sunnywang   </author><pubDate>Mon, 10 Dec 2007 10:07:00 GMT</pubDate><guid>http://www.cnitblog.com/sunnywang/archive/2007/12/10/37555.html</guid><wfw:comment>http://www.cnitblog.com/sunnywang/comments/37555.html</wfw:comment><comments>http://www.cnitblog.com/sunnywang/archive/2007/12/10/37555.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/sunnywang/comments/commentRss/37555.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/sunnywang/services/trackbacks/37555.html</trackback:ping><description><![CDATA[<table style="TABLE-LAYOUT: fixed">
    <tbody>
        <tr>
            <td>
            <div class=cnt>
            <p>整个设计模式贯穿一个原理:面对接口编程，而不是面对实现.目标原则是:降低耦合,增强灵活性.&nbsp;&nbsp;<br>一些基本的设计模式<br><br>Abstract Factory：提供一个创建一系列相关或相互依赖对象的接口，而无需指定它们具体的类。（使用得非常频繁。）<br><br>Adapter：将一个类的接口转换成客户希望的另外一个接口。A d a p t e r模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。<br><br>Bridge：将抽象部分与它的实现部分分离，使它们都可以独立地变化。<br><br>Builder：将一个复杂对象的构建与它的表示分离，使得同样的构建过程可以创建不同的表示。<br><br>Chain of Responsibility：为解除请求的发送者和接收者之间耦合，而使多个对象都有机会处理这个请求。将这些对象连成一条链，并沿着这条链传递该请求，直到有一个对象处理它。<br><br>Command：将一个请求封装为一个对象，从而使你可用不同的请求对客户进行参数化；对请求排队或记录请求日志，以及支持可取消的操作。<br><br>Composite：将对象组合成树形结构以表示&#8220;部分-整体&#8221;的层次结构。它使得客户对单个对象和复合对象的使用具有一致性。<br><br>Decorator：动态地给一个对象添加一些额外的职责。就扩展功能而言， 它比生成子类方式更为灵活。<br><br>Facade：为子系统中的一组接口提供一个一致的界面， F a c a d e模式定义了一个高层接口，这个接口使得这一子系统更加容易使用。<br><br>Factory Method：定义一个用于创建对象的接口，让子类决定将哪一个类实例化。Factory Method使一个类的实例化延迟到其子类。<br><br>Flyweight：运用共享技术有效地支持大量细粒度的对象。<br><br>Interpreter：给定一个语言, 定义它的文法的一种表示，并定义一个解释器, 该解释器使用该表示来解释语言中的句子。<br><br>Iterator：提供一种方法顺序访问一个聚合对象中各个元素, 而又不需暴露该对象的内部表示。<br><br>Mediator：用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用，从而使其耦合松散，而且可以独立地改变它们之间的交互。<br><br>Memento：在不破坏封装性的前提下，捕获一个对象的内部状态，并在该对象之外保存这个状态。这样以后就可将该对象恢复到保存的状态。<br><br>Observer：定义对象间的一种一对多的依赖关系,以便当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动刷新。<br><br>Prototype：用原型实例指定创建对象的种类，并且通过拷贝这个原型来创建新的对象。<br><br>Proxy：为其他对象提供一个代理以控制对这个对象的访问。<br><br><span style="COLOR: red">Singleton</span>：保证一个类仅有一个实例，并提供一个访问它的全局访问点。<br>State：允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它所属的类。<br><br>Strategy：定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。本模式使得算法的变化可独立于使用它的客户。<br><br>Template Method：定义一个操作中的算法的骨架，而将一些步骤延迟到子类中。Template Method使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。<br><br>Visitor：表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。</p>
            </div>
            </td>
        </tr>
    </tbody>
</table>
<p>附：<a href="http://tianleiwu.spaces.live.com/blog/cns!c00b51ce0ad262d7!1456.entry"><u><font color=#0000ff>http://tianleiwu.spaces.live.com/blog/cns!c00b51ce0ad262d7!1456.entry</font></u></a></p>
<p>设计模式的鼻祖(四个作者, 简称"四人帮")列举了23个模式, 但真正在开发中常用的模式有哪些呢? 今天我去给实习生做了一个讲座, 其中讨论到的一个问题就是这个.<br><br>我对一个搜索引擎的代码进行分析，结果如下：<br>最常用：Factory Method, Strategy, Singleton, Iterator<br><br>偶尔用：Abstract Factory, Builder, Adapter, Bridge, Composite, Interpreter, Command, Mediator, Observer, State<br><br>几乎不用: Prototype, Decorator, Flyweight, Facade, Proxy, Template Method, Chain of Responsibility, Memento, Visitor</p>
<img src ="http://www.cnitblog.com/sunnywang/aggbug/37555.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/sunnywang/" target="_blank">sunnywang   </a> 2007-12-10 18:07 <a href="http://www.cnitblog.com/sunnywang/archive/2007/12/10/37555.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用java实现ftp</title><link>http://www.cnitblog.com/sunnywang/archive/2007/12/03/37269.html</link><dc:creator>sunnywang   </dc:creator><author>sunnywang   </author><pubDate>Mon, 03 Dec 2007 06:00:00 GMT</pubDate><guid>http://www.cnitblog.com/sunnywang/archive/2007/12/03/37269.html</guid><wfw:comment>http://www.cnitblog.com/sunnywang/comments/37269.html</wfw:comment><comments>http://www.cnitblog.com/sunnywang/archive/2007/12/03/37269.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/sunnywang/comments/commentRss/37269.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/sunnywang/services/trackbacks/37269.html</trackback:ping><description><![CDATA[<strong>　FTP(File Transfer Protocol文件传输协议)是Internet上用来传送文件的协议。在Internet上通过FTP服务器可以进行文件的上传(Upload)或下载(Download)。FTP是实时联机服务，在使用它之前必须是具有该服务的一个用户(用户名和口令)，工作时客户端必须先登录到作为服务器一方的计算机上，用户登录后可以进行文件搜索和文件传送等有关操作，如改变当前工作目录、列文件目录、设置传输参数及传送文件等。使用FTP可以传送所有类型的文件，如文本文件、二进制可执行文件、图象文件、声音文件和数据压缩文件等。 <br>　　</strong><br><strong><em>　　</em>FTP 命令 </strong><br><em><em>　　</em></em>FTP 的主要操作都是基于各种命令基础之上的。常用的命令有： <br><em>　　</em>1、设置传输模式，它包括ASCⅡ(文本) 和BINARY 二进制模式; <br>　　2、目录操作，改变或显示远程计算机的当前目录(cd、dir/ls 命令); <br>　　3、连接操作，open命令用于建立同远程计算机的连接；close命令用于关闭连接; <br>　　4、发送操作，put命令用于传送文件到远程计算机；mput 命令用于传送多个文件到远程计算机; <br>　　5、获取操作，get命令用于接收一个文件；mget命令用于接收多个文件。 <br><br><em>　　</em><strong>编程思路 <br></strong><em>　　</em>根据FTP的工作原理，在主函数中建立一个服务器套接字端口，等待客户端请求，一旦客户端请求被接受，服务器程序就建立一个服务器分线程，处理客户端的命令。如果客户端需要和服务器端进行文件的传输，则建立一个新的套接字连接来完成文件的操作。 <br><br>　　<strong>编程技巧说明 <br></strong><em>　　</em>1.主函数设计 <br><em>　　</em>在主函数中，完成服务器端口的侦听和服务线程的创建。我们利用一个静态字符串变量initDir来保存服务器线程运行时所在的工作目录。服务器的初始工作目录是由程序运行时用户输入的，缺省为C盘的根目录。 <br>　　具体的代码如下： <br>　　public class ftpServer extends Thread{<br>　　private Socket socketClient;<br>　　private int counter;<br>　　private static String initDir;<br>　　public static void main(String[] args)<br>　　{<br>　　　　if(args.length != 0) {<br>　　　　　　initDir = args[0];<br>　　　　}<br>　　　　else{<br>　　　　　　 initDir = "c:";<br>　　　　}<br>　　　　int i = 1;<br>　　　　try{<br>　　　　　　System.out.println("ftp server started!");<br>　　　　　　//监听21号端口<br>　　　　　　ServerSocket s = new ServerSocket(21);<br>　　　　　　for(;;)<br>　　　　　　{<br>　　　　　　　　//接受客户端请求<br>　　　　　　　　Socket incoming = s.accept();<br>　　　　　　　　//创建服务线程<br>　　　　　　　　new ftpServer(incoming,i).start();<br>　　　　　　　　i++;<br>　　　　　　}<br>　　　　}catch(Exception e){}<br>　　}<br>
<img src ="http://www.cnitblog.com/sunnywang/aggbug/37269.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/sunnywang/" target="_blank">sunnywang   </a> 2007-12-03 14:00 <a href="http://www.cnitblog.com/sunnywang/archive/2007/12/03/37269.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>