﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-I wish you-文章分类-Java</title><link>http://www.blogjava.net/Iwishyou/category/5458.html</link><description>今天, 你java了吗</description><language>zh-cn</language><lastBuildDate>Thu, 01 Mar 2007 02:45:03 GMT</lastBuildDate><pubDate>Thu, 01 Mar 2007 02:45:03 GMT</pubDate><ttl>60</ttl><item><title>Spring 文档的连接</title><link>http://www.blogjava.net/Iwishyou/articles/70954.html</link><dc:creator>Iwishyou</dc:creator><author>Iwishyou</author><pubDate>Wed, 20 Sep 2006 15:24:00 GMT</pubDate><guid>http://www.blogjava.net/Iwishyou/articles/70954.html</guid><wfw:comment>http://www.blogjava.net/Iwishyou/comments/70954.html</wfw:comment><comments>http://www.blogjava.net/Iwishyou/articles/70954.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Iwishyou/comments/commentRss/70954.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Iwishyou/services/trackbacks/70954.html</trackback:ping><description><![CDATA[
		<br />中文文档<br />http://www.jactiongroup.net/reference/html/beans.html#beans-introduction<br /><br /><br />Spring论坛<br />http://spring.jactiongroup.net/<br /><img src ="http://www.blogjava.net/Iwishyou/aggbug/70954.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Iwishyou/" target="_blank">Iwishyou</a> 2006-09-20 23:24 <a href="http://www.blogjava.net/Iwishyou/articles/70954.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>系统是SQL优化</title><link>http://www.blogjava.net/Iwishyou/articles/52708.html</link><dc:creator>Iwishyou</dc:creator><author>Iwishyou</author><pubDate>Wed, 14 Jun 2006 05:40:00 GMT</pubDate><guid>http://www.blogjava.net/Iwishyou/articles/52708.html</guid><wfw:comment>http://www.blogjava.net/Iwishyou/comments/52708.html</wfw:comment><comments>http://www.blogjava.net/Iwishyou/articles/52708.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Iwishyou/comments/commentRss/52708.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Iwishyou/services/trackbacks/52708.html</trackback:ping><description><![CDATA[
		<p>
				<span class="postbody">JavaEye 看到的, 个人觉得很不错, 有机会碰到的时候可以参考一下, 优化系统的性能. <br /><br />帖子见: <a href="http://forum.javaeye.com/viewtopic.php?t=19464">http://forum.javaeye.com/viewtopic.php?t=19464</a><br /><br /><br />----------------------------------------------------------<br />信息系统访问量又不大，瓶颈一般不会出现在应用层，极有可能在数据库这一层，不用急着看程序。先找出逻辑读取次数最多的SQL，硬盘读取次数最多的SQL，找到SQL，对于SQL进行优化。看看有没有发生全表扫描的地方。 <br />一般发生全表扫描，极有可能是没有建立合理的索引，或者索引由于左边引用函数或其它原因造成索引失效。 <br />对于运行一年多的系统，最好要自己写一个自动重建索引的程序，定时重建索引。 <br />或者使用TOAD工具帮你重建索引。 <br /><br />另外在看一下数据库的CPU占用率，如果占用率在经常在80%－100%，那一定要是SQL或存储过程及trigger中写的不好。 <br /><br />不需要从应用层找SQL，方向性错误，太累，也看不出效果。 <br />而应当使用pl/SQL, toad等工具，分析出最bad的SQL语句，一看到这些语句后，再修改应用层的查询就是了。又快又方便。 <br /><br /><br /><br />-- 逻辑读多的SQL <br />select * from (select buffer_gets, sql_text <br />from v$sqlarea <br />where buffer_gets &gt; 500000 <br />order by buffer_gets desc) where rownum&lt;=30; <br /><br />-- 执行次数多的SQL <br />select sql_text,executions from <br />(select sql_text,executions from v$sqlarea order by executions desc) <br />where rownum&lt;81; <br /><br />-- 读硬盘多的SQL <br />select sql_text,disk_reads from <br />(select sql_text,disk_reads from v$sqlarea order by disk_reads desc) <br />where rownum&lt;21; <br /><br />-- 排序多的SQL <br />select sql_text,sorts from <br />(select sql_text,sorts from v$sqlarea order by sorts desc) <br />where rownum&lt;21; <br /><br />--分析的次数太多，执行的次数太少，要用绑变量的方法来写sql <br />set pagesize 600; <br />set linesize 120; <br />select substr(sql_text,1,80) "sql", count(*), sum(executions) "totexecs" <br />from v$sqlarea <br />where executions &lt; 5 <br />group by substr(sql_text,1,80) <br />having count(*) &gt; 30 <br />order by 2;</span>
		</p>
<img src ="http://www.blogjava.net/Iwishyou/aggbug/52708.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Iwishyou/" target="_blank">Iwishyou</a> 2006-06-14 13:40 <a href="http://www.blogjava.net/Iwishyou/articles/52708.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用javamail接收, 搜索email</title><link>http://www.blogjava.net/Iwishyou/articles/43209.html</link><dc:creator>Iwishyou</dc:creator><author>Iwishyou</author><pubDate>Wed, 26 Apr 2006 02:27:00 GMT</pubDate><guid>http://www.blogjava.net/Iwishyou/articles/43209.html</guid><wfw:comment>http://www.blogjava.net/Iwishyou/comments/43209.html</wfw:comment><comments>http://www.blogjava.net/Iwishyou/articles/43209.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Iwishyou/comments/commentRss/43209.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Iwishyou/services/trackbacks/43209.html</trackback:ping><description><![CDATA[从网上参考了一点, 然后自己写一点, 呵呵, 虽然简单, 但是很实用<br /><br />package helloworld;<br /><br />import java.sql.Connection;<br />import java.sql.SQLException;<br />import java.util.Date;<br />import java.util.LinkedList;<br />import java.util.List;<br />import java.util.Properties;<br /><br />import javax.mail.Authenticator;<br />import javax.mail.Folder;<br />import javax.mail.Message;<br />import javax.mail.MessagingException;<br />import javax.mail.PasswordAuthentication;<br />import javax.mail.Session;<br />import javax.mail.Store;<br />import javax.mail.search.SearchTerm;<br />import javax.mail.search.SentDateTerm;<br /><br />import org.apache.commons.logging.Log;<br />import org.apache.commons.logging.LogFactory;<br /><br />public class ReadSupportMailAgent extends Authenticator implements Runnable {//此段代码用来进行服务器对用户的认证  <br />    <br />    <br />    Log log = LogFactory.getLog(getClass().getName());<br />    <br />    String username=null;<br />    String host =null;<br />    String password=null;<br />    <br />    Properties props=null;<br />    Session session = null;<br />    <br />    boolean inited = false;<br />    Date latestSentDate = null;<br />    <br />    private static TypeConvert tc = new TypeConvert();<br />    <br />    public ReadSupportMailAgent(String host, String username, String password) {<br />        super();<br />        this.host = host;<br />        this.username = username;<br />        this.password = password;<br />    }<br /><br />    public PasswordAuthentication getPasswordAuthentication() {<br />        return new PasswordAuthentication(username, password);<br />    }<br /><br />    public static void main(String[] args) throws Exception {<br />        ReadSupportMailAgent gm = new ReadSupportMailAgent("pop3.126.com", "username","password");<br />        Thread t = new Thread(gm);<br />        t.start();<br />    }<br />    <br />    boolean exit = false;<br />    int interval = 1*60000;<br />    public void run() {<br />        while (!exit) {<br />            try {<br />                receive();<br />                Thread.sleep(interval);<br />            } catch (InterruptedException e) {<br />                log.debug("GetMail agent is interrupted.", e);<br />                exit = true;<br />                log.info("quit the agent.");<br />            } <br />        }<br />    }<br />    <br />    void receive()  {<br />        Folder folder = null;<br />        Store store = null;<br />        try {<br />            init();<br />            store = session.getStore("pop3");<br />            store.connect(host, username, password);<br /><br />            //open inbox in read_only mode  <br />            folder = store.getFolder("INBOX");  <br />            folder.open(Folder.READ_ONLY); //只读模式, 把邮件留在服务器上面<br /><br />            <br />            Message messages[];<br />            if(latestSentDate==null){ //本地没有记录最新的邮件的发送时间, 那么读取所有的邮件<br />                log.info("receiving all mails ... ");<br />                messages = folder.getMessages();<br /><br />            }else{ //搜索大于latestSentDate的邮件<br />                SearchTerm st = new SentDateTerm(SentDateTerm.GT, latestSentDate);<br />                log.info("start searching mails after " + showSentDate() );<br />                messages = folder.search(st);<br />            }<br />            log.info(messages.length+" mails received.");<br />            <br />            if(messages!=null &amp;&amp; messages.length&gt;0)<br />                processMessages(messages);<br />            <br />        } catch (Exception e) {<br />            e.printStackTrace();<br />        } finally {<br />            try {<br />                if(folder!=null)<br />                folder.close(true);  <br />                <br />                if(store!=null)<br />                store.close();<br />            } catch (MessagingException e) {<br />                e.printStackTrace();<br />            }<br />        }<br />    }<br /><br />    private void init() {<br />        if(!inited) {<br />            props = System.getProperties(); <br />            props.put("mail.smtp.host", host);<br />            props.put("mail.smtp.auth", "true");  <br />            session = Session.getDefaultInstance(props, this ); <br />            <br />              // 从某个地方读取上次接收邮件的最迟时间<br />              //this.latestSentDate = "2006-05-01";<br />            <br />              // 从某个地方读取循环检查新邮件的间隔时间<br />            String iInterval =  5 * 60000;//默认5分钟读取一次<br />            <br />            inited = true;<br />        }<br />    }<br /><br />    private void processMessages(Message[] message) throws MessagingException, SaksException {<br />        <br />        log.info("total mails: " + message.length);<br /><br />        Date tempSentDate = latestSentDate;<br />        <br />        List vs = new LinkedList();<br />        <br />        for (int i = 0, n = message.length; i &lt; n; i++) {<br />        <br />            String subject = message[i].getSubject();<br />            <br />            Date sentDate = message[i].getSentDate();<br />            tempSentDate = max(tempSentDate, sentDate); //记录邮件的最迟时间<br />                <br />              // 其他的处理代码 ....<br />        }<br />        <br />        //处理成功后, 更新这个时间<br />        latestSentDate = tempSentDate;<br />        <br />    }<br /><br />    private Date max(Date date1, Date date2) {<br />        if(date1==null)<br />            return date2;<br />        else if(date2==null)<br />            return date1;<br />        <br />        if(date1.after(date2))<br />            return date1;<br />        else<br />            return date2;<br />    }<br />    <br />    public String showSentDate() {<br />        // 格式化这个时间成为你想要的任何格式<br />        if(this.latestSentDate==null)return "";<br />         else <br />                return this.latestSentDate.toString();<br />    }<br />}<br /><br /><img src ="http://www.blogjava.net/Iwishyou/aggbug/43209.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Iwishyou/" target="_blank">Iwishyou</a> 2006-04-26 10:27 <a href="http://www.blogjava.net/Iwishyou/articles/43209.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MySQL 和 UTF-8</title><link>http://www.blogjava.net/Iwishyou/articles/40599.html</link><dc:creator>Iwishyou</dc:creator><author>Iwishyou</author><pubDate>Wed, 12 Apr 2006 03:52:00 GMT</pubDate><guid>http://www.blogjava.net/Iwishyou/articles/40599.html</guid><wfw:comment>http://www.blogjava.net/Iwishyou/comments/40599.html</wfw:comment><comments>http://www.blogjava.net/Iwishyou/articles/40599.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Iwishyou/comments/commentRss/40599.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Iwishyou/services/trackbacks/40599.html</trackback:ping><description><![CDATA[
		<p>
				<font size="2">MySQL 和 UTF-8<br /></font>
		</p>
		<p>
				<br />
		</p>
		<p>
				<font size="2">
						<br />
				</font>
		</p>
		<p>
				<font size="2">[此文是转载]<br /></font>
		</p>
		<p>
				<font size="2">最近看到好多关于MySql支持utf-8编码的问题，刚好自己也要用，去找了一下，没有写的很全面的。<br />整理了一下，供大家参考。</font>
		</p>
		<p>
				<font size="2">在一下服务器设置测试通过<br />服务器配置：<br />    window2000<br />    Tomcat 4.1,5.19<br />    Mysql 4.1, 5.0<br />    Java语言，JDK1.4.2<br />    数据库驱动mysql-connector-java-3.0.10-stable-bin.jar<br />    Struts1.1<br />    <br />开始前先看提示<br />MySQL数据库的4.1是一个分水岭，4.1直接支持Unicode，以下版本支持的不好； </font>
		</p>
		<p>
				<font size="2">MySQL
JDBC Driver的3.0.16也是一个分水岭，3.0.16版本会取数据库本身的编码，然后按照该编码转换，这种方式和Oracle的JDBC
Driver是一样的。例如你的数据库是GBK编码的话，JDBC
Driver就会把数据库里面的取出来的字符串按照GBK往unicode转换，送给JVM。因此正确的设置数据库本身的编码就尤为重要。 </font>
		</p>
		<p>
				<font size="2">MySQL
JDBC
Driver3.0.16以下的版本则不然，它不会那么智能的根据数据库编码来确定如何转换，它总是默认使用ISO8859-1，因此你必须使用
characterEncoding=GBK来强制他把数据库中取出来的字符串按照GBK来往unicode转换。 </font>
		</p>
		<p>
				<font size="2">因此，使用什么数据库版本，不管是3.x，还是4.0.x还是4.1.x，其实对我们来说不重要，重要的有二： </font>
		</p>
		<p>
				<font size="2">1)
正确的设定数据库编码，MySQL4.0以下版本的字符集总是默认ISO8859-1，MySQL4.1在安装的时候会让你选择。如果你准备使用UTF-
8，那么在创建数据库的时候就要指定好UTF-8(创建好以后也可以改，4.1以上版本还可以单独指定表的字符集) </font>
		</p>
		<p>
				<font size="2">2) 使用3.0.16以上版本的JDBC Driver，那么你就不需要再写什么characterEncoding=UTF-8</font>
		</p>
		<p>
				<font size="2">开始设置：<br />1.打开WinMysqlAdmin管理器，选择my.ini设置项，在[mysql]段加入一下代码<br />  default-character-set=utf8<br />  设置后重新启动MySQL服务。<br />  再打开 WinMysqlAdmin管理器，选择Variables项，查看一下变量的值是否如下<br />  character_set_server  = utf8<br />  character_set_system  = utf8<br />  character_set_database  = utf8<br />  character_set_client  = utf8<br />  character_set_connection  = utf8<br />  character_set_results = utf8<br />  <br />  collation_connection = utf8_general_ci<br />  collation_database = utf8_general_ci<br />  collation_server = utf8_general_ci<br />  <br />  如果不能重启Mysql服务，则可能拼写错误，检查一下<br />  以上变量的值都符合，恭喜你，设置成功</font>
		</p>
		<p>
				<font size="2">2.Java中调用数据库连接方法如下<br />  jdbc:mysql://192.168.1.87/mytest?useUnicode=true&amp;characterEncoding=utf8<br />  <br />  如果驱动使用3.0.16以上版本的JDBC Driver，那么你就不需要再写什么characterEncoding=UTF-8<br />  <br />3.在页面提交数据处理请看 </font>
				<a href="http://blog.csdn.net/feng_sundy/archive/2004/10/17/139647.aspx" target="_blank">
						<font size="2">"中文问题"，"struts国际化问题"——终极解决方案</font>
				</a>
				<font size="2"> 一文，非常清楚<br /><br />4.完成以上三步，你的系统就可以运行与UTF-8编码环境了。</font>
		</p>
<img src ="http://www.blogjava.net/Iwishyou/aggbug/40599.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Iwishyou/" target="_blank">Iwishyou</a> 2006-04-12 11:52 <a href="http://www.blogjava.net/Iwishyou/articles/40599.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>正则表达式</title><link>http://www.blogjava.net/Iwishyou/articles/39528.html</link><dc:creator>Iwishyou</dc:creator><author>Iwishyou</author><pubDate>Thu, 06 Apr 2006 02:16:00 GMT</pubDate><guid>http://www.blogjava.net/Iwishyou/articles/39528.html</guid><wfw:comment>http://www.blogjava.net/Iwishyou/comments/39528.html</wfw:comment><comments>http://www.blogjava.net/Iwishyou/articles/39528.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Iwishyou/comments/commentRss/39528.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Iwishyou/services/trackbacks/39528.html</trackback:ping><description><![CDATA[创建： <br />一个文本格式或正则表达式构造函数 <br />文本格式： /pattern/flags <br /><br />java的正则表达式构造函数： new RegExp("pattern"[,"flags"]); <br />参数说明： <br />pattern -- 一个正则表达式文本 <br />flags -- 如果存在，将是以下值： <br />g: 全局匹配 <br />i: 忽略大小写 <br />gi: 以上组合 <br /><br /><b>注意</b> 文本格式的参数不用引号，而在用构造函数时的参数需要引号'/'。<br />如：/ab+c/i 和 new RegExp("ab+c","i")是实现一样的功能。<br /><br />在构造函数中，一些特殊字符需要进行转意(在特殊字符前加"\")。<br />如：re = new RegExp("\\w+"), 表示要匹配 "\" 字符一次, "w"字符一次或者以上. 不过事实上, 在java里面, 特殊的"\" 字符也要写成 "\\", 所以代码类似:<br /><br />    String msg = "\\w";<br />    Pattern p = Pattern.compile("\\w{2}");<br /><br /><br />~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~<br />正则表达式中的特殊字符 <br /><br />字符  含意 <br />\        做为转意，即通常在"\"后面的字符不按原来意义解释，如/b/匹配字符"b"，<br />         当b前面加了反斜杆后/\b/，转意为匹配一个单词的边界。 <br />         例如: *  匹配它前面元字符0次或多次，/a*/将匹配a,aa,aaa，加了"\"后，/a\*/将只匹配"a*"。<br />         在java代码里面就是<br />            String msg = "aaabc";<br />
            Pattern p = Pattern.compile("a*"); --结果为true<br />            <strike>Pattern p = Pattern.compile("a\*"); --结果为false </strike><font color="#ff0000">需要修正</font><strike><br /><br /><br /><br /></strike>^       匹配一个输入或一行的开头，/^a/匹配"an A"，而不匹配"An a" <br />$      匹配一个输入或一行的结尾，/a$/匹配"An a"，而不匹配"an A" <br />*       匹配前面元字符0次或多次，/ba*/将匹配b,ba,baa,baaa <br />+      匹配前面元字符1次或多次，/ba*/将匹配ba,baa,baaa <br />?      匹配前面元字符0次或1次，/ba*/将匹配b,ba <br />.       <span style="font-family: 宋体;">句点符号匹配所有字符（一个），包括空格、</span><span style="" lang="EN-US">Tab</span><span style="font-family: 宋体;">字符甚至换行符。</span><br />(x)    匹配x保存x在名为$1...$9的变量中 <span style="background: yellow none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;" lang="EN-US"><br /></span><span style="" lang="EN-US"><span style="">()     </span></span><span style="font-family: 宋体;">分组，圆括号中的字符视为一个整体。</span><br />x|y    匹配x或y <br />{n}   精确匹配n次 <br />{n,}  匹配n次以上 <br />{n,m} 匹配n-m次 <br />[xyz] 字符集(character set)，匹配这个集合中的任一一个字符(或元字符) <br />[^xyz] 不匹配这个集合中的任何一个字符 <br />[\b] 匹配一个退格符 <br />\b 匹配一个单词的边界 <br />\B 匹配一个单词的非边界 <br />\cX 这儿，X是一个控制符，/\cM/匹配Ctrl-M <br />\d 匹配一个字数字符，/\d/ = /[0-9]/ <br />\D 匹配一个非字数字符，/\D/ = /[^0-9]/ <br />\n 匹配一个换行符 <br />\r 匹配一个回车符 <br />\s 匹配一个空白字符，包括\n,\r,\f,\t,\v等 <br />\S 匹配一个非空白字符，等于/[^\n\f\r\t\v]/ <br />\t 匹配一个制表符 <br />\v 匹配一个重直制表符 <br />\w 匹配一个可以组成单词的字符(alphanumeric，这是我的意译，含数字)，包括下划线，如[\w]匹配"$5.98"中的5，等于[a-zA-Z0-9] <br />\W 匹配一个不可以组成单词的字符，如[\W]匹配"$5.98"中的$，等于[^a-zA-Z0-9]。 <br /><br /><br />~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~<br />说了这么多了，我们来看一些正则表达式的实际应用的例子： <br /><br />E-mail地址验证: <br />function test_email(strEmail) { <br />var myReg = /^[_a-z0-9]+@([_a-z0-9]+\.)+[a-z0-9]{2,3}$/; <br />if(myReg.test(strEmail)) return true; <br />return false; <br />} <br />HTML代码的屏蔽 <br />function mask_HTMLCode(strInput) { <br />var myReg = /&lt;(\w+)&gt;/; <br />return strInput.replace(myReg, "&lt;$1&gt;"); <br />}<br /><br /><br />其他的一些例子:<br /><table class="MsoNormalTable" style="border-collapse: collapse;" border="0" cellpadding="0" cellspacing="0"><tbody><tr style=""><td style="border: 1pt solid windowtext; padding: 0cm 5.4pt; width: 69.65pt;" valign="top" width="93"><p class="MsoNormal"><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">regEx
  <o:p></o:p></span></p></td><td style="border-style: solid solid solid none; border-color: windowtext windowtext windowtext -moz-use-text-color; border-width: 1pt 1pt 1pt medium; padding: 0cm 5.4pt; width: 140.65pt;" valign="top" width="188"><p class="MsoNormal"><span style="font-size: 9pt;">匹配</span><span style="font-size: 9pt; font-family: Arial;"><span lang="EN-US"><o:p></o:p></span></span></p></td><td style="border-style: solid solid solid none; border-color: windowtext windowtext windowtext -moz-use-text-color; border-width: 1pt 1pt 1pt medium; padding: 0cm 5.4pt; width: 138.85pt;" valign="top" width="185"><p class="MsoNormal"><span style="font-size: 9pt;">测试用</span><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">str <o:p></o:p></span></p></td></tr><tr style=""><td style="border-style: none solid solid; border-color: -moz-use-text-color windowtext windowtext; border-width: medium 1pt 1pt; padding: 0cm 5.4pt; width: 69.65pt;" valign="top" width="93"><p class="MsoNormal"><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">(a|b){2}
  <o:p></o:p></span></p></td><td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 140.65pt;" valign="top" width="188"><p class="MsoNormal"><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">aa</span><span style="font-size: 9pt;">、</span><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">ab</span><span style="font-size: 9pt;">、</span><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">bb</span><span style="font-size: 9pt;">、</span><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">ba <o:p></o:p></span></p></td><td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 138.85pt;" valign="top" width="185"><p class="MsoNormal"><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">aabbfooaabfooabfoob
  <o:p></o:p></span></p></td></tr><tr style=""><td style="border-style: none solid solid; border-color: -moz-use-text-color windowtext windowtext; border-width: medium 1pt 1pt; padding: 0cm 5.4pt; width: 69.65pt;" valign="top" width="93"><p class="MsoNormal"><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">a[abc]b
  <o:p></o:p></span></p></td><td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 140.65pt;" valign="top" width="188"><p class="MsoNormal"><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">aab</span><span style="font-size: 9pt;">、</span><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">abb</span><span style="font-size: 9pt;">、</span><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">acb <o:p></o:p></span></p></td><td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 138.85pt;" valign="top" width="185"><p class="MsoNormal"><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">3dfacb5ooyfo6abbfooaab
  <o:p></o:p></span></p></td></tr><tr style=""><td style="border-style: none solid solid; border-color: -moz-use-text-color windowtext windowtext; border-width: medium 1pt 1pt; padding: 0cm 5.4pt; width: 69.65pt;" valign="top" width="93"><p class="MsoNormal"><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">.
  <o:p></o:p></span></p></td><td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 140.65pt;" valign="top" width="188"><p class="MsoNormal"><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">all
  string <o:p></o:p></span></p></td><td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 138.85pt;" valign="top" width="185"><p class="MsoNormal"><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">3dfac
  <o:p></o:p></span></p></td></tr><tr style=""><td style="border-style: none solid solid; border-color: -moz-use-text-color windowtext windowtext; border-width: medium 1pt 1pt; padding: 0cm 5.4pt; width: 69.65pt;" valign="top" width="93"><p class="MsoNormal"><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">a.
  <o:p></o:p></span></p></td><td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 140.65pt;" valign="top" width="188"><p class="MsoNormal"><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">aa</span><span style="font-size: 9pt;">、</span><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">ax……</span><span style="font-size: 9pt;">等等</span><span style="font-size: 9pt; font-family: Arial;"><span lang="EN-US"><o:p></o:p></span></span></p></td><td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 138.85pt;" valign="top" width="185"><p class="MsoNormal"><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">3dfacgg
  <o:p></o:p></span></p></td></tr><tr style=""><td style="border-style: none solid solid; border-color: -moz-use-text-color windowtext windowtext; border-width: medium 1pt 1pt; padding: 0cm 5.4pt; width: 69.65pt;" valign="top" width="93"><p class="MsoNormal"><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">d[^j]a
  <o:p></o:p></span></p></td><td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 140.65pt;" valign="top" width="188"><p class="MsoNormal"><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">daa</span><span style="font-size: 9pt;">、</span><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">d9a</span><span style="font-size: 9pt;">等等，除</span><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">dja <o:p></o:p></span></p></td><td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 138.85pt;" valign="top" width="185"><p class="MsoNormal"><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">3dfacggdjad5a
  <o:p></o:p></span></p></td></tr><tr style=""><td style="border-style: none solid solid; border-color: -moz-use-text-color windowtext windowtext; border-width: medium 1pt 1pt; padding: 0cm 5.4pt; width: 69.65pt;" valign="top" width="93"><p class="MsoNormal"><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">[d-g][ac]c
  <o:p></o:p></span></p></td><td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 140.65pt;" valign="top" width="188"><p class="MsoNormal"><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">dac</span><span style="font-size: 9pt;">、</span><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">ecc</span><span style="font-size: 9pt;">、</span><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">gac</span><span style="font-size: 9pt;">等</span><span style="font-size: 9pt; font-family: Arial;"><span lang="EN-US"><o:p></o:p></span></span></p></td><td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 138.85pt;" valign="top" width="185"><p class="MsoNormal"><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">3dfacggggccad5c
  <o:p></o:p></span></p></td></tr><tr style=""><td style="border-style: none solid solid; border-color: -moz-use-text-color windowtext windowtext; border-width: medium 1pt 1pt; padding: 0cm 5.4pt; width: 69.65pt;" valign="top" width="93"><p class="MsoNormal"><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">[d-g].{2}c
  <o:p></o:p></span></p></td><td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 140.65pt;" valign="top" width="188"><p class="MsoNormal"><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">d</span><span style="font-size: 9pt;" lang="EN-US">⊙⊙</span><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">c……
  <o:p></o:p></span></p></td><td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 138.85pt;" valign="top" width="185"><p class="MsoNormal"><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">3dfacggggccad5c
  <o:p></o:p></span></p></td></tr><tr style=""><td style="border-style: none solid solid; border-color: -moz-use-text-color windowtext windowtext; border-width: medium 1pt 1pt; padding: 0cm 5.4pt; width: 69.65pt;" valign="top" width="93"><p class="MsoNormal"><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">g{1,10}
  <o:p></o:p></span></p></td><td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 140.65pt;" valign="top" width="188"><p class="MsoNormal"><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">g</span><span style="font-size: 9pt;">、</span><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">ggg…… <o:p></o:p></span></p></td><td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 138.85pt;" valign="top" width="185"><p class="MsoNormal"><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">3dfacggggccad5c
  <o:p></o:p></span></p></td></tr><tr style=""><td style="border-style: none solid solid; border-color: -moz-use-text-color windowtext windowtext; border-width: medium 1pt 1pt; padding: 0cm 5.4pt; width: 69.65pt;" valign="top" width="93"><p class="MsoNormal"><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">[a|c][^a]
  <o:p></o:p></span></p></td><td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 140.65pt;" valign="top" width="188"><p class="MsoNormal"><span style="font-size: 9pt; font-family: Arial;" lang="EN-US"> <o:p></o:p></span></p></td><td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 138.85pt;" valign="top" width="185"><p class="MsoNormal"><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">3dfacggggccad5c
  <o:p></o:p></span></p></td></tr></tbody></table><br /><br /><table class="MsoNormalTable" style="border-collapse: collapse;" border="0" cellpadding="0" cellspacing="0"><tbody><tr style=""><td style="border: 1pt solid windowtext; padding: 0cm 5.4pt; width: 121.5pt;" valign="top" width="162"><p class="MsoNormal"><span style="font-size: 9pt;">测试用</span><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">str <o:p></o:p></span></p></td><td style="border-style: solid solid solid none; border-color: windowtext windowtext windowtext -moz-use-text-color; border-width: 1pt 1pt 1pt medium; padding: 0cm 5.4pt; width: 140.65pt;" valign="top" width="188"><p class="MsoNormal"><span style="font-size: 9pt;">匹配</span><span style="font-size: 9pt; font-family: Arial;"><span lang="EN-US"><o:p></o:p></span></span></p></td><td style="border-style: solid solid solid none; border-color: windowtext windowtext windowtext -moz-use-text-color; border-width: 1pt 1pt 1pt medium; padding: 0cm 5.4pt; width: 138.85pt;" valign="top" width="185"><p class="MsoNormal"><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">regEx
  <o:p></o:p></span></p></td></tr><tr style=""><td style="border-style: none solid solid; border-color: -moz-use-text-color windowtext windowtext; border-width: medium 1pt 1pt; padding: 0cm 5.4pt; width: 121.5pt;" valign="top" width="162"><p class="MsoNormal"><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">aabbfoaoabfooafobob
  <o:p></o:p></span></p></td><td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 140.65pt;" valign="top" width="188"><p class="MsoNormal"><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">a</span><span style="font-size: 9pt;" lang="EN-US">⊙⊙</span><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">b <o:p></o:p></span></p></td><td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 138.85pt;" valign="top" width="185"><p class="MsoNormal"><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">a..b
  <o:p></o:p></span></p></td></tr><tr style=""><td style="border-style: none solid solid; border-color: -moz-use-text-color windowtext windowtext; border-width: medium 1pt 1pt; padding: 0cm 5.4pt; width: 121.5pt;" valign="top" width="162"><p class="MsoNormal"><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">aabbfoaaobfooafbob
  <o:p></o:p></span></p></td><td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 140.65pt;" valign="top" width="188"><p class="MsoNormal"><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">a</span><span style="font-size: 9pt;" lang="EN-US">⊙</span><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">b</span><span style="font-size: 9pt;">、除</span><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">aab <o:p></o:p></span></p></td><td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 138.85pt;" valign="top" width="185"><p class="MsoNormal"><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">a[^a]b</span><span style="font-size: 9pt;">、</span><span style="font-size: 9pt; font-family: Arial;"><span lang="EN-US"><o:p></o:p></span></span></p></td></tr><tr style=""><td style="border-style: none solid solid; border-color: -moz-use-text-color windowtext windowtext; border-width: medium 1pt 1pt; padding: 0cm 5.4pt; width: 121.5pt;" valign="top" width="162"><p class="MsoNormal"><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">gooooooogle
  <o:p></o:p></span></p></td><td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 140.65pt;" valign="top" width="188"><p class="MsoNormal"><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">oooo……</span><span style="font-size: 9pt;">变成</span><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">oo <o:p></o:p></span></p></td><td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 138.85pt;" valign="top" width="185"><p class="MsoNormal"><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">o{2,20}
  <o:p></o:p></span></p></td></tr><tr style=""><td colspan="2" style="border-style: none solid solid; border-color: -moz-use-text-color windowtext windowtext; border-width: medium 1pt 1pt; padding: 0cm 5.4pt; width: 262.15pt;" valign="top" width="350"><p class="MsoNormal"><span style="font-size: 9pt;">一本书中的</span><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">“tan”</span><span style="font-size: 9pt;">、</span><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">“ten”</span><span style="font-size: 9pt;">、</span><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">“tin”</span><span style="font-size: 9pt;">和</span><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">“ton” <o:p></o:p></span></p></td><td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 138.85pt;" valign="top" width="185"><p class="MsoNormal"><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">t.n</span><span style="font-size: 9pt;">、</span><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">t[aeio]n <o:p></o:p></span></p></td></tr><tr style=""><td style="border-style: none solid solid; border-color: -moz-use-text-color windowtext windowtext; border-width: medium 1pt 1pt; padding: 0cm 5.4pt; width: 121.5pt;" valign="top" width="162"><p class="MsoNormal"><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">abcaccbcbaacabccaa
  <o:p></o:p></span></p></td><td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 140.65pt;" valign="top" width="188"><p class="MsoNormal"><span style="font-size: 9pt;">删除</span><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">ac</span><span style="font-size: 9pt;">、</span><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">ca <o:p></o:p></span></p></td><td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 138.85pt;" valign="top" width="185"><p class="MsoNormal"><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">(ca)|(ac)
  <o:p></o:p></span></p></td></tr><tr style=""><td style="border-style: none solid solid; border-color: -moz-use-text-color windowtext windowtext; border-width: medium 1pt 1pt; padding: 0cm 5.4pt; width: 121.5pt;" valign="top" width="162"><p class="MsoNormal"><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">abccbcbaabca
  <o:p></o:p></span></p></td><td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 140.65pt;" valign="top" width="188"><p class="MsoNormal"><span style="font-size: 9pt;">再删除</span><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">ab</span><span style="font-size: 9pt;">、</span><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">ba <o:p></o:p></span></p></td><td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 138.85pt;" valign="top" width="185"><p class="MsoNormal"><span style="font-size: 9pt;">结果</span><span style="font-size: 9pt; font-family: Arial;" lang="EN-US">ccbcca</span><span style="font-size: 9pt;">（如何与上面的合并）</span><span style="font-size: 9pt; font-family: Arial;"><span lang="EN-US"><o:p></o:p></span></span></p></td></tr></tbody></table><br />正则表达式对象的属性及方法 <br />　　预定义的正则表达式拥有有以下静态属性：input, multiline, lastMatch, lastParen, leftContext, rightContext和$1到$9。<br />其中input和multiline可以预设置。其他属性的值在执行过exec或test方法后被根据不同条件赋以不同的值。<br />许多属性同时拥有长和短(perl风格)的两个名字，并且，这两个名字指向同一个值。(JavaScript模拟perl的正则表达式) <br /><br />正则表达式对象的属性 属性 含义 <br />$1...$9 如果它(们)存在，是匹配到的子串 <br />$_ 参见input <br />$* 参见multiline <br />$&amp; 参见lastMatch <br />$+ 参见lastParen <br />$` 参见leftContext <br />$’　　　　　　　　　 参见rightContext <br />constructor　　　 创建一个对象的一个特殊的函数原型 <br />global　　　　　　 是否在整个串中匹配(bool型) <br />ignoreCase　　　　 匹配时是否忽略大小写(bool型) <br />input　　　　　　　 被匹配的串 <br />lastIndex　　　　 最后一次匹配的索引 <br />lastParen　　　　 最后一个括号括起来的子串 <br />leftContext　　　 最近一次匹配以左的子串 <br />multiline　　　　 是否进行多行匹配(bool型) <br />prototype　　　　 允许附加属性给对象 <br />rightContext　　　 最近一次匹配以右的子串 <br />source　　　　　　 正则表达式模式 <br />lastIndex　　　　 最后一次匹配的索引 <br /><br /><br />正则表达式对象的方法 <br />方法 含义 <br />compile　　　　　 正则表达式比较 <br />exec　　　　　　　 执行查找 <br />test　　　　　　　 进行匹配 <br />toSource　　　　　 返回特定对象的定义(literal representing)，其值可用来创建一个新的对象。重载Object.toSource方法得到的。 <br />toString　　　　　 返回特定对象的串。重载Object.toString方法得到的。 <br />valueOf　　　　　 返回特定对象的原始值。重载Object.valueOf方法得到 <br /><br />例子 <br />Smith, John <br />将输出"Smith, John" <br /><div class="postname">posted by yxs</div><br /><strike><br /></strike><img src ="http://www.blogjava.net/Iwishyou/aggbug/39528.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Iwishyou/" target="_blank">Iwishyou</a> 2006-04-06 10:16 <a href="http://www.blogjava.net/Iwishyou/articles/39528.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>快速排序算法的详细分析, 好东东, 呵呵</title><link>http://www.blogjava.net/Iwishyou/articles/39110.html</link><dc:creator>Iwishyou</dc:creator><author>Iwishyou</author><pubDate>Tue, 04 Apr 2006 03:10:00 GMT</pubDate><guid>http://www.blogjava.net/Iwishyou/articles/39110.html</guid><wfw:comment>http://www.blogjava.net/Iwishyou/comments/39110.html</wfw:comment><comments>http://www.blogjava.net/Iwishyou/articles/39110.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Iwishyou/comments/commentRss/39110.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Iwishyou/services/trackbacks/39110.html</trackback:ping><description><![CDATA[
		<p>
				<font size="2">留下给我这种菜鸟慢慢琢磨的, 呵呵</font>
				<br />
				<br />
		</p>
		<h2>快速排序 Quick Sort</h2>
		<p>我们已经知道，<a href="http://www.zsqz.com/jsbase/suanfa/commonalg/sort/internal_sorting/chapter1.htm">在决策树计算模型下，任何一个基于比较来确定两个元素相对位置的排序算法需要Ω(nlogn)计算时间</a>。如果我们能设计一个需要<i>O</i>(n1ogn)时间的排序算法，则在渐近的意义上，这个排序算法就是最优的。许多排序算法都是追求这个目标。</p>
		<p>下面介绍快速排序算法，它在平均情况下需要<i>O</i>(nlogn)时间。这个算法是由C.A.R.Hoare发明的。</p>
		<h3>算法的基本思想<a name="idea"></a></h3>
		<p>快速排序的基本思想是基于分治策略的。对于输入的子序列L[p..r]，如果规模足够小则直接进行排序（比如用前述的冒泡、选择、插入排序均可），否则分三步处理：</p>
		<ul>
				<li>分解(Divide)：将待排序列L[p..r]划分为两个非空子序列L[p..q]和L[q+1..r]，使L
[p..q]中任一元素的值不大于L[q+1..r]中任一元素的值。具体可通过这样的途径实现：在序列L[p..r]中选择数据元素L[q]，经比较和
移动后，L[q]将处于L[p..r]中间的适当位置，使得数据元素L[q]的值小于L[q+1..r]中任一元素的值。</li>
				<li>递归求解(Conquer)：通过递归调用快速排序算法，分别对L[p..q]和L[q+1..r]进行排序。</li>
				<li>合并(Merge)：由于对分解出的两个子序列的排序是就地进行的，所以在L[p..q]和L[q+1..r]都排好序后不需要执行任何计算L[p..r]就已排好序，即自然合并。</li>
		</ul>
		<p>这个解决流程是符合分治法的基本步骤的。因此，快速排序法是分治法的经典应用实例之一。</p>
		<h3>算法的实现<a name="imp"></a></h3>
		<p>
				<a name="algorithm-quick_sort">
				</a>算法Quick_Sort的实现：</p>
		<p class="note">
				<b>注意：</b>下面的记号L[p..r]代表线性表L从位置p到位置r的元素的集合，但是L并不一定要用数组来实现，可以是用任何一种实现方法（比如说链表），这里L[p..r]只是一种记号。</p>
		<pre>procedure Quick_Sort(p,r:position;var L:List);<br />const<br />e=12;<br />var<br />q:position;<br />begin<br />1  if r-p&lt;=e then Insertion_Sort(L,p,r)<br />//若L[p..r]足够小则直接对L[p..r]进行插入排序<br />     else begin<br />2            q:=partition(p,r,L);<br />//将L[p..r]分解为L[p..q]和L[q+1..r]两部分<br />3            Quick_Sort(p,q,L);  //递归排序L[p..q]<br />4            Quick_Sort(q+1,r,L);//递归排序L[q+1..r]		<br />          end;<br />end;<br /></pre>
		<p>对线性表L[1..n]进行排序，只要调用Quick_Sort(1,n,L)就可以了。算法首先判断L[p..r]是否足够小，若足够小则直接对L[p..r]进行排序，Sort可以是任何一种简单的排序法，一般用<a href="http://www.zsqz.com/jsbase/suanfa/commonalg/sort/internal_sorting/insertion_sort/insertion_sort.htm">插入排序</a>。
这是因为，对于较小的表，快速排序中划分和递归的开销使得该算法的效率还不如其它的直接排序法好。至于规模多小才算足够小，并没有一定的标准，因为这跟生
成的代码和执行代码的计算机有关，可以采取试验的方法确定这个规模阈值。经验表明，在大多数计算机上，取这个阈值为12较好，也就是说，当r-p&lt;
=e=12即L[p..r]的规模不大于12时，直接采用插入排序法对L[p..r]进行排序。当然，比较方便的方法是取该阈值为1，当待排序的表只有一
个元素时，根本不用排序(其实还剩两个元素时就已经在Partition函数中排好序了)，只要把第1行的if语句改为if p=r then
exit else ...。这就是通常教科书上看到的快速排序的形式。</p>
		<p class="note">
				<b>注意：</b>算法Quick_Sort中变量q的值一定不能等于r，否则该过程会无限递归下去，永远不能结束。因此下面在<a href="http://www.zsqz.com/jsbase/suanfa/commonalg/sort/internal_sorting/quick_sort/quick_sort.htm#Partition">partition函数</a>里加了限制条件，避免q=r情况的出现。</p>
		<p>算法Quick_Sort中调用了一个函数partition，该函数主要实现以下两个功能：</p>
		<blockquote>
				<ol>
						<li>在L[p..r]中选择一个支点元素pivot;</li>
						<li>对L[p..r]中的元素进行整理，使得L[p..q]分为两部分L[p..q]和L[q+1..r]，并且L[p..q]中的每一个元素的值不大于pivot，L[q+1..r]中的每一个元素的值不小于pivot，<b>但是L[p..q]和L[q+1..r]中的元素并不要求排好序</b>。</li>
				</ol>
		</blockquote>
		<p>快速排序法改进性能的关键就在于上述的第二个功能，因为该功能并不要求L[p..q]和L[q+1..r]中的元素排好序。</p>
		<p>函数partition可以实现如下。以下的实现方法是<a href="http://www.zsqz.com/jsbase/suanfa/commonalg/sort/index.htm#in-place-sort">原地置换</a>的，当然也有不是原地置换的方法，实现起来较为简单，这里就不介绍了。</p>
		<pre>function partition(p,r:position;var L:List):position;<a name="partition"></a><br />var<br />pivot:ElementType;<br />i,j:position;<br />begin<br />1  pivot:=Select_Pivot(p,r,L); //在L[p..r]中选择一个支点元素pivot<br />2  i:=p-1;<br />3  j:=r+1;<br />4  while true do<br />     begin<br />5      repeat j:=j-1 until L[j]&lt;=pivot;  <br />//移动左指针，注意这里不能用while循环<br />6      repeat i:=i+1 until L[i]&gt;=pivot;  <br />//移动右指针，注意这里不能用while循环<br />7      if i&lt; j then swap(L[i],L[j])  //交换L[i]和L[j]<br />8        else if j&lt;&gt;r then return j  //返回j的值作为分割点<br />9          else return j-1;          //返回j前一位置作为分割点<br />     end;<br />end;<br /></pre>
		<p>该算法的实现很精巧。其中，有一些细节需要注意。例如，算法中的位置i和j不会超出A[p..r]的位置界，并且该算法的循环不会出现死循环，<b>如果将两个repeat语句换为while则要注意当L[i]=L[j]=pivot且i&lt;j时i和j的值都不再变化，会出现死循环。</b></p>
		<p>另外，最后一个if..then..语句很重要，因为如果pivot取的不好，使得Partition结束时j正好等于r，则如前所述，<a href="http://www.zsqz.com/jsbase/suanfa/commonalg/sort/internal_sorting/quick_sort/quick_sort.htm#algorithm-quick_sort">算法Quick_Sort</a>会无限递归下去；因此必须判断j是否等于r，若j=r则返回j的前驱。</p>
		<p>以上算法的一个执行实例如图1所示，其中pivot=L[p]=5：</p>
		<p align="center">
				<img src="http://www.zsqz.com/jsbase/suanfa/commonalg/sort/internal_sorting/quick_sort/image0011.gif" border="0" />
		</p>
		<p align="center">图1 Partition过程的一个执行实例</p>
		<p>Partition对L[p..r]进行划分时，以pivot作为划分的基准，然后分别从左、右两端开始，扩展两个区域L[p..i]和L[j..
r]，使得L[p..i]中元素的值小于或等于pivot，而L[j..r]中元素的值大于或等于pivot。初始时i=p-1，且j=i+1，从而这两
个区域是空的。在while循环体中，位置j逐渐减小，i逐渐增大，直到L[i]≥pivot≥L[j]。如果这两个不等式是严格的，则L[i]不会是左
边区域的元素，而L[j]不会是右边区域的元素。此时若i在j之前，就应该交换L[i]与L[j]的位置，扩展左右两个区域。
while循环重复至i不再j之前时结束。这时L[p..r]己被划分成L[p..q]和L[q+1..r]，且满足L[p..q]中元素的值不大于L
[q+1..r]中元素的值。在过程Partition结束时返回划分点q。</p>
		<p>
				<a name="find_pivot">
				</a>寻找支点元素select_pivot有多种实现方法，不同的实现方法会导致快速排序的不同性能。根据分治法平衡子问题的思想，我们希望支点元素可以使L[p..r]尽量平均地分为两部分，但实际上这是很难做到的。下面我们给出几种寻找pivot的方法。</p>
		<blockquote>
				<ol>
						<li>选择L[p..r]的第一个元素L[p]的值作为pivot；</li>
						<li>选择L[p..r]的最后一个元素L[r]的值作为pivot；</li>
						<li>选择L[p..r]中间位置的元素L[m]的值作为pivot；</li>
						<li>选择L[p..r]的某一个随机位置上的值L[random(r-p)+p]的值作为pivot；</li>
				</ol>
		</blockquote>
		<p>按照第4种方法随机选择pivot的快速排序法又称为<i><b>随机化版本的快速排序法</b></i>，在下面的复杂性分析中我们将看到该方法具有平均情况下最好的性能，在实际应用中该方法的性能也是最好的。</p>
		<p>下面是一个快速排序的Java
Applet演示程序，该程序使用第一种pivot选择法，即选L[p]为pivot，因此Partition过程作了一些简化，与我们这里的
Partition过程实现方法不同，但功能相同。该程序是针对用数组实现的线性表，用C语言实现的。</p>
		<applet code="AlgAnimApp.class" codebase="demo/" height="55" width="300">
				<param name="filename" value="AlgThread.java" />
				<param name="buttonname" value="观看快速排序的Java Applet演示" />
				<param name="algname" value="Quick Sort" />
		</applet>
		<p>[参考算法]：Pascal语言表述的快速排序算法<br />   
procedure sort(l,r:integer);<br />
   var i,j,mid:integer;<br />
   begin<br />
     i:=l;j:=r; mid:=a[(l+r) div 2];<br />
     {将当前序列在中间位置的数定义为中间数}<br />
     repeat<br />
       while a[i]&lt; mid do inc(i); <br />
     {在左半部分寻找比中间数大的数}<br />
       while mid&lt; a[j] do dec(j);<br />
     {在右半部分寻找比中间数小的数}<br />
       if i&lt; =j then begin <br />
     {若找到一组与排序目标不一致的数对则交换它们}<br />
         swap(a[i],a[j]);<br />
         inc(i);dec(j); {继续找}<br />
       end;<br />
     until i &gt;j;<br />
     if l&lt; j then sort(l,j); <br />
     {若未到两个数的边界，则递归搜索左右区间}<br />
     if i&lt; r then sort(i,r);<br />
   end;{sort}
</p>
		<p>
				<font color="red">
						<b>思考与练习：</b>
				</font>
				<a href="http://www.zsqz.com/qz_zuoye/" target="_blank">完成并提交作业</a>
				<br />    
　　1、仔细阅读下面的Pascal程序，并回答有关问题。<br />
procedure PX(var A:array[1..500] of integer,n:integer);<br />  
var i,j,x:integer;b:boolean;<br />  
begin<br />
  b:=true;i:=1;<br />  
  while (i &lt; n) and b do<br />  
    begin<br />  
b:=false;<br />
for j:=1 to ______ do<br />  
  if _____ then<br />  
begin<br />
 x:=A[j];A[j]:=A[j+1];A[j+1]:=x; <br />
 ______ end;<br />  
  i:=i+1;<br />  
    end;  <br />  
end;<br />
 (1)在_____中填上正确的语句或表达式；<br />
 (2)该过程使用的是什么排序方式?<br />
 (3)当数组A的元素初始时已为递增排列时，该过程运行时会进行几次比较？几次交换？<br />
 (4)若A是递减排列，比较和交换次数又是多少？</p>
		<p>　2、给出n个学生的考试成绩表，每个数据记录由学生的姓名和成绩组成，试设计一个算法：<br />
 (1)按成绩高低次序,输出每个学生在考试中获得的名次,成绩相同的名次相同;<br />
 (2)按名次输出每个学生的姓名和成绩。 
</p>
		<p>
				<font color="#ff0000">下面的内容供参考</font>—— 
</p>
		<h3>性能分析<a name="comp"></a></h3>
		<p>下面我们就最好情况，最坏情况和平均情况对快速排序算法的性能作一点分析。</p>
		<p class="note">
				<b>注意：</b>这里为方便起见，我们假设算法Quick_Sort的<a href="http://www.zsqz.com/jsbase/suanfa/commonalg/sort/internal_sorting/quick_sort/quick_sort.htm#algorithm-quick_sort">范围阈值</a>为1（即一直将线性表分解到只剩一个元素），这对该算法复杂性的分析没有本质的影响。</p>
		<p>我们先分析函数partition的性能，该函数对于确定的输入复杂性是确定的。观察该函数，我们发现，对于有n个元素的确定输入L[p..r]，该函数运行时间显然为θ(n)。</p>
		<h4>最坏情况<a name="worst"></a></h4>
		<p>无论适用哪一种方法来选择pivot，由于我们不知道各个元素间的相对大小关系（若知道就已经排好序了），所以我们无法确定pivot的选择对划分造成的影响。因此对各种pivot选择法而言，最坏情况和最好情况都是相同的。</p>
		<p>我们从直觉上可以判断出最坏情况发生在每次划分过程产生的两个区间分别包含n-1个元素和1个元素的时候(设输入的表有n个元素)。下面我们暂时认为该猜测正确，在后文我们再详细证明该猜测。</p>
		<p>对于有n个元素的表L[p..r]，由于函数Partition的计算时间为θ(n)，所以快速排序在序坏情况下的复杂性有递归式如下：</p>
		<blockquote>
				<p>T(1)=θ(1), T(n)=T(n-1)+T(1)+θ(n)                    
    (1)</p>
		</blockquote>
		<p>用迭代法可以解出上式的解为T(n)=θ(n<sup>2</sup>)。</p>
		<p>这个最坏情况运行时间与<a href="http://www.zsqz.com/jsbase/suanfa/commonalg/sort/internal_sorting/insertion_sort/insertion_sort.htm">插入排序</a>是一样的。</p>
		<p>下面我们来证明这种每次划分过程产生的两个区间分别包含n-1个元素和1个元素的情况就是最坏情况。</p>
		<p>设T(n)是过程Quick_Sort作用于规模为n的输入上的最坏情况的时间，则</p>
		<blockquote>
				<p>T(n)=max(T(q)+T(n-q))+θ(n) ,其中1≤q≤n-1    (2)</p>
		</blockquote>
		<p>我们假设对于任何k&lt;n，总有T(k)≤ck<sup>2 </sup>，其中c为常数；显然当k=1时是成立的。</p>
		<p>将归纳假设代入(2)，得到：</p>
		<blockquote>
				<p>T(n)≤max(cq<sup>2</sup>+c(n-q)<sup>2</sup>)+θ(n)=c*max(q<sup>2</sup>+(n-q)<sup>2</sup>)+θ(n)</p>
		</blockquote>
		<p>因为在[1,n-1]上q<sup>2</sup>+(n-q)<sup>2</sup>关于q递减，所以当q=1时q<sup>2</sup>+(n-q)<sup>2</sup>有最大值n<sup>2</sup>-2(n-1)。于是有：</p>
		<blockquote>
				<p>T(n)≤cn<sup>2</sup>-2c(n-1)+θ(n)≤cn<sup>2</sup></p>
		</blockquote>
		<p>只要c足够大，上面的第二个小于等于号就可以成立。于是对于所有的n都有T(n)≤cn<sup>2 </sup>。</p>
		<p>这样，排序算法的最坏情况运行时间为θ(n<sup>2</sup>)，且最坏情况发生在每次划分过程产生的两个区间分别包含n-1个元素和1个元素的时候。</p>
		<h4>最好情况<a name="best"></a></h4>
		<p>如果每次划分过程产生的区间大小都为n/2，则快速排序法运行就快得多了。这时有：</p>
		<blockquote>
				<p>T(n)=2T(n/2)+θ(n), T(1)=θ(1)     (3)</p>
		</blockquote>
		<p>解得： T(n)=θ(nlogn)</p>
		<p>快速排序法最佳情况下执行过程的递归树如下图所示，图中lgn表示以2位底的对数，而本文中用logn表示以2位底的对数.</p>
		<p align="center">
				<img src="http://www.zsqz.com/jsbase/suanfa/commonalg/sort/internal_sorting/quick_sort/wpe1.gif" border="0" height="263" width="467" />
		</p>
		<blockquote>
				<p align="center">图2  快速排序法最佳情况下执行过程的递归树</p>
				<p align="center">　</p>
		</blockquote>
		<p>由于快速排序法也是<a href="http://www.zsqz.com/jsbase/suanfa/commonalg/sort/internal_sorting/chapter1.htm">基于比较的排序法，其运行时间为Ω(nlogn)</a>，所以如果每次划分过程产生的区间大小都为n/2，则运行时间θ(nlogn)就是最好情况运行时间。</p>
		<p>但是，是否一定要每次平均划分才能达到最好情况呢？要理解这一点就必须理解对称性是如何在描述运行时间的递归式中反映的。我们假设每次划分过程都产生9:1的划分，乍一看该划分很不对称。我们可以得到递归式：</p>
		<blockquote>
				<p>T(n)=T(n/10)+T(9n/10)+θ(n) , T(1)=θ(1)                
    (4)</p>
		</blockquote>
		<p>这个递归式对应的递归树如下图所示：</p>
		<p align="center">
				<img src="http://www.zsqz.com/jsbase/suanfa/commonalg/sort/internal_sorting/quick_sort/wpe6.gif" border="0" height="306" width="490" />
		</p>
		<blockquote>
				<p align="center">图3  (4)式对应的递归树</p>
				<p align="center">　</p>
		</blockquote>
		<p>请注意该树的每一层都有代价n，直到在深度log<sub>10</sub>n=θ(logn)处达到边界条件，        
    以后各层代价至多为n。递归于深度log<sub>10/9</sub>n=
θ(logn)处结束。这样，快速排序的总时间代价为T(n)=θ(nlogn)，从渐进意义上看就和划分是在中间进行的一样。事实上，即使是99:1的
划分时间代价也为θ(nlogn)。其原因在于，任何一种按常数比例进行划分所产生的递归树的深度都为θ(nlogn)，其中每一层的代价为<i>O</i>(n)，因而不管常数比例是什么，总的运行时间都为θ(nlogn)，只不过其中隐含的常数因子有所不同。</p>
		<h4>平均情况<a name="avg"></a></h4>
		<p>我们首先对平均情况下的性能作直觉上的分析。</p>
		<p>要想对快速排序的平均情况有个较为清楚的概念，我们就要对遇到的各种输入作个假设。通常都假设输入数据的所有排列都是等可能的。后文中我们要讨论这个假设。</p>
		<p>当我们对一个随机的输入数组应用快速排序时，要想在每一层上都有同样的划分是不太可能的。我们所能期望的是某些划分较对称，另一些则很不对称。事实
上，我们可以证明，如果选择L[p..r]的第一个元素作为支点元素，Partition所产生的划分80%以上都比9:1更对称，而另20%则比9:1
差，这里证明从略。</p>
		<p>
				<a name="bad-good">
				</a>平均情况下，Partition产生的划分中既有“好的”，又有“差的”。这时，与
Partition执行过程对应的递归树中，好、差划分是随机地分布在树的各层上的。为与我们的直觉相一致，假设好、差划分交替出现在树的各层上，且好的
划分是最佳情况划分，而差的划分是最坏情况下的划分，图4(a)表示了递归树的连续两层上的划分情况。在根节点处，划分的代价为n，划分出来的两个子表的
大小为n-1和1，即最坏情况。在根的下一层，大小为n-1的子表按最佳情况划分成大小各为(n-1)/2的两个子表。这儿我们假设含1个元素的子表的边
界条件代价为1。<br /></p>
		<table border="0">
				<tbody>
						<tr>
								<td width="50%">
										<img src="http://www.zsqz.com/jsbase/suanfa/commonalg/sort/internal_sorting/quick_sort/quick_1.gif" border="0" height="112" width="270" />
										<p align="center">(a)     
      </p>
								</td>
								<td width="50%">
										<img src="http://www.zsqz.com/jsbase/suanfa/commonalg/sort/internal_sorting/quick_sort/quick_2.gif" border="0" height="112" width="270" />
										<p align="center">(b)     
      </p>
								</td>
						</tr>
				</tbody>
		</table>
		<p align="center">图4 快速排序的递归树划分中的两种情况</p>
		<p>在一个差的划分后接一个好的划分后，产生出三个子表，大小各为1，(n-1)/2和(n-1)/2，代价共为2n-1=θ(n)。这与图4(b)中
的情况差不多。该图中一层划分就产生出大小为(n-1)/2+1和(n-1)/2的两个子表，代价为n=θ(n)。这种划分差不多是完全对称的，比9:1
的划分要好。从直觉上看，差的划分的代价θ(n)可被吸收到好的划分的代价θ(n)中去，结果是一个好的划分。这样，当好、差划分交替分布划分都是好的一
样：仍是θ(nlogn)，但θ记号中隐含的常数因子要略大一些。关于平均情况的严格分析将在后文给出。</p>
		<p>在前文从直觉上探讨快速排序的平均性态过程中，我们已假定输入数据的所有排列都是等可能的。如果输入的分布满足这个假设时，快速排序是对足够大的输入的理想选择。但在实际应用中，这个假设就不会总是成立。</p>
		<p>解决的方法是，利用随机化策略，能够克服分布的等可能性假设所带来的问题。</p>
		<p>一种随机化策略是：与对输入的分布作“假设”不同的是对输入的分布作“规定”。具体地说，在排序输入的线性表前，对其元素加以随机排列，以强制的方
法使每种排列满足等可能性。事实上，我们可以找到一个能在O(n)时间内对含n个元素的数组加以随机排列的算法。这种修改不改变算法的最坏情况运行时间，
但它却使得运行时间能够独立于输入数据已排序的情况。</p>
		<p>另一种随机化策略是：利用前文介绍的<a href="http://www.zsqz.com/jsbase/suanfa/commonalg/sort/internal_sorting/quick_sort/quick_sort.htm#find_pivot">选择支点元素pivot的第四种方法</a>，即随机地在L[p..r]中选择一个元素作为支点元素pivot。实际应用中通常采用这种方法。</p>
		<p>快速排序的随机化版本有一个和其他随机化算法一样的有趣性质：没有一个特别的输入会导致最坏情况性态。这种算法的最坏情况性态是由随机数产生器决定
的。你即使有意给出一个坏的输入也没用，因为随机化排列会使得输入数据的次序对算法不产生影响。只有在随机数产生器给出了一个很不巧的排列时，随机化算法
的最坏情况性态才会出现。事实上可以证明几乎所有的排列都可使快速排序接近平均情况性态,只有非常少的几个排列才会导致算法的近最坏情况性态。</p>
		<p>一般来说，当一个算法可按多条路子做下去，但又很难决定哪一条保证是好的选择时，随机化策略是很有用的。如果大部分选择都是好的，则随机地选一个就
行了。通常，一个算法在其执行过程中要做很多选择。如果一个好的选择的获益大于坏的选择的代价，那么随机地做一个选择就能得到一个很有效的算法。我们在前
文已经了解到，<a href="http://www.zsqz.com/jsbase/suanfa/commonalg/sort/internal_sorting/quick_sort/quick_sort.htm#bad-good">对快速排序来说，一组好坏相杂的划分仍能产生很好的运行时间</a>。因此我们可以认为该算法的随机化版本也能具有较好的性态。</p>
		<p>在前文我们从直觉上分析了快速排序在平均情况下的性能为θ(nlogn)，我们将在下面定量地分析快速排序法在平均情况下的性能。为了满足输入的数
据的所有排列都是等可能的这个假设，我们采用上面提到的随机选择pivot的方法，并且在Select_pivot函数中将选出的pivot与L[p]交
换位置（这不是必需的，纯粹是为了下文分析的方便，这样L[p]就是支点元素pivot）。那种基于对输入数据加以随机排列的随机化算法的平均性态也很
好，只是比这儿介绍的这个版本更难以分析。</p>
		<p>我们先来看看Partition的执行过程。为简化分析，假设所有输入数据都是不同的。即使这个假设不满足，快速排序的平均情况运行时间仍为θ(nlogn)，但这时的分析就要复杂一些。</p>
		<p>由Partition返回的值q仅依赖于pivot在L[p..r]中的<b><i>秩(rank)</i></b>，某个数在一个集合中的秩是指该集合中小于或等于该数的元素的个数。如果设n为L[p..r]的元素个数，将L[p]与L[p..r]中的一个随机元素pivot交换就得rank(pivot)=i(i=1,2,..,n)的概率为l/n。</p>
		<p>下一步来计算划分过程不同结果的可能性。如果rank(pivot)=1，即pivot是L[p..r]中最小的元素，则<a href="http://www.zsqz.com/jsbase/suanfa/commonalg/sort/internal_sorting/quick_sort/quick_sort.htm#Partition">Partition</a>的循环结束时指针i停在i=p处，指针j停在k=p处。当返回q时，划分结果的"低区"中就含有唯一的元素L[p]=pivot。这个事件发生的概率为1/n，因为rank(pivot)=i的概率为1/n。</p>
		<p>如果rank(pivot)≥2，则至少有一个元素小于L[p]，故在外循环while循环的第一次执行中，指针i停于i=p处，指针j则在达到p
之前就停住了。这时通过交换就可将L[p]置于划分结果的高区中。当Partition结束时，低区的rank(pivot)-1个元素中的每一个都严格
小于pivot（因为假设输入的元素不重复）。这样，对每个i=1,2,..,n-1，当rank(pivot)≥2时，划分的低区中含i个元素的概率为
l/n。</p>
		<p>把这两种情况综合起来，我们的结论为：划分的低区的大小为1的概率为2/n，低区大小为i的概率为1/n，i=2,3,..n-1。</p>
		<p>现在让我们来对Quick_Sort的期望运行时间建立一个递归式。设T(n)表示排序含n个元素的表所需的平均时间，则：</p>
		<blockquote>
				<p>
						<img src="http://www.zsqz.com/jsbase/suanfa/commonalg/sort/internal_sorting/quick_sort/image009.gif" border="0" height="53" width="353" />   （5）</p>
				<p>其中T(1)=θ(1)。</p>
		</blockquote>
		<p>q的分布基本上是均匀的，但是q=1的可能性是其他值的两倍。根据前面作的<a href="http://www.zsqz.com/jsbase/suanfa/commonalg/sort/internal_sorting/quick_sort/quick_sort.htm#worst">最坏情况的分析</a>有：</p>
		<blockquote>
				<p>T(1)=θ(1),T(n-1)=θ(n<sup>2</sup>)，所以</p>
				<p>
						<img src="http://www.zsqz.com/jsbase/suanfa/commonalg/sort/internal_sorting/quick_sort/image008.gif" border="0" height="41" width="289" />
				</p>
		</blockquote>
		<p>这可被(5)式中的θ(n)所吸收，所以(5)式可简化为：</p>
		<blockquote>
				<p>
						<img src="http://www.zsqz.com/jsbase/suanfa/commonalg/sort/internal_sorting/quick_sort/image010.gif" border="0" height="53" width="236" />               
      (6)</p>
		</blockquote>
		<p>注意对k=1,2,..,n-1，和式中每一项T(k)为T(q)和T(n-q)的机会各有一次，把这两项迭起来有：</p>
		<blockquote>
				<p>
						<img src="http://www.zsqz.com/jsbase/suanfa/commonalg/sort/internal_sorting/quick_sort/image012.gif" border="0" height="51" width="153" />                       
(7)</p>
				<p>　</p>
		</blockquote>
		<p>我们用<a href="http://www.zsqz.com/jsbase/suanfa/complexity/chapter6_1.htm">代入法</a>来解上述递归方程。归纳假设T(n)≤a*nlogn+b，其中a&gt;0,b&gt;0为待定常数。可以选择足够大的a,b使anlogn+b&gt;T(1)，对于n&gt;1有：</p>
		<blockquote>
				<p>
						<img src="http://www.zsqz.com/jsbase/suanfa/commonalg/sort/internal_sorting/quick_sort/image014.gif" border="0" height="155" width="252" />              
      （8）</p>
		</blockquote>
		<p>下面我们来确定和式</p>
		<blockquote>
				<p>
						<img src="http://www.zsqz.com/jsbase/suanfa/commonalg/sort/internal_sorting/quick_sort/image016.gif" border="0" height="51" width="65" />                        
      （9）</p>
		</blockquote>
		<p>的界。</p>
		<p>因为和式中每一项至多是nlogn，则有界：</p>
		<blockquote>
				<p>
						<img src="http://www.zsqz.com/jsbase/suanfa/commonalg/sort/internal_sorting/quick_sort/image018.gif" border="0" height="51" width="133" />
				</p>
		</blockquote>
		<p>这是个比较紧的界，但是对于解递归式（8）来说还不够强。为解该递归式，我们希望有界：</p>
		<blockquote>
				<p>
						<img src="http://www.zsqz.com/jsbase/suanfa/commonalg/sort/internal_sorting/quick_sort/image020.gif" border="0" height="41" width="124" />
				</p>
		</blockquote>
		<p>为了得到这个界，可以将和式(9)分解为两部分，这时有：</p>
		<blockquote>
				<p>
						<img src="http://www.zsqz.com/jsbase/suanfa/commonalg/sort/internal_sorting/quick_sort/image022.gif" border="0" height="55" width="243" />
				</p>
		</blockquote>
		<p>等号右边的第一个和式中的logk可由log(n/2)=logn-1从上方限界。第二个和式中的logk可由logn从上方限界，这样，</p>
		<blockquote>
				<p>
						<img src="http://www.zsqz.com/jsbase/suanfa/commonalg/sort/internal_sorting/quick_sort/image024.gif" border="0" height="195" width="272" />
				</p>
		</blockquote>
		<p>对于n≥2成立。即:</p>
		<blockquote>
				<p>
						<img src="http://www.zsqz.com/jsbase/suanfa/commonalg/sort/internal_sorting/quick_sort/image026.gif" border="0" height="51" width="188" />     (10)</p>
		</blockquote>
		<p>将(10)代入(8）式得：</p>
		<blockquote>
				<p>
						<img src="http://www.zsqz.com/jsbase/suanfa/commonalg/sort/internal_sorting/quick_sort/image028.gif" border="0" height="152" width="309" />      （11）</p>
				<p>　</p>
		</blockquote>
		<p>因为我们可以选择足够大的a使a*n/4能够决定θ(n)+b，所以快速排序的平均运行时间为θ(nlogn)。</p>
		<dfn>
				<font color="red">思考与练习</font>
		</dfn>见本页中上部<img src ="http://www.blogjava.net/Iwishyou/aggbug/39110.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Iwishyou/" target="_blank">Iwishyou</a> 2006-04-04 11:10 <a href="http://www.blogjava.net/Iwishyou/articles/39110.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>很简单的一个RMI</title><link>http://www.blogjava.net/Iwishyou/articles/35046.html</link><dc:creator>Iwishyou</dc:creator><author>Iwishyou</author><pubDate>Mon, 13 Mar 2006 07:30:00 GMT</pubDate><guid>http://www.blogjava.net/Iwishyou/articles/35046.html</guid><wfw:comment>http://www.blogjava.net/Iwishyou/comments/35046.html</wfw:comment><comments>http://www.blogjava.net/Iwishyou/articles/35046.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Iwishyou/comments/commentRss/35046.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Iwishyou/services/trackbacks/35046.html</trackback:ping><description><![CDATA[很简单的一个RMI<br>
<br>

作者：zhangxhsj&nbsp;&nbsp;&nbsp;&nbsp;来自：未知                
<br>
                               　　RMI，远程方法调用（Remote 
                                Method Invocation）是Enterprise JavaBeans的支柱，是建立分布式Java应用程序的方便途径。RMI是非常容易使用的，但是它非常的强大。<br>
                                　　RMI的基础是接口，RMI构架基于一个重要的原理：定义接口和定义接口的具体实现是分开的。下面我们通过具体的例子，建立一个简单的远程计算服务和使用它的客户程序<br>
                                <br>
                                　　一个正常工作的RMI系统由下面几个部分组成： 
                                <ul><li>远程服务的接口定义</li><li>远程服务接口的具体实现</li><li>桩（Stub）和框架（Skeleton）文件</li><li>一个运行远程服务的服务器</li><li>一个RMI命名服务，它允许客户端去发现这个远程服务</li><li>类文件的提供者（一个HTTP或者FTP服务器）</li><li>一个需要这个远程服务的客户端程序</li></ul>
                                <p>　　下面我们一步一步建立一个简单的RMI系统。首先在你的机器里建立一个新的文件夹，以便放置我们创建的文件，为了简单起见，我们只使用一个文件夹存放客户端和服务端代码，并且在同一个目录下运行服务端和客户端。<br>
                                  <br>
                                  　　如果所有的RMI文件都已经设计好了，那么你需要下面的几个步骤去生成你的系统：<br>
                                  <br>
                                  　　1、&nbsp;&nbsp;编写并且编译接口的Java代码<br>
                                  　　2、&nbsp;&nbsp;编写并且编译接口实现的Java代码<br>
                                  　　3、&nbsp;&nbsp;从接口实现类中生成桩（Stub）和框架（Skeleton）类文件<br>
                                  　　4、&nbsp;&nbsp;编写远程服务的主运行程序<br>
                                  　　5、&nbsp;&nbsp;编写RMI的客户端程序<br>
                                  　　6、&nbsp;&nbsp;安装并且运行RMI系统<br>
                                  <br>
</p><br>

                                  　　1、&nbsp;&nbsp;接口<br>

                                  　　第一步就是建立和编译服务接口的Java代码。这个接口定义了所有的提供远程服务的功能，下面是源程序：<br>

                                  <br>

                                  //Calculator.java<br>

                                  //define the interface<br>

                                  import java.rmi.Remote;<br>

                                  <br>

                                  public interface Calculator extends Remote<br>

                                  {<br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;public long add(long 
                                  a, long b) <br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throws 
                                  java.rmi.RemoteException; <br>

                                  <br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;public long sub(long 
                                  a, long b) <br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throws 
                                  java.rmi.RemoteException; <br>

                                  <br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;public long mul(long 
                                  a, long b) <br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throws 
                                  java.rmi.RemoteException; <br>

                                  <br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;public long div(long 
                                  a, long b) <br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throws 
                                  java.rmi.RemoteException; <br>

                                  } <br>

                                  　　注意，这个接口继承自Remote，每一个定义的方法都必须抛出一个RemoteException异常对象。<br>

                                  <br>

                                  　　建立这个文件，把它存放在刚才的目录下，并且编译。<br>

                                  <br>

                                  　　&gt;javac Calculator.java<br>

                                  <br>

                                  　　2、&nbsp;&nbsp;接口的具体实现<br>

                                  <br>

                                  　　下一步，我们就要写远程服务的具体实现，这是一个CalculatorImpl类文件：<br>

                                  <br>

                                  //CalculatorImpl.java<br>

                                  //Implementation<br>

                                  import java.rmi.server.UnicastRemoteObject<br>

                                  <br>

                                  public class CalculatorImpl extends UnicastRemoteObject 
                                  implements Calculator <br>

                                  { <br>

                                  <br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;// 这个实现必须有一个显式的构造函数，并且要抛出一个RemoteException异常 
                                  <br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;public CalculatorImpl() 
                                  <br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throws 
                                  java.rmi.RemoteException { <br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;super(); 
                                  <br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;} <br>

                                  <br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;public long add(long 
                                  a, long b) <br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throws 
                                  java.rmi.RemoteException { <br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 
                                  a + b; <br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;} <br>

                                  <br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;public long sub(long 
                                  a, long b) <br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throws 
                                  java.rmi.RemoteException { <br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 
                                  a - b; <br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;} <br>

                                  <br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;public long mul(long 
                                  a, long b) <br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throws 
                                  java.rmi.RemoteException { <br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 
                                  a * b; <br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;} <br>

                                  <br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;public long div(long 
                                  a, long b) <br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throws 
                                  java.rmi.RemoteException { <br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 
                                  a / b; <br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;} <br>

                                  } <br>

                                  　　同样的，把这个文件保存在你的目录里然后编译他。<br>

                                  <br>

　　这个实现类使用了UnicastRemoteObject去联接RMI系统。在我们的例子中，我们是直接的从UnicastRemoteObject
这个类上继承的，事实上并不一定要这样做，如果一个类不是从UnicastRmeoteObject上继承，那必须使用它的exportObject()
方法去联接到RMI。<br>

                                  <br>

　　如果一个类继承自UnicastRemoteObject，那么它必须提供一个构造函数并且声明抛出一个RemoteException对象。当这个
构造函数调用了super()，它久激活UnicastRemoteObject中的代码完成RMI的连接和远程对象的初始化。<br>

                                  <br>

                                  　　3、&nbsp;&nbsp;桩（Stubs）和框架（Skeletons）<br>

                                  <br>

                                  　　下一步就是要使用RMI编译器rmic来生成桩和框架文件，这个编译运行在远程服务实现类文件上。<br>

                                  <br>

                                  　　&gt;rmic CalculatorImpl<br>

                                  <br>

　　在你的目录下运行上面的命令，成功执行完上面的命令你可以发现一个Calculator_stub.class文件，如果你是使用的
Java2SDK，那么你还可以发现Calculator_Skel.class文件。<br>

                                  <br>

                                  　　4、&nbsp;&nbsp;主机服务器<br>

                                  <br>

                                  　　远程RMI服务必须是在一个服务器中运行的。CalculatorServer类是一个非常简单的服务器。<br>

                                  <br>

                                  //CalculatorServer.java<br>

                                  import java.rmi.Naming;<br>

                                  <br>

                                  public class CalculatorServer {<br>

                                  <br>

                                  &nbsp;&nbsp;&nbsp;public CalculatorServer() 
                                  {<br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try {<br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Calculator 
                                  c = new CalculatorImpl();<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Naming.rebind("rmi://localhost:1099/CalculatorService",
c);<br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} catch (Exception 
                                  e) {<br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("Trouble: 
                                  " + e);<br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>

                                  &nbsp;&nbsp;&nbsp;}<br>

                                  <br>

                                  &nbsp;&nbsp;&nbsp;public static void main(String 
                                  args[]) {<br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;new CalculatorServer();<br>

                                  &nbsp;&nbsp;&nbsp;}<br>

                                  }<br>

                                  　　建立这个服务器程序，然后保存到你的目录下，并且编译它。<br>

                                  <br>

                                  　　5、&nbsp;&nbsp;客户端<br>

                                  <br>

                                  　　客户端源代码如下：<br>

                                  <br>

                                  //CalculatorClient.java<br>

                                  <br>

                                  import java.rmi.Naming; <br>

                                  import java.rmi.RemoteException; <br>

                                  import java.net.MalformedURLException; <br>

                                  import java.rmi.NotBoundException; <br>

                                  <br>

                                  public class CalculatorClient { <br>

                                  <br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;public static void main(String[] 
                                  args) { <br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try 
                                  { <br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Calculator 
                                  c = (Calculator)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Naming.lookup(<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"rmi://localhost<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/CalculatorService");
<br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println( 
                                  c.sub(4, 3) ); <br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println( 
                                  c.add(4, 5) ); <br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println( 
                                  c.mul(3, 6) ); <br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println( 
                                  c.div(9, 3) ); <br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} 
                                  <br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;catch 
                                  (MalformedURLException murle) { <br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(); 
                                  <br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"MalformedURLException");
<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(murle);
<br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} 
                                  <br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;catch 
                                  (RemoteException re) { <br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(); 
                                  <br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"RemoteException");
<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(re);
<br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} 
                                  <br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;catch 
                                  (NotBoundException nbe) { <br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(); 
                                  <br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"NotBoundException");
<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(nbe);
<br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} 
                                  <br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;catch 
                                  (<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;java.lang.ArithmeticException<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ae)
{ <br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(); 
                                  <br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"java.lang.ArithmeticException");
<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(ae);
<br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} 
                                  <br>

                                  &nbsp;&nbsp;&nbsp;&nbsp;} <br>

                                  } <br>

                                  　　保存这个客户端程序到你的目录下（注意这个目录是一开始建立那个，所有的我们的文件都在那个目录下），并且编译他。<br>

                                  <br>

                                  　　6、&nbsp;&nbsp;运行RMI系统<br>

                                  <br>

                                  　　现在我们建立了所有运行这个简单RMI系统所需的文件，现在我们终于可以运行这个RMI系统啦！来享受吧。<br>

                                  <br>

                                  　　我们是在命令控制台下运行这个系统的，你必须开启三个控制台窗口，一个运行服务器，一个运行客户端，还有一个运行RMIRegistry。<br>

                                  <br>

                                  　　首先运行注册程序RMIRegistry，你必须在包含你刚写的类的那么目录下运行这个注册程序。<br>

                                  <br>

                                  　　&gt;rmiregistry<br>

                                  <br>

　　好，这个命令成功的话，注册程序已经开始运行了，不要管他，现在切换到另外一个控制台，在第二个控制台里，我们运行服务器
CalculatorService，因为RMI的安全机制将在服务端发生作用,所以你必须增加一条安全策略。以下是对应安全策略的例子 <br>

                                  grant {<br>

                                  permission java.security.AllPermission "", "";<br>

                                  };<br>

                                  　　注意:这是一条最简单的安全策略,它允许任何人做任何事,对于你的更加关键性的应用,你必须指定更加详细安全策略。<br>

                                  　　现在为了运行服务端，你需要除客户类(CalculatorClient.class)之外的所有的类文件。确认安全策略在policy.txt文件之后,使用如下命令来运行服务器。
                                
<p> 　　&gt; java -Djava.security.policy=policy.txt 
                                  CalculatorServer<br>
                                  <br>
                                  　　这个服务器就开始工作了，把接口的实现加载到内存等待客户端的联接。好现在切换到第三个控制台，启动我们的客户端。<br>
                                  　　为了在其他的机器运行客户端程序你需要一个远程接口(Calculator.class) 
                                  和一个stub(CalculatorImpl_Stub.class)。 使用如下命令运行客户端</p>

                                
<p>　　 prompt&gt; java -Djava.security.policy=policy.txt 
                                  CalculatorClient<br>
                                  <br>
                                  如果所有的这些都成功运行，你应该看到下面的输出：<br>
                                  　　1<br>
                                  　　9<br>
                                  　　18<br>
                                  　　3<br>
　　如果你看到了上面的输出，恭喜你，你成功了，你已经成功的创建了一个RMI系统，并且使他正确工作了。即使你运行在同一个计算机上，RMI还是使用了
你的网络堆栈和TCP/IP去进行通讯，并且是运行在三个不同的Java虚拟机上。这已经是一个完整的RMI系统。</p>

<img src ="http://www.blogjava.net/Iwishyou/aggbug/35046.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Iwishyou/" target="_blank">Iwishyou</a> 2006-03-13 15:30 <a href="http://www.blogjava.net/Iwishyou/articles/35046.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>介绍session</title><link>http://www.blogjava.net/Iwishyou/articles/35013.html</link><dc:creator>Iwishyou</dc:creator><author>Iwishyou</author><pubDate>Mon, 13 Mar 2006 05:34:00 GMT</pubDate><guid>http://www.blogjava.net/Iwishyou/articles/35013.html</guid><wfw:comment>http://www.blogjava.net/Iwishyou/comments/35013.html</wfw:comment><comments>http://www.blogjava.net/Iwishyou/articles/35013.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Iwishyou/comments/commentRss/35013.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Iwishyou/services/trackbacks/35013.html</trackback:ping><description><![CDATA[<table style="" align="center" border="0" cellpadding="0" cellspacing="0" width="700">
<tbody><tr><td align="center" height="25"><font face="黑体" size="4">Session详解</font></td></tr>                <tr bgcolor="#f9f9f9"><td align="center" height="30">作者：郎云鹏&nbsp;&nbsp;&nbsp;&nbsp;来自：dev2dev</td></tr>                <tr bgcolor="#f9f9f9"><td style="line-height: 200%;" id="fontzoom">                     <p>作者：郎云鹏（dev2dev ID: hippiewolf）</p>
<p>摘要：虽然session机制在web应用程序中被采用已经很长时间了，但是仍然有很多人不清楚session机制的本质，以至不能正确的应用这一
技术。本文将详细讨论session的工作机制并且对在Java web application中应用session机制时常见的问题作出解答。</p>
<p>目录：<br>一、术语session<br>二、HTTP协议与状态保持<br>三、理解cookie机制<br>四、理解session机制<br>五、理解javax.servlet.http.HttpSession<br>六、HttpSession常见问题<br>七、跨应用程序的session共享<br>八、总结<br>参考文档</p>
<p id="#1"><strong>一、术语session</strong><br>在我的经验里，session这个词被滥用的程度大概仅次于transaction，更加有趣的是transaction与session在某些语境下的含义是相同的。</p>
<p>session，中文经常翻译为会话，其本来的含义是指有始有终的一系列动作/消息，比如打电话时从拿起电话拨号到挂断电话这中间的一系列过程可以
称之为一个session。有时候我们可以看到这样的话“在一个浏览器会话期间，...”，这里的会话一词用的就是其本义，是指从一个浏览器窗口打开到关
闭这个期间①。最混乱的是“用户（客户端）在一次会话期间”这样一句话，它可能指用户的一系列动作（一般情况下是同某个具体目的相关的一系列动作，比如从
登录到选购商品到结账登出这样一个网上购物的过程，有时候也被称为一个transaction），然而有时候也可能仅仅是指一次连接，也有可能是指含义
①，其中的差别只能靠上下文来推断②。</p>
<p>然而当session一词与网络协议相关联时，它又往往隐含了“面向连接”和/或“保持状态”这样两个含义，“面向连接”指的是在通信双方在通信之
前要先建立一个通信的渠道，比如打电话，直到对方接了电话通信才能开始，与此相对的是写信，在你把信发出去的时候你并不能确认对方的地址是否正确，通信渠
道不一定能建立，但对发信人来说，通信已经开始了。“保持状态”则是指通信的一方能够把一系列的消息关联起来，使得消息之间可以互相依赖，比如一个服务员
能够认出再次光临的老顾客并且记得上次这个顾客还欠店里一块钱。这一类的例子有“一个TCP session”或者“一个POP3 session”③。</p>
<p>而到了web服务器蓬勃发展的时代，session在web开发语境下的语义又有了新的扩展，它的含义是指一类用来在客户端与服务器之间保持状态的
解决方案④。有时候session也用来指这种解决方案的存储结构，如“把xxx保存在session里”⑤。由于各种用于web开发的语言在一定程度上
都提供了对这种解决方案的支持，所以在某种特定语言的语境下，session也被用来指代该语言的解决方案，比如经常把Java里提供的
javax.servlet.http.HttpSession简称为session⑥。</p>
<p>鉴于这种混乱已不可改变，本文中session一词的运用也会根据上下文有不同的含义，请大家注意分辨。<br>在本文中，使用中文“浏览器会话期间”来表达含义①，使用“session机制”来表达含义④，使用“session”表达含义⑤，使用具体的“HttpSession”来表达含义⑥</p>
<p id="#2"><strong>二、HTTP协议与状态保持</strong><br>HTTP协议本身是无状态的，这与HTTP协议本来的目的
是相符的，客户端只需要简单的向服务器请求下载某些文件，无论是客户端还是服务器都没有必要纪录彼此过去的行为，每一次请求之间都是独立的，好比一个顾客
和一个自动售货机或者一个普通的（非会员制）大卖场之间的关系一样。</p>
<p>然而聪明（或者贪心？）的人们很快发现如果能够提供一些按需生成的动态信息会使web变得更加有用，就像给有线电视加上点播功能一样。这种需求一方
面迫使HTML逐步添加了表单、脚本、DOM等客户端行为，另一方面在服务器端则出现了CGI规范以响应客户端的动态请求，作为传输载体的HTTP协议也
添加了文件上载、cookie这些特性。其中cookie的作用就是为了解决HTTP协议无状态的缺陷所作出的努力。至于后来出现的session机制则
是又一种在客户端与服务器之间保持状态的解决方案。</p>
<p>让我们用几个例子来描述一下cookie和session机制之间的区别与联系。笔者曾经常去的一家咖啡店有喝5杯咖啡免费赠一杯咖啡的优惠，然而一次性消费5杯咖啡的机会微乎其微，这时就需要某种方式来纪录某位顾客的消费数量。想象一下其实也无外乎下面的几种方案：<br>1、该店的店员很厉害，能记住每位顾客的消费数量，只要顾客一走进咖啡店，店员就知道该怎么对待了。这种做法就是协议本身支持状态。<br>2、发给顾客一张卡片，上面记录着消费的数量，一般还有个有效期限。每次消费时，如果顾客出示这张卡片，则此次消费就会与以前或以后的消费相联系起来。这种做法就是在客户端保持状态。<br>3、发给顾客一张会员卡，除了卡号之外什么信息也不纪录，每次消费时，如果顾客出示该卡片，则店员在店里的纪录本上找到这个卡号对应的纪录添加一些消费信息。这种做法就是在服务器端保持状态。</p>
<p>由于HTTP协议是无状态的，而出于种种考虑也不希望使之成为有状态的，因此，后面两种方案就成为现实的选择。具体来说cookie机制采用的是在
客户端保持状态的方案，而session机制采用的是在服务器端保持状态的方案。同时我们也看到，由于采用服务器端保持状态的方案在客户端也需要保存一个
标识，所以session机制可能需要借助于cookie机制来达到保存标识的目的，但实际上它还有其他选择。</p>
<p id="#3"><strong>三、理解cookie机制</strong> <br>cookie机制的基本原理就如上面的例子一样简单，但是还有几个问题需要解决：“会员卡”如何分发；“会员卡”的内容；以及客户如何使用“会员卡”。</p>
<p>正统的cookie分发是通过扩展HTTP协议来实现的，服务器通过在HTTP的响应头中加上一行特殊的指示以提示浏览器按照指示生成相应的cookie。然而纯粹的客户端脚本如JavaScript或者VBScript也可以生成cookie。</p>
<p>而cookie的使用是由浏览器按照一定的原则在后台自动发送给服务器的。浏览器检查所有存储的cookie，如果某个cookie所声明的作用范
围大于等于将要请求的资源所在的位置，则把该cookie附在请求资源的HTTP请求头上发送给服务器。意思是麦当劳的会员卡只能在麦当劳的店里出示，如
果某家分店还发行了自己的会员卡，那么进这家店的时候除了要出示麦当劳的会员卡，还要出示这家店的会员卡。</p>
<p>cookie的内容主要包括：名字，值，过期时间，路径和域。<br>其中域可以指定某一个域比如.google.com，相当于总店招牌，比如宝洁公司，也可以指定一个域下的具体某台机器比如www.google.com或者froogle.google.com，可以用飘柔来做比。<br>路径就是跟在域名后面的URL路径，比如/或者/foo等等，可以用某飘柔专柜做比。<br>路径与域合在一起就构成了cookie的作用范围。<br>如
果不设置过期时间，则表示这个cookie的生命期为浏览器会话期间，只要关闭浏览器窗口，cookie就消失了。这种生命期为浏览器会话期的
cookie被称为会话cookie。会话cookie一般不存储在硬盘上而是保存在内存里，当然这种行为并不是规范规定的。如果设置了过期时间，浏览器
就会把cookie保存到硬盘上，关闭后再次打开浏览器，这些cookie仍然有效直到超过设定的过期时间。</p>
<p>存储在硬盘上的cookie可以在不同的浏览器进程间共享，比如两个IE窗口。而对于保存在内存里的cookie，不同的浏览器有不同的处理方式。
对于IE，在一个打开的窗口上按Ctrl-N（或者从文件菜单）打开的窗口可以与原窗口共享，而使用其他方式新开的IE进程则不能共享已经打开的窗口的内
存cookie；对于Mozilla
Firefox0.8，所有的进程和标签页都可以共享同样的cookie。一般来说是用javascript的window.open打开的窗口会与原窗
口共享内存cookie。浏览器对于会话cookie的这种只认cookie不认人的处理方式经常给采用session机制的web应用程序开发者造成很
大的困扰。</p>
<p>下面就是一个goolge设置cookie的响应头的例子<br>HTTP/1.1 302 Found<br>Location: http://www.google.com/intl/zh-CN/<br>Set-Cookie:
PREF=ID=0565f77e132de138:NW=1:TM=1098082649:LM=1098082649:S=KaeaCFPo49RiA_d8;
expires=Sun, 17-Jan-2038 19:14:07 GMT; path=/; domain=.google.com<br>Content-Type: text/html</p>
<p align="center"><img src="http://dev2dev.bea.com.cn/images/paihang_article/041020/image002.jpg" height="293" width="408"></p>
<p><br>这是使用HTTPLook这个HTTP Sniffer软件来俘获的HTTP通讯纪录的一部分</p>
<p align="center"><img src="http://dev2dev.bea.com.cn/images/paihang_article/041020/image004.jpg" height="344" width="432"></p>
<p><br>浏览器在再次访问goolge的资源时自动向外发送cookie</p>
<p align="center"><img src="http://dev2dev.bea.com.cn/images/paihang_article/041020/image006.jpg" height="305" width="421"> </p>
<p><br>使用Firefox可以很容易的观察现有的cookie的值<br>使用HTTPLook配合Firefox可以很容易的理解cookie的工作原理。</p>
<p align="center"><img src="http://dev2dev.bea.com.cn/images/paihang_article/041020/image008.jpg" height="248" width="324"></p>
<p><br>IE也可以设置在接受cookie前询问</p>
<p align="center"><img src="http://dev2dev.bea.com.cn/images/paihang_article/041020/image010.jpg" height="249" width="239"> </p>
<p><br>这是一个询问接受cookie的对话框。</p>
<p id="#4"><strong>四、理解session机制</strong><br>session机制是一种服务器端的机制，服务器使用一种类似于散列表的结构（也可能就是使用散列表）来保存信息。</p>
<p>当程序需要为某个客户端的请求创建一个session的时候，服务器首先检查这个客户端的请求里是否已包含了一个session标识 -
称为session id，如果已包含一个session id则说明以前已经为此客户端创建过session，服务器就按照session
id把这个session检索出来使用（如果检索不到，可能会新建一个），如果客户端请求不包含session
id，则为此客户端创建一个session并且生成一个与此session相关联的session id，session
id的值应该是一个既不会重复，又不容易被找到规律以仿造的字符串，这个session id将被在本次响应中返回给客户端保存。</p>
<p>保存这个session
id的方式可以采用cookie，这样在交互过程中浏览器可以自动的按照规则把这个标识发挥给服务器。一般这个cookie的名字都是类似于
SEEESIONID，而。比如weblogic对于web应用程序生成的cookie，JSESSIONID=
ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764，它的名字就是
JSESSIONID。</p>
<p>由于cookie可以被人为的禁止，必须有其他机制以便在cookie被禁止时仍然能够把session
id传递回服务器。经常被使用的一种技术叫做URL重写，就是把session
id直接附加在URL路径的后面，附加方式也有两种，一种是作为URL路径的附加信息，表现形式为http://...../xxx;
jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764<br>另一种是作为查询字符串附加在URL后面，表现形式为http://...../xxx?jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764<br>这两种方式对于用户来说是没有区别的，只是服务器在解析的时候处理的方式不同，采用第一种方式也有利于把session id的信息和正常程序参数区分开来。<br>为了在整个交互过程中始终保持状态，就必须在每个客户端可能请求的路径后面都包含这个session id。</p>
<p>另一种技术叫做表单隐藏字段。就是服务器会自动修改表单，添加一个隐藏字段，以便在表单提交时能够把session id传递回服务器。比如下面的表单<br>&lt;form name="testform" action="/xxx"&gt;<br>&lt;input type="text"&gt;<br>&lt;/form&gt;<br>在被传递给客户端之前将被改写成<br>&lt;form name="testform" action="/xxx"&gt;<br>&lt;input type="hidden" name="jsessionid" value="ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764"&gt;<br>&lt;input type="text"&gt;<br>&lt;/form&gt;<br>这种技术现在已较少应用，笔者接触过的很古老的iPlanet6(SunONE应用服务器的前身)就使用了这种技术。<br>实际上这种技术可以简单的用对action应用URL重写来代替。</p>
<p>在谈论session机制的时候，常常听到这样一种误解“只要关闭浏览器，session就消失了”。其实可以想象一下会员卡的例子，除非顾客主动
对店家提出销卡，否则店家绝对不会轻易删除顾客的资料。对session来说也是一样的，除非程序通知服务器删除一个session，否则服务器会一直保
留，程序一般都是在用户做log
off的时候发个指令去删除session。然而浏览器从来不会主动在关闭之前通知服务器它将要关闭，因此服务器根本不会有机会知道浏览器已经关闭，之所
以会有这种错觉，是大部分session机制都使用会话cookie来保存session id，而关闭浏览器后这个session
id就消失了，再次连接服务器时也就无法找到原来的session。如果服务器设置的cookie被保存到硬盘上，或者使用某种手段改写浏览器发出的
HTTP请求头，把原来的session id发送给服务器，则再次打开浏览器仍然能够找到原来的session。</p>
<p>恰恰是由于关闭浏览器不会导致session被删除，迫使服务器为seesion设置了一个失效时间，当距离客户端上一次使用session的时间超过这个失效时间时，服务器就可以认为客户端已经停止了活动，才会把session删除以节省存储空间。</p>
<p id="#5"><strong>五、理解javax.servlet.http.HttpSession</strong><br>HttpSession是Java平台对session机制的实现规范，因为它仅仅是个接口，具体到每个web应用服务器的提供商，除了对规范支持之外，仍然会有一些规范里没有规定的细微差异。这里我们以BEA的Weblogic Server8.1作为例子来演示。</p>
<p>首先，Weblogic
Server提供了一系列的参数来控制它的HttpSession的实现，包括使用cookie的开关选项，使用URL重写的开关选项，session持
久化的设置，session失效时间的设置，以及针对cookie的各种设置，比如设置cookie的名字、路径、域，cookie的生存时间等。</p>
<p>一般情况下，session都是存储在内存里，当服务器进程被停止或者重启的时候，内存里的session也会被清空，如果设置了session的
持久化特性，服务器就会把session保存到硬盘上，当服务器进程重新启动或这些信息将能够被再次使用，Weblogic
Server支持的持久性方式包括文件、数据库、客户端cookie保存和复制。</p>
<p>复制严格说来不算持久化保存，因为session实际上还是保存在内存里，不过同样的信息被复制到各个cluster内的服务器进程中，这样即使某个服务器进程停止工作也仍然可以从其他进程中取得session。</p>
<p>cookie生存时间的设置则会影响浏览器生成的cookie是否是一个会话cookie。默认是使用会话cookie。有兴趣的可以用它来试验我们在第四节里提到的那个误解。</p>
<p>cookie的路径对于web应用程序来说是一个非常重要的选项，Weblogic Server对这个选项的默认处理方式使得它与其他服务器有明显的区别。后面我们会专题讨论。</p>
<p>关于session的设置参考[5] http://e-docs.bea.com/wls/docs70/webapp/weblogic_xml.html#1036869</p>
<p id="#6"><strong>六、HttpSession常见问题</strong><br>（在本小节中session的含义为⑤和⑥的混合）</p>
<p><br>1、session在何时被创建<br>一个常见的误解是以为session在有客户端访问时就被创建，然而事实是直到某server端程
序调用HttpServletRequest.getSession(true)这样的语句时才被创建，注意如果JSP没有显示的使用
&lt;%@page session="false"%&gt;
关闭session，则JSP文件在编译成Servlet时将会自动加上这样一条语句HttpSession session =
HttpServletRequest.getSession(true);这也是JSP中隐含的session对象的来历。</p>
<p>由于session会消耗内存资源，因此，如果不打算使用session，应该在所有的JSP中关闭它。</p>
<p>2、session何时被删除<br>综合前面的讨论，session在下列情况下被删除a.程序调用HttpSession.invalidate();或b.距离上一次收到客户端发送的session id时间间隔超过了session的超时设置;或c.服务器进程被停止（非持久session）</p>
<p>3、如何做到在浏览器关闭时删除session<br>严格的讲，做不到这一点。可以做一点努力的办法是在所有的客户端页面里使用javascript代码window.oncolose来监视浏览器的关闭动作，然后向服务器发送一个请求来删除session。但是对于浏览器崩溃或者强行杀死进程这些非常规手段仍然无能为力。</p>
<p>4、有个HttpSessionListener是怎么回事<br>你可以创建这样的listener去监控session的创建和销毁事件，使得
在发生这样的事件时你可以做一些相应的工作。注意是session的创建和销毁动作触发listener，而不是相反。类似的与HttpSession有
关的listener还有HttpSessionBindingListener，HttpSessionActivationListener和
HttpSessionAttributeListener。</p>
<p>5、存放在session中的对象必须是可序列化的吗<br>不是必需的。要求对象可序列化只是为了session能够在集群中被复制或者能够持久
保存或者在必要时server能够暂时把session交换出内存。在Weblogic
Server的session中放置一个不可序列化的对象在控制台上会收到一个警告。我所用过的某个iPlanet版本如果session中有不可序列化
的对象，在session销毁时会有一个Exception，很奇怪。</p>
<p>6、如何才能正确的应付客户端禁止cookie的可能性<br>对所有的URL使用URL重写，包括超链接，form的action，和重定向的URL，具体做法参见[6]<br>http://e-docs.bea.com/wls/docs70/webapp/sessions.html#100770</p>
<p>7、开两个浏览器窗口访问应用程序会使用同一个session还是不同的session<br>参见第三小节对cookie的讨论，对session来说是只认id不认人，因此不同的浏览器，不同的窗口打开方式以及不同的cookie存储方式都会对这个问题的答案有影响。</p>
<p>8、如何防止用户打开两个浏览器窗口操作导致的session混乱<br>这个问题与防止表单多次提交是类似的，可以通过设置客户端的令牌来解决。
就是在服务器每次生成一个不同的id返回给客户端，同时保存在session里，客户端提交表单时必须把这个id也返回服务器，程序首先比较返回的id与
保存在session里的值是否一致，如果不一致则说明本次操作已经被提交过了。可以参看《J2EE核心模式》关于表示层模式的部分。需要注意的是对于使
用javascript
window.open打开的窗口，一般不设置这个id，或者使用单独的id，以防主窗口无法操作，建议不要再window.open打开的窗口里做修改
操作，这样就可以不用设置。</p>
<p>9、为什么在Weblogic Server中改变session的值后要重新调用一次session.setValue<br>做这个动作主要是为了在集群环境中提示Weblogic Server session中的值发生了改变，需要向其他服务器进程复制新的session值。</p>
<p>10、为什么session不见了<br>排除session正常失效的因素之外，服务器本身的可能性应该是微乎其微的，虽然笔者在
iPlanet6SP1加若干补丁的Solaris版本上倒也遇到过；浏览器插件的可能性次之，笔者也遇到过3721插件造成的问题；理论上防火墙或者代
理服务器在cookie处理上也有可能会出现问题。<br>出现这一问题的大部分原因都是程序的错误，最常见的就是在一个应用程序中去访问另外一个应用程序。我们在下一节讨论这个问题。</p>
<p id="#7">七、跨应用程序的session共享<br><br>常常有这样的情况，一个大项目被分割成若干小项目开发，为了能够互不干扰，要
求每个小项目作为一个单独的web应用程序开发，可是到了最后突然发现某几个小项目之间需要共享一些信息，或者想使用session来实现SSO
(single sign on)，在session中保存login的用户信息，最自然的要求是应用程序间能够访问彼此的session。</p>
<p>然而按照Servlet规范，session的作用范围应该仅仅限于当前应用程序下，不同的应用程序之间是不能够互相访问对方的session的。
各个应用服务器从实际效果上都遵守了这一规范，但是实现的细节却可能各有不同，因此解决跨应用程序session共享的方法也各不相同。</p>
<p>首先来看一下Tomcat是如何实现web应用程序之间session的隔离的，从Tomcat设置的cookie路径来看，它对不同的应用程序设
置的cookie路径是不同的，这样不同的应用程序所用的session
id是不同的，因此即使在同一个浏览器窗口里访问不同的应用程序，发送给服务器的session id也可以是不同的。<br></p>
<p align="center"><img src="http://dev2dev.bea.com.cn/images/paihang_article/041020/image012.jpg" height="219" width="288"> <img src="http://dev2dev.bea.com.cn/images/paihang_article/041020/image014.jpg" height="215" width="257"> </p>
<p>根据这个特性，我们可以推测Tomcat中session的内存结构大致如下。<br></p>
<p align="center"><img src="http://dev2dev.bea.com.cn/images/paihang_article/041020/image016.jpg" height="278" width="444"> </p>
<p>笔者以前用过的iPlanet也采用的是同样的方式，估计SunONE与iPlanet之间不会有太大的差别。对于这种方式的服务器，解决的思路很
简单，实际实行起来也不难。要么让所有的应用程序共享一个session id，要么让应用程序能够获得其他应用程序的session id。</p>
<p>iPlanet中有一种很简单的方法来实现共享一个session id，那就是把各个应用程序的cookie路径都设为/（实际上应该是/NASApp，对于应用程序来讲它的作用相当于根）。<br>&lt;session-info&gt;<br>&lt;path&gt;/NASApp&lt;/path&gt;<br>&lt;/session-info&gt;</p>
<p>需要注意的是，操作共享的session应该遵循一些编程约定，比如在session
attribute名字的前面加上应用程序的前缀，使得setAttribute("name",
"neo")变成setAttribute("app1.name", "neo")，以防止命名空间冲突，导致互相覆盖。</p>
<p><br>在Tomcat中则没有这么方便的选择。在Tomcat版本3上，我们还可以有一些手段来共享session。对于版本4以上的
Tomcat，目前笔者尚未发现简单的办法。只能借助于第三方的力量，比如使用文件、数据库、JMS或者客户端cookie，URL参数或者隐藏字段等手
段。</p>
<p>我们再看一下Weblogic Server是如何处理session的。<br></p>
<p align="center"><img src="http://dev2dev.bea.com.cn/images/paihang_article/041020/image018.jpg" height="208" width="288"> <img src="http://dev2dev.bea.com.cn/images/paihang_article/041020/image020.jpg" height="207" width="269"> </p>
<p>从截屏画面上可以看到Weblogic Server对所有的应用程序设置的cookie的路径都是/，这是不是意味着在Weblogic
Server中默认的就可以共享session了呢？然而一个小实验即可证明即使不同的应用程序使用的是同一个session，各个应用程序仍然只能访问
自己所设置的那些属性。这说明Weblogic Server中的session的内存结构可能如下<br></p>
<p align="center"><img src="http://dev2dev.bea.com.cn/images/paihang_article/041020/image022.jpg" height="290" width="420"> </p>
<p>对于这样一种结构，在session机制本身上来解决session共享的问题应该是不可能的了。除了借助于第三方的力量，比如使用文件、数据库、
JMS或者客户端cookie，URL参数或者隐藏字段等手段，还有一种较为方便的做法，就是把一个应用程序的session放到
ServletContext中，这样另外一个应用程序就可以从ServletContext中取得前一个应用程序的引用。示例代码如下，</p>
<p>应用程序A<br>context.setAttribute("appA", session); </p>
<p>应用程序B<br>contextA = context.getContext("/appA");<br>HttpSession sessionA = (HttpSession)contextA.getAttribute("appA"); </p>
<p>值得注意的是这种用法不可移植，因为根据ServletContext的JavaDoc，应用服务器可以处于安全的原因对于context.getContext("/appA");返回空值，以上做法在Weblogic Server 8.1中通过。</p>
<p>那么Weblogic
Server为什么要把所有的应用程序的cookie路径都设为/呢？原来是为了SSO，凡是共享这个session的应用程序都可以共享认证的信息。一
个简单的实验就可以证明这一点，修改首先登录的那个应用程序的描述符weblogic.xml，把cookie路径修改为/appA访问另外一个应用程序
会重新要求登录，即使是反过来，先访问cookie路径为/的应用程序，再访问修改过路径的这个，虽然不再提示登录，但是登录的用户信息也会丢失。注意做
这个实验时认证方式应该使用FORM，因为浏览器和web服务器对basic认证方式有其他的处理方式，第二次请求的认证不是通过session来实现
的。具体请参看[7] secion 14.8 Authorization，你可以修改所附的示例程序来做这些试验。</p>
<p id="#8">八、总结<br>session机制本身并不复杂，然而其实现和配置上的灵活性却使得具体情况复杂多变。这也要求我们不能把仅仅某一次的经验或者某一个浏览器，服务器的经验当作普遍适用的经验，而是始终需要具体情况具体分析。</p>
<p>关于作者：<br>郎云鹏（dev2dev ID: hippiewolf），软件工程师，从事J2EE开发<br>电子邮件：langyunpeng@yahoo.com.cn<br>地址：大连软件园路31号科技大厦A座大连博涵咨询服务有限公司</p>
<p id="#9">参考文档：<br>[1] Preliminary Specification http://wp.netscape.com/newsref/std/cookie_spec.html<br>[2] RFC2109 http://www.rfc-editor.org/rfc/rfc2109.txt<br>[3] RFC2965 http://www.rfc-editor.org/rfc/rfc2965.txt<br>[4] The Unofficial Cookie FAQ http://www.cookiecentral.com/faq/<br>[5] http://e-docs.bea.com/wls/docs70/webapp/weblogic_xml.html#1036869<br>[6] http://e-docs.bea.com/wls/docs70/webapp/sessions.html#100770<br>[7] RFC2616 http://www.rfc-editor.org/rfc/rfc2616.txt</p></td></tr></tbody>
</table>
<img src ="http://www.blogjava.net/Iwishyou/aggbug/35013.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Iwishyou/" target="_blank">Iwishyou</a> 2006-03-13 13:34 <a href="http://www.blogjava.net/Iwishyou/articles/35013.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>批量更新的SQL</title><link>http://www.blogjava.net/Iwishyou/articles/33814.html</link><dc:creator>Iwishyou</dc:creator><author>Iwishyou</author><pubDate>Mon, 06 Mar 2006 02:59:00 GMT</pubDate><guid>http://www.blogjava.net/Iwishyou/articles/33814.html</guid><wfw:comment>http://www.blogjava.net/Iwishyou/comments/33814.html</wfw:comment><comments>http://www.blogjava.net/Iwishyou/articles/33814.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Iwishyou/comments/commentRss/33814.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Iwishyou/services/trackbacks/33814.html</trackback:ping><description><![CDATA[<style>.abc{font-size:10.5pt;}</style>
<table class="abc"><tbody><tr><td>
<font face="Arial" size="3">今天发现这种批量更新的sql在做数据补丁的时候, 很有用. <br>例如, 给某个表加上一个新的字段, mcNo, 而这个mcNo是保存在<br>saks_invoice表的一个上级表的时候, 就可以直接用SQL把saks_invoice<br>的mcNo更新了, 而不用写代码, 把上级表的mcNo都拿出来, 再来个batchupdate<br><br>update saks_invoice inv set inv.MCNO=(<br>&nbsp; select pl.mcNo from saks_packinglist pl where inv.PACKINGLISTID=pl.id<br>) ;</font>
</td></tr></tbody></table><img src ="http://www.blogjava.net/Iwishyou/aggbug/33814.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Iwishyou/" target="_blank">Iwishyou</a> 2006-03-06 10:59 <a href="http://www.blogjava.net/Iwishyou/articles/33814.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>小学生的SQL</title><link>http://www.blogjava.net/Iwishyou/articles/33504.html</link><dc:creator>Iwishyou</dc:creator><author>Iwishyou</author><pubDate>Fri, 03 Mar 2006 09:15:00 GMT</pubDate><guid>http://www.blogjava.net/Iwishyou/articles/33504.html</guid><wfw:comment>http://www.blogjava.net/Iwishyou/comments/33504.html</wfw:comment><comments>http://www.blogjava.net/Iwishyou/articles/33504.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Iwishyou/comments/commentRss/33504.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Iwishyou/services/trackbacks/33504.html</trackback:ping><description><![CDATA[<font face="Arial" size="2">作项目碰到一个问题, 如下:<br><br>两个集合, A为 n组{a, b, c}数据的集合, 而B为m组{catID, a, b, c}, <br>当A的全部成员都出现在B同组的集合内部是, A才是对B可用的, 例如:<br>A=[1][2][3]&nbsp; B=[x][1][2][3]&nbsp; 或者 B=[x][1][2][3]<br>&nbsp;&nbsp;&nbsp; [3][4][5],&nbsp;&nbsp;&nbsp;&nbsp; [x][1][2][4]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [x][3][4][5], 都称A对B可用<br></font><font face="Arial" size="2"><br>而 如果 B=</font><font face="Arial" size="2">[x][3][4][5], <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [x][1][2][3]<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [y][3][4][5]的话, 则是A对B不可用. <br><br>这样的sql, 怎么写? 想了好久, 才发现可以用小学时的数学运算解决, 通分!<br><br>&nbsp;4&nbsp;&nbsp;&nbsp;&nbsp; 9&nbsp;&nbsp;&nbsp;&nbsp; 4x11&nbsp;&nbsp;&nbsp;&nbsp; 9x7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 44&nbsp;&nbsp;&nbsp;&nbsp; 63&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 19<br>--- - --- = --------- -&nbsp; ------- = ------ - ----- = - ----<br>&nbsp;7&nbsp;&nbsp;&nbsp;&nbsp; 11&nbsp;&nbsp;&nbsp; 7x11&nbsp;&nbsp;&nbsp; 11x7&nbsp;&nbsp;&nbsp;&nbsp; 77&nbsp;&nbsp;&nbsp;&nbsp; 77&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 77<br><br><br>就是说, 要分别得到两个同样结构的sql集合, 现在来求差集, 假定只要1个A集合, <br>而B集合却有多个, 又, 假设在oracle数据库运行, 如下:<br><br>&nbsp; select (catID, a, b, c) from A, (<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (select distinct catID&nbsp; from B)&nbsp; --取B的分组, 连接A表,得到积<br>&nbsp;&nbsp;&nbsp; ) matrixA<br>&nbsp; minus&nbsp;&nbsp;&nbsp;&nbsp; --然后减去B集合<br>&nbsp; (select (catID, a, b, c) from B)<br><br>这样, 我们就可以得到A集合不适用于哪些B集合了.<br><br><br>当然, 实际情况中, 可能A集合也是多个的, 假设A集合的分类ID为catIDA, B集<br>合的分组ID为catIDB, 那么就有:<br>&nbsp; select (catIDA, catIDB, a, b, c) from A, (<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (select distinct catIDB from B)&nbsp; --取B的分组, 连接A表,得到积<br>
&nbsp;&nbsp;&nbsp; ) matrixA<br>
&nbsp; minus&nbsp;&nbsp;&nbsp;&nbsp; --然后减去B集合<br>
&nbsp; (select (catIDA, catIDB, a, b, c) from B, <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (select distinct catIDA from A)&nbsp; --取B的分组, 连接A表,得到积<br>&nbsp; )<br>这样, 我们就可以得到所有的A集合中, 哪些A集合不适用于哪些B集合了.<br><br><br><br><br></font><img src ="http://www.blogjava.net/Iwishyou/aggbug/33504.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Iwishyou/" target="_blank">Iwishyou</a> 2006-03-03 17:15 <a href="http://www.blogjava.net/Iwishyou/articles/33504.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在Jboss中发布EJB的几种方式</title><link>http://www.blogjava.net/Iwishyou/articles/28247.html</link><dc:creator>Iwishyou</dc:creator><author>Iwishyou</author><pubDate>Mon, 16 Jan 2006 15:52:00 GMT</pubDate><guid>http://www.blogjava.net/Iwishyou/articles/28247.html</guid><wfw:comment>http://www.blogjava.net/Iwishyou/comments/28247.html</wfw:comment><comments>http://www.blogjava.net/Iwishyou/articles/28247.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Iwishyou/comments/commentRss/28247.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Iwishyou/services/trackbacks/28247.html</trackback:ping><description><![CDATA[<br><br>&nbsp;&nbsp;&nbsp; 很不错的文章, 从网上摘来的.<br>&nbsp; &nbsp; <br>&nbsp; &nbsp; 引子: 我自己弄了两个ejb, 相互之间有引用, 放到Jboss 4.0 里面去发布, 我只写好了 ejb-jar.xml, jboss.xml, 却没有指定web.xml, 结果在Jsp里面用一些测试代码查找ejb的时候, 告诉我 "ejb not bound", 估计很多人也遇到和我同样的错误:<br>&nbsp;&nbsp;&nbsp; (xxxLocalHome) home = (xxxLocalHome)ic.lookup("java:comp/env/ejb/local/xxxLocalEJB");<br>但是当你使用 <br>&nbsp;&nbsp;&nbsp; (xxxLocalHome) home = (xxxLocalHome)ic.lookup("ejb/local/xxxLocalEJB");<br>却发现一切正常 ("ejb/local/xxxLocalEJB" 是在jboss.xml里面配置的xxxLocalEJB的JNDI名字), 看看下面的说明, 对号入座, 就知道为什么了<br><br><br>============================================================================================<br>&nbsp;&nbsp;&nbsp; 首先介绍JBoss容器中部署各类EJB对象的两种方法。下面的演示以Session Bean为例，客户端是一个本机上的web应用。这里不对演示程序进行具体介绍。<br>第一种方式：<br>&nbsp;&nbsp; &nbsp;把开发好的ejb jar包和web应用的war包公共放在deploy目录下。<br>演示1：不需要jboss.xml文件和其他任何特殊的设置。<br>ejb-jar.xml:<br>&nbsp;&nbsp; &nbsp;&lt;ejb-jar&gt;<br>&nbsp;&nbsp; &nbsp;······<br>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;ejb-name&gt;ejbtest&lt;/ejb-name&gt;<br>&nbsp;&nbsp; &nbsp;······<br>&nbsp;&nbsp; &nbsp;&lt;/ejb-jar&gt;<br>客户端：web应用中对web.xml不需要添加ejb信息，不需要jboss-web.xml文件。引用ejb对象的jsp文件如下：<br>&nbsp;&nbsp; &nbsp;······<br>&nbsp;&nbsp; &nbsp;InitialContext ctx = new InitialContext();<br>&nbsp;&nbsp; &nbsp;Object objref&nbsp; = ctx.lookup("ejbtest");&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;//使用&lt;ejb-name&gt;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;beanHome=(zcxejb1Home)PortableRemoteObject.narrow(objref,ejbtestHome.class);<br>&nbsp;&nbsp; &nbsp;······<br>&nbsp;&nbsp; &nbsp; <br>演示2：使用jboss.xml文件。<br>&nbsp;&nbsp; &nbsp;在缺省情况下JBoss的JNDI服务将通过ejb-jar.xml中&lt;ejb-name&gt;XXX&lt;/ejb-name&gt;中的XXX来使用EJB的home interface。但是如果有多个ejb对象在相同的ejb jar包中，在ejb-jar.xml中通过&lt;ejb-name&gt;XXX&lt;/ejb-name&gt;就可能不能很好的表示某一个ejb对象，所以一般我们希望可以提供一些附加的信息，例如采用这样的格式"[应用名]/[bean名]"来引用一个EJB对象。这时JNDI服务就可能不能正确地找到你的ejb对象，我们就需要使用jboss.xml文件，通过它实现jndi 名到ejb名的重定向。这个文件必须和ejb-jar.xml一起放到META-INFO目录下。<br>ejb-jar.xml:<br>&lt;ejb-jar&gt;<br>&nbsp;&nbsp; &nbsp;······<br>&nbsp;&nbsp; &nbsp;&lt;ejb-name&gt;ejbtest&lt;/ejb-name&gt;<br>&nbsp;&nbsp; &nbsp;······<br>&lt;/ejb-jar&gt;<br>jboss.xml:<br>&lt;jboss&gt;<br>&nbsp;&nbsp; &nbsp;&lt;ejb-name&gt;ejbtest&lt;/ejb-name&gt;<br>&nbsp;&nbsp; &nbsp;&lt;jndi-name&gt;example/ejbtest&lt;/jndi-name&gt;<br>&lt;/jboss&gt;<br>&nbsp;<br>客户端：需要使用新的jndi名进行ejb定位。<br>······<br>&nbsp;&nbsp; &nbsp;InitialContext ctx = new InitialContext();<br>&nbsp;&nbsp; &nbsp;Object objref&nbsp; = ctx.lookup("example/ejbtest");&nbsp;&nbsp; &nbsp;//使用&lt;jndi-name&gt;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;beanHome=(zcxejb1Home)PortableRemoteObject.narrow(objref,ejbtestHome.class);<br>······<br>第二种方式： <br>&nbsp;&nbsp; &nbsp;把ejb和web应用包装成一个企业应用包。部署ear时可以简单地把通过application.xml描述ejb jar包和web应用的war包，同样在web.war中不需要提供特殊的信息就可以和第一种方式一样使用ejb对象。客户端代码也不需要进行改动。这里不再举例说明。<br>&nbsp;&nbsp; &nbsp;此外我们可以进行更进一步的部署，这时需要使用到web.xml和jboss-web.xml。jboss-web.xml是JBoss提供的一个针对web应用进行配置的文件。jboss-web.xml和web.xml一起放在web应用的WEB-INF目录下。<br>演示1：改动web.xml文件，添加&lt;ejb-ref&gt;标记，不使用jboss-web.xml文件。<br>&nbsp;&nbsp; &nbsp;（注意&lt;ejb-ref&gt;包括内部引用和外部引用。如果是同一个单元的可以通过&lt;ejb-link&gt;直接进行引用，而不用提供其他信息。）<br>web.xml:<br>······<br>&lt;ejb-ref&gt;<br>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &lt;ejb-ref-name&gt;ejb/ejbtest&lt;/ejb-ref-name&gt;&nbsp; &lt;!--采用sun推荐的命名方式--&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;ejb-ref-type&gt;Session&lt;/ejb-ref-type&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;home&gt;org.zcx.test.zcxejb1Home&lt;/home&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;remote&gt;org.zcx.test.zcxejb1&lt;/remote&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;ejb-link&gt;ejbtest&lt;/ejb-link&gt;&nbsp;&nbsp;&nbsp; &lt;!--必须和被应用的ejb-name匹配--&gt;<br>&lt;/ejb-ref&gt;<br>······<br>客户端：由于在web.xml中引入ejb引用描述这时ejb定位发生了变化：<br>······<br>&nbsp;&nbsp; &nbsp;InitialContext ctx = new InitialContext();<br>&nbsp;&nbsp; &nbsp;Object objref&nbsp; = ctx.lookup("java:comp/env/ ejb/ejbtest ");&nbsp;&nbsp; &nbsp;//使用java:comp/env命名空间&nbsp;&nbsp; &nbsp;beanHome=(zcxejb1Home)PortableRemoteObject.narrow(objref,ejbtestHome.class);<br>······<br>&nbsp;&nbsp; &nbsp; <br>演示2：联合使用web.xml和jboss-web.xml<br>web.xml<br>······<br>&lt;ejb-ref&gt;<br>&nbsp;&nbsp; &nbsp;&lt;ejb-ref-name&gt;ejb/ejbtest&lt;/ejb-ref-name&gt;&nbsp; &lt;!--采用sun推荐的命名方式--&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;ejb-ref-type&gt;Session&lt;/ejb-ref-type&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;home&gt;org.zcx.test.zcxejb1Home&lt;/home&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;remote&gt;org.zcx.test.zcxejb1&lt;/remote&gt;<br>&lt;/ejb-ref&gt;<br>······<br>jboss-web.xml<br>&lt;ejb-ref&gt;<br>&nbsp;&nbsp; &nbsp;&lt;ejb-ref-name&gt; ejb/ejbtest &lt;/ejb-ref-name&gt;<br>&nbsp;&nbsp; &nbsp;&lt;jndi-name&gt; example/ejbtest &lt;/jndi-name&gt; &lt;!-- 这里对应ejb对象的jndi名--&gt;<br>&lt;/ejb-ref&gt;<br>客户端：<br>&nbsp;&nbsp; &nbsp;nitialContext ctx = new InitialContext();<br>&nbsp;&nbsp; &nbsp;Object objref&nbsp; = ctx.lookup("java:comp/env/ ejb/ejbtest ");&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;beanHome=(zcxejb1Home)PortableRemoteObject.narrow(objref,ejbtestHome.class);<br>&nbsp;<br>以上的所有演示说明了ejb-jar.xml、jboss.xml、web.xml、jboss-web.xml之间的基本关系和它们的使用方式。它们是部署各类ejb对象的关键文件。接下来介绍针对不同类型的ejb对象所需要的特殊配置。<img src ="http://www.blogjava.net/Iwishyou/aggbug/28247.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Iwishyou/" target="_blank">Iwishyou</a> 2006-01-16 23:52 <a href="http://www.blogjava.net/Iwishyou/articles/28247.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转载: Digister 学习笔记 一</title><link>http://www.blogjava.net/Iwishyou/articles/21946.html</link><dc:creator>Iwishyou</dc:creator><author>Iwishyou</author><pubDate>Wed, 30 Nov 2005 05:25:00 GMT</pubDate><guid>http://www.blogjava.net/Iwishyou/articles/21946.html</guid><wfw:comment>http://www.blogjava.net/Iwishyou/comments/21946.html</wfw:comment><comments>http://www.blogjava.net/Iwishyou/articles/21946.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Iwishyou/comments/commentRss/21946.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Iwishyou/services/trackbacks/21946.html</trackback:ping><description><![CDATA[<p>　　在windows下开发程序，用M$提供的接口处理.ini文件或管理注册表的键值是非常方便的。在java平台上开发程序，则习惯于以xml
格式的文件来存放系统的配置信息，对这种文件的解析和处理，可以用sax或dom。有没有更简便的方法呢？有，就是用digester模块。<br>
　　Digester是Jakarta 子项目Commons下的一个模块，支持基于规则的对任意XML文档的处理。它最初是Structs项目的一部分，后因其通用性而划归Commons.<br>
</p>

<a name="more"></a>
<h4>下载及编译</h4><div class="code">cvs -d :pserver:anoncvs@cvs.apache.org:/home/cvspublic login<br>
password: anoncvs<br>
cvs -d :pserver:anoncvs@cvs.apache.org:/home/cvspublic checkout jakarta-commons/digester<br>
cd jakarta-commons/digester<br>
ant dist<br>
</div><br>
　　Digester的运行依赖下列包：<br>
<ol><li>一个遵循Jaxp(1.1版本及以后)的XML解析器</li><br><li>Jakarta commons beanutils包(1.5版本及以后)</li><br><li>Jakarta commons collections包(2.1版本及以后)</li><br><li>Jakarta commons logging包(1.0.2版本及以后)</li></ol>　<br>
<h4>一个简单的例子</h4>　　假定有两个JavaBean如下，分别为Foo和Bar<br>
<div class="code">package mypackage;<br>
public class Foo {<br>
&nbsp;&nbsp;public void addBar(Bar bar);<br>
&nbsp;&nbsp;public Bar findBar(int id);<br>
&nbsp;&nbsp;public Iterator getBars();<br>
&nbsp;&nbsp;public String getName();<br>
&nbsp;&nbsp;public void setName(String name);<br>
}<br>
public mypackage;<br>
public class Bar {<br>
&nbsp;&nbsp;public int getId();<br>
&nbsp;&nbsp;public void setId(int id);<br>
&nbsp;&nbsp;public String getTitle();<br>
&nbsp;&nbsp;public void setTitle(String title);<br>
}</div><br>
　　用下面的xml文件进行配置<br>
<div class="code">&lt;foo name="The Parent"&gt;<br>
&nbsp;&nbsp;&lt;bar id="123" title="The First Child"/&gt;<br>
&nbsp;&nbsp;&lt;bar id="456" title="The Second Child"/&gt;<br>
&lt;/foo&gt;</div><br>
　　用下面几行代码即可完成配置文件解析工作：<br>
<table border="1"><tbody><tr><td>Digest解析代码</td><td>注释</td></tr><tr><td>Digester digester = new Digester();</td><td><br></td></tr><tr><td>digester.setValidating(false);</td><td>不进行XML与相应的DTD的合法性验证</td></tr><tr><td>digester.addObjectCreate("foo", "mypackage.Foo");</td><td>当遇到&lt;foo&gt;时创建一个mypackage.Foo对象，并将其放在栈顶</td></tr><tr><td>digester.addSetProperties("foo");</td><td>根据&lt;foo&gt;元素的属性(attribute)，对刚创建的Foo对象的属性(property)进行设置</td></tr><tr><td>digester.addObjectCreate("foo/bar", "mypackage.Bar");</td><td>当遇到&lt;foo&gt;的子元素&lt;bar&gt;时创建一个mypackage.Bar对象，并将其放在栈顶。</td></tr><tr><td>digester.addSetProperties("foo/bar");</td><td>根据&lt;bar&gt;元素的属性(attribute)，对刚创建的Bar对象的属性(property)进行设置</td></tr><tr><td>digester.addSetNext("foo/bar", "addBar", "mypackage.Bar");</td><td>当再次遇到&lt;foo&gt;的子元素&lt;bar&gt;时创建一个mypackage.Bar对象，并将其放在栈顶，同时调用第二栈顶元素(Foo对象)的addBar方法。</td></tr><tr><td>Foo foo = (Foo) digester.parse();</td><td>分析结束后，返回根元素。</td></tr></tbody></table><br>
<h4>基本情况</h4>　　熟悉用SAX来处理XML文档的程序员，会发现Digester隐藏了遍历XML元素这些细节，而是提供了更高一层的、更友好的SAX事件接口，从而让程序员的精力放在对数据的处理过程中。<br>
　　使用Digester，须按照以下步骤：<br>
<ol><li>创建一个org.apache.commons.digester.Digester实例。一个解析请求完成后，这个Digester可以被后面复用。但也不要试图在不同的线程中从共享一个Digester实例。</li><br><li>根据需要设置一些配置属性(configuration properties)，以控制下一步的解析操作。</li><br><li>将一个或几个初始对象(initial object)压入Digester对象栈,本步骤不是必须的。</li><br><li>注册所有的元素匹配模板(elemet matching pattern)。当一个模板被从输入文档中识别出来以后，与其相联系的处理规则(processing rules)被激活。对一个特定的模板，可以定义任意多的规则，当识别出该模板后，这些规则依序依次执行。</li><br><li>调用digester.parse()方法，一个XML文档的引用(用多种方式供选择)要传给这个方法。注意，需要捕捉并处理IOException或SAXEception或处理过程中抛出的异常。</li></ol><br>
<h4>元素匹配模板</h4>　　Digester能自动遍历目标XML文档的元素形成的层次结构，这个过程无需程序员参与。程序员的任务是决定，在解析的过程中，当由嵌套的元素形成的一个特定序列被识别出时，如何处理它。用以描述这种序列的机制，就叫“元素匹配模板”。<br>
　　具体说来，元素和其子元素间，用”/”相隔，如果一些元素前没有”/”则其必为根元素。如例：<br>
<div class="code">&lt;a&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;--&nbsp;匹配模板&nbsp;"a"<br>
&nbsp;&nbsp;&lt;b&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;--&nbsp;匹配模板&nbsp;"a/b"<br>
&nbsp;&nbsp;&nbsp;&nbsp;&lt;c/&gt;&nbsp;&nbsp;&nbsp;&nbsp;--&nbsp;匹配模板&nbsp;"a/b/c"<br>
&nbsp;&nbsp;&nbsp;&nbsp;&lt;c/&gt;&nbsp;&nbsp;&nbsp;&nbsp;--&nbsp;匹配模板&nbsp;"a/b/c"<br>
&nbsp;&nbsp;&lt;/b&gt;<br>
&nbsp;&nbsp;&lt;b&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;--&nbsp;匹配模板&nbsp;"a/b"<br>
&nbsp;&nbsp;&nbsp;&nbsp;&lt;c/&gt;&nbsp;&nbsp;&nbsp;&nbsp;--&nbsp;匹配模板&nbsp;"a/b/c"<br>
&nbsp;&nbsp;&nbsp;&nbsp;&lt;c/&gt;&nbsp;&nbsp;&nbsp;&nbsp;--&nbsp;匹配模板&nbsp;"a/b/c"<br>
&nbsp;&nbsp;&nbsp;&nbsp;&lt;c/&gt;&nbsp;&nbsp;&nbsp;&nbsp;--&nbsp;匹配模板&nbsp;"a/b/c"<br>
&nbsp;&nbsp;&lt;/b&gt;<br>
&lt;/a&gt;</div><br>
　　字符”*”表示任意级别，如”*/a”表示任意级别的&lt;a&gt;都可匹配(不包括根元素级的).熟悉XLST的朋友，对这种思路一定不陌生。<br>
　　从上面的描述，可知某个元素同时满足多个匹配模板是非常可能的，在这种情况下，与各个模板相关联的处理规则（processing rule）的执行顺序如下：对begin或body方法，按照各个rule的注册顺序的先后，对end方法则是注册顺序的反序。<br>
<h4>处理规则(processing rule)</h4>　　元素匹配模板用以识别什么时候采取行动，处理规则则用以定义行动的内容。<br>
　　从形式上讲，一个处理规则是一个java类，它扩展了org.apache.commons.digester.Rule类。每个处理规则，实现下列
的一个或几个事件处理方法(event method)，当相应的模板匹配成功以后，在已定义的某个时刻，这些事件方法会被触发。<br>
<ol><li>begin(),在一个匹配元素被识别出后的“开始”时刻被调用，这个元素的所有属性放在一个数据结构中被传递给begin()</li><br><li>body(),当元素的嵌套内容（如子元素）被识别出时被调用。在解析的过程中，前后的空白被去掉了</li><br><li>end(),匹配元素的“结束”时刻被调用。如果子元素也匹配相关的规则，则这些规则的方法需都执行毕，才能达到该元素的“结束”时刻。</li><br><li>finish(),解析结束时被调用，以提供给各个规则以清理临时数据的机会。</li></ol><br>
　　在设置digester时，通过调用addRule()方法，来注册一个特定的元素匹配模板以及相应的一个Rule类的实例。如上所述，Rule类中的事件处理方法，会在适当的时间被调用。这个机制，允许动态地生成Rule的实现。<br>
　　另外，digester也提供了一些处理常见情况的处理规则类。<br>
<ol><li>ObjectCreateRule,当begin()方法被调用时，这个规则类实例化一个指定的java类，并将其压入栈顶。这个被实例
化的类的名字，默认是这个规则类构造函数得到的参数，也可以通过指定正在处理的xml元素的属性来传递一个新的类的名字。当end()方法被调用　时，栈
顶的对象被弹出，Digester中对它的任何引用将被忽略。</li><br><li>FactoryCreateRule,一个非常有用的ObjectCreateRule的变体。</li><br><li>SetPropertiesRule,当begin()方法被调用时，digester使用标准的Java Relection
API来识别JavaBean的属性设置方法(setter
method)，这些方法名称中包含属性（property）的名字，这些属性与XML元素的属性(attribute)匹配，于是这些方法被调用并将相
应的属性值(attribute
value)传给它们。这些自然的映射可以被重写。建议不要过度使用这项功能，在大多数情况下，使用标准的BeanInfo机制会更好。</li><br><li>SetPropertyRule,当begin()方法被调用时，digester调用栈顶对象的一个特定的属性设置方法(property
setter)并传给它特定的值(property和值分别由两个attribute命名)。这对XML需要遵循一个指定的DTD时比较有用，你可以设置
一个特别的属性(property)，虽然在指定DTD没有attribute与其相对应。</li><br><li>SetNextRule,当end()方法被调用时，digester分析第二栈顶元素，寻找一个特定属性(property)的设置方法
(setter
method)，并接着调用这个方法，以栈顶的元素作参数。这个规则通常用来在两个对象间建立1对多的关系，所用的方法也常被叫做addChild什么
的。</li><br><li>SetTopRule,当end()方法被调用时，digester分析栈顶元素，寻找一个特定属性(property)的设置方法
(setter
method)，并接着调用这个方法，以第二栈顶的元素作参数。这个规则通常用来在两个对象间建立1对多的关系，所用的方法也常被叫做setParent
什么的。</li><br><li>CallMethodRule,这个规则设置当end()被调用时执行的栈顶对象的自定义方法，通过对这个规则的设置，来指定方法的名字、参数的数量以及定义的参数类型的Java类的名字。实际的参数值，来自激活这个方法的元素的子元素。</li><br><li>CallParamRule,这个规则用来指定CallMethodRule的参数的值的来源，它可以来自一个特定的属性，或子元素的body的内容.</li><br><li>NodeCreateRule,一个特殊的规则，将对象树的一部分转换成一个DOM结点(Node)，并压入栈顶。</li></ol><br>
　　对这些标准的规则类，可以创建它们的实例，并调用digester.addRule来注册它们。由于经常使用它们，所以digester定义了一些简便的方法来注册它们。如：<div class="code">Rule rule = new SetNextRule(digester, "addChild","com.mycompany.mypackage.MyChildClass");<br>
digester.addRule("a/b/c", rule);</div>可以用下列代码替换<div class="code">digester.addSetNext("a/b/c", "addChild",                        "com.mycompany.mypackage.MyChildClass");</div><br>


<span class="posted">Posted by Hilton at October 23, 2003 11:26 PM
| <a href="http://hedong.3322.org/mt/mt-tb.cgi?__mode=view&amp;entry_id=333" onclick="OpenTrackback(this.href); return false">TrackBack</a>

<br></span>            <p><em><font size="2">在保留http://www.javajia.com原出处的情况下，欢迎转载!</font></em></p><img src ="http://www.blogjava.net/Iwishyou/aggbug/21946.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Iwishyou/" target="_blank">Iwishyou</a> 2005-11-30 13:25 <a href="http://www.blogjava.net/Iwishyou/articles/21946.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>