<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>java随笔</title><link>http://www.mscenter.edu.cn/blog/wangpeng/</link><description /><managingEditor>angel</managingEditor><dc:language>zh-CHS</dc:language><generator>.Text Version 0.958.2004.214</generator><item><dc:creator>angel</dc:creator><title>[实用技巧]怎么在html中嵌入一个文件内容</title><link>http://www.mscenter.edu.cn/blog/wangpeng/archive/2005/10/11/6143.html</link><pubDate>Mon, 10 Oct 2005 16:28:00 GMT</pubDate><guid>http://www.mscenter.edu.cn/blog/wangpeng/archive/2005/10/11/6143.html</guid><wfw:comment>http://www.mscenter.edu.cn/blog/wangpeng/comments/6143.html</wfw:comment><comments>http://www.mscenter.edu.cn/blog/wangpeng/archive/2005/10/11/6143.html#Feedback</comments><slash:comments>14</slash:comments><wfw:commentRss>http://www.mscenter.edu.cn/blog/wangpeng/comments/commentRss/6143.html</wfw:commentRss><trackback:ping>http://www.mscenter.edu.cn/blog/wangpeng/services/trackbacks/6143.html</trackback:ping><description>&lt;TABLE style="BORDER-COLLAPSE: collapse" cellSpacing=0 cellPadding=1 width="96%" align=center border=0&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD class=article_title id=Title align=middle height=26&gt;
&lt;DIV align=center&gt;[实用技巧]怎么在html中嵌入一个文件内容&lt;/DIV&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD class=unnamed1 align=middle height=30&gt;&lt;SPAN style="FONT-SIZE: 9pt"&gt;日期：&lt;/SPAN&gt;2002:9:3 &amp;#183;来源：52w.net &lt;SPAN style="FONT-SIZE: 9pt"&gt;&amp;nbsp;&lt;B&gt;查看&lt;/B&gt;:[&lt;A href="javascript:doZoom(12)"&gt;&lt;FONT color=#759de1&gt;大字体&lt;/FONT&gt;&lt;/A&gt;&lt;FONT color=#759de1&gt; &lt;/FONT&gt;&lt;A href="javascript:doZoom(10.5)"&gt;&lt;FONT color=#759de1&gt;中字体&lt;/FONT&gt;&lt;/A&gt;&lt;FONT color=#759de1&gt; &lt;/FONT&gt;&lt;A href="javascript:doZoom(9)"&gt;&lt;FONT color=#759de1&gt;小字体&lt;/FONT&gt;&lt;/A&gt;]&lt;/SPAN&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD id=zoom&gt;&lt;BR&gt;
&lt;SCRIPT language=javascript src="http://www.6to23.com/ad/it/ad_it.js"&gt;&lt;/SCRIPT&gt;
&lt;BR&gt;在html文件引入其它html文件的几种方法 &lt;BR&gt;简介：在论坛中常常有网友问到，可以在一个html的文件当中读取另一个html文件的内容吗？答案是确定的，而且方法不只一种，在以前我只会使用iframe来引用，后来发现了另外的几种方法，那今天就总结这几种方法让大家参考一下，本人觉得第三种方式较好！ &lt;BR&gt;1.IFrame引入，看看下面的代码 &lt;BR&gt;&lt;BR&gt;-------------------------------------------------------------------------------- &lt;BR&gt;&amp;lt;IFRAME NAME="content_frame" width=100% height=30 marginwidth=0 marginheight=0 SRC="import.htm" &amp;gt;&amp;lt;/IFRAME&amp;gt; &lt;BR&gt;-------------------------------------------------------------------------------- &lt;BR&gt;&lt;BR&gt;你会看到一个外部引入的文件，但会发现有一个类似外框的东西将其包围，可使用 &lt;BR&gt;&lt;BR&gt;-------------------------------------------------------------------------------- &lt;BR&gt;&amp;lt;iframe name="content_frame" marginwidth=0 marginheight=0 width=100% height=30 src="import.htm" frameborder=0&amp;gt;&amp;lt;/iframe&amp;gt; &lt;BR&gt;-------------------------------------------------------------------------------- &lt;BR&gt;&lt;BR&gt;但你会发现还会有点问题，就是背景色不同，你只要在引入的文件import.htm中使用相同的背景色也可以，但如果你使用的是IE5.5的话，可以看看这篇关于透明色的文章 如果想引入的文件过长时不出现滚动条的话在import.htm中的body中加入scroll=no &lt;BR&gt;&lt;BR&gt;2.&amp;lt;object&amp;gt;方式 &lt;BR&gt;&lt;BR&gt;&lt;BR&gt;-------------------------------------------------------------------------------- &lt;BR&gt;&amp;lt;object style="border:0px" type="text/x-scriptlet" data="import.htm" width=100% height=30&amp;gt;&amp;lt;/object&amp;gt; &lt;BR&gt;-------------------------------------------------------------------------------- &lt;BR&gt;&lt;BR&gt;3.Behavior的download方式 &lt;BR&gt;&lt;BR&gt;-------------------------------------------------------------------------------- &lt;BR&gt;&amp;lt;span id=showImport&amp;gt;&amp;lt;/span&amp;gt; &lt;BR&gt;&amp;lt;IE:Download ID="oDownload" STYLE="behavior:url(#default#download)" /&amp;gt; &lt;BR&gt;&amp;lt;script&amp;gt; &lt;BR&gt;function onDownloadDone(downDate){ &lt;BR&gt;showImport.innerHTML=downDate &lt;BR&gt;} &lt;BR&gt;oDownload.startDownload('import.htm',onDownloadDone) &lt;BR&gt;&amp;lt;/script&amp;gt; &lt;BR&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;img src ="http://www.mscenter.edu.cn/blog/wangpeng/aggbug/6143.html" width = "1" height = "1" /&gt;</description></item><item><dc:creator>angel</dc:creator><title>java调用外部命令</title><link>http://www.mscenter.edu.cn/blog/wangpeng/archive/2005/06/02/2995.html</link><pubDate>Thu, 02 Jun 2005 15:37:00 GMT</pubDate><guid>http://www.mscenter.edu.cn/blog/wangpeng/archive/2005/06/02/2995.html</guid><wfw:comment>http://www.mscenter.edu.cn/blog/wangpeng/comments/2995.html</wfw:comment><comments>http://www.mscenter.edu.cn/blog/wangpeng/archive/2005/06/02/2995.html#Feedback</comments><slash:comments>341</slash:comments><wfw:commentRss>http://www.mscenter.edu.cn/blog/wangpeng/comments/commentRss/2995.html</wfw:commentRss><trackback:ping>http://www.mscenter.edu.cn/blog/wangpeng/services/trackbacks/2995.html</trackback:ping><description>--&amp;nbsp;&amp;nbsp;作者：wnsaaa777&lt;BR&gt;--&amp;nbsp;&amp;nbsp;发布时间：2005-1-20 20:47:00&lt;BR&gt;&lt;BR&gt;--&amp;nbsp;&amp;nbsp;实用实例之（24）java调用外部命令&lt;BR&gt;
&lt;P&gt;/*&lt;BR&gt;* TestCmd.java&lt;BR&gt;*&lt;BR&gt;* Created on 2005年1月20日, 下午7:07&lt;BR&gt;*/&lt;/P&gt;
&lt;P&gt;/**&lt;BR&gt;*&lt;BR&gt;* @author&amp;nbsp;&amp;nbsp;Administrator&lt;BR&gt;*/&lt;BR&gt;public class TestCmd {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public TestCmd(){}&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public static void main(String args[]){&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Process process = Runtime.getRuntime().exec("cmd.exe&amp;nbsp;&amp;nbsp;/c&amp;nbsp;&amp;nbsp;start&amp;nbsp;&amp;nbsp;&lt;A href="http://www.hao123.net/" target=_blank&gt;&lt;FONT color=#000000&gt;http://www.hao123.net/&lt;/FONT&gt;&lt;/A&gt;");&amp;nbsp;&amp;nbsp;//登录网站&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // Process process = Runtime.getRuntime().exec("cmd.exe&amp;nbsp;&amp;nbsp;/c&amp;nbsp;&amp;nbsp;start&amp;nbsp;&amp;nbsp;ping 10.5.2.19");&amp;nbsp;&amp;nbsp;//调用Ping命令&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}catch (Exception&amp;nbsp;&amp;nbsp;e)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;e.printStackTrace();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&amp;nbsp;&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&amp;nbsp;&lt;/P&gt;&lt;img src ="http://www.mscenter.edu.cn/blog/wangpeng/aggbug/2995.html" width = "1" height = "1" /&gt;</description></item><item><dc:creator>angel</dc:creator><title>在可执行jar 包中动态载入第三方jar class的有关问题 王旭科</title><link>http://www.mscenter.edu.cn/blog/wangpeng/archive/2005/05/24/2739.html</link><pubDate>Tue, 24 May 2005 06:35:00 GMT</pubDate><guid>http://www.mscenter.edu.cn/blog/wangpeng/archive/2005/05/24/2739.html</guid><wfw:comment>http://www.mscenter.edu.cn/blog/wangpeng/comments/2739.html</wfw:comment><comments>http://www.mscenter.edu.cn/blog/wangpeng/archive/2005/05/24/2739.html#Feedback</comments><slash:comments>63</slash:comments><wfw:commentRss>http://www.mscenter.edu.cn/blog/wangpeng/comments/commentRss/2739.html</wfw:commentRss><trackback:ping>http://www.mscenter.edu.cn/blog/wangpeng/services/trackbacks/2739.html</trackback:ping><description>&lt;P&gt;
&lt;TABLE cellSpacing=0 cellPadding=0 width="100%" border=0&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD class="t12 black" align=middle width=520 height=26&gt;&lt;/TD&gt;
&lt;TD width=10&gt;&amp;nbsp;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD width=10&gt;&amp;nbsp;&lt;/TD&gt;
&lt;TD align=middle&gt;&lt;/TD&gt;
&lt;TD width=10&gt;&amp;nbsp;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD width=10&gt;&amp;nbsp;&lt;/TD&gt;
&lt;TD align=middle width=520&gt;
&lt;TABLE height=200 width=520 border=0&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style="FONT-SIZE: 14px; TEXT-INDENT: 25px; LINE-HEIGHT: 20px" vAlign=top&gt;一、前言 
&lt;P&gt;&lt;/P&gt;
&lt;P class=newtext&gt;&lt;/P&gt;
&lt;P class=newtext&gt;在商业化开发中经常是将开发的类打成jar包发布．由于有很多第三方的提供功能集合Jar包，所以经常会用到这些功能包．以下情景是很多Java开发人员经常碰到的:在开发，调试阶段，通过在CL 
&lt;TABLE style="MARGIN: 10px 7px 3px 4px" cellSpacing=0 cellPadding=0 align=left border=0&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD&gt;
&lt;SCRIPT language=JavaScript1.1 src="http://ad.ccw.com.cn/adshow.asp?positionID=38&amp;amp;js=1&amp;amp;innerJs=1"&gt;&lt;/SCRIPT&gt;

&lt;OBJECT codeBase=http://active.macromedia.com/flash2/cabs/swflash.cab#version=4,0,0,0 height=300 width=360 classid=clsid:D27CDB6E-AE6D-11cf-96B8-444553540000&gt;&lt;PARAM NAME="_cx" VALUE="7620"&gt;&lt;PARAM NAME="_cy" VALUE="6350"&gt;&lt;PARAM NAME="FlashVars" VALUE=""&gt;&lt;PARAM NAME="Movie" VALUE="http://imgs.ccw.com.cn/200505/SAP_360_300.swf"&gt;&lt;PARAM NAME="Src" VALUE="http://imgs.ccw.com.cn/200505/SAP_360_300.swf"&gt;&lt;PARAM NAME="WMode" VALUE="Window"&gt;&lt;PARAM NAME="Play" VALUE="-1"&gt;&lt;PARAM NAME="Loop" VALUE="-1"&gt;&lt;PARAM NAME="Quality" VALUE="High"&gt;&lt;PARAM NAME="SAlign" VALUE=""&gt;&lt;PARAM NAME="Menu" VALUE="-1"&gt;&lt;PARAM NAME="Base" VALUE=""&gt;&lt;PARAM NAME="AllowScriptAccess" VALUE="always"&gt;&lt;PARAM NAME="Scale" VALUE="ShowAll"&gt;&lt;PARAM NAME="DeviceFont" VALUE="0"&gt;&lt;PARAM NAME="EmbedMovie" VALUE="0"&gt;&lt;PARAM NAME="BGColor" VALUE=""&gt;&lt;PARAM NAME="SWRemote" VALUE=""&gt;&lt;PARAM NAME="MovieData" VALUE=""&gt;&lt;PARAM NAME="SeamlessTabbing" VALUE="1"&gt;
&lt;embed src='http://imgs.ccw.com.cn/200505/SAP_360_300.swf' quality=high 
pluginspage='http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash' 
type='application/x-shockwave-flash' width='360' 
height='300'&gt;&lt;/EMBED&gt;&lt;/OBJECT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;ASSPATH中设置第三方的jar包路径，自己编写的class工作正常．开发完毕,部署的时候，将开发的class打成一个可执行jar包,会发现通过Class.forName(String classname) 或ClassLoader.getSystemClassLoader().loadClass(String classname)来动态载入存在于第三方jar包中的class会抛出异常&amp;#8221; ClassNotFoundException．&lt;/P&gt;
&lt;P class=newtext&gt;这种问题存在于通过jar &amp;#8211;jar yourself.jar 来运行jar包,并在jar中的class中通过Class.forName(String classname)来动态载入第三方的class的时候．&lt;/P&gt;
&lt;P class=newtext&gt;常见的应用,比如根据用户的选择配置,动态载入不同厂商的JDBC Driver.&lt;/P&gt;
&lt;P class=newtext&gt;&lt;/P&gt;
&lt;P class=newtext&gt;二、背景知识&lt;/P&gt;
&lt;P class=newtext&gt;自JDK 1.2以后,JVM采用了委托(delegate)模式来载入class．采用这种设计的原因可以参考http://java.sun.com/docs/books/tutorial/ext/basics/load.html &lt;/P&gt;
&lt;P class=newtext&gt;归纳来讲:是基于JVM sandbox(沙盒)安装模型上提供应用层的可定制的安全机制.&lt;/P&gt;
&lt;P class=newtext&gt;&lt;/P&gt;
&lt;P class=newtext&gt;三、Java虚拟机(JVM)寻找Class的顺序&lt;/P&gt;
&lt;P class=newtext&gt;3.1 Bootstrap classes&lt;/P&gt;
&lt;P class=newtext&gt;属于Java 平台核心的class,比如java.lang.String等.及rt.jar等重要的核心级别的class.这是由JVM Bootstrap class loader来载入的.一般是放置在{java_home}\jre\lib目录下&lt;/P&gt;
&lt;P class=newtext&gt;3.2 Extension classes&lt;/P&gt;
&lt;P class=newtext&gt;基于Java扩展机制,用来扩展Java核心功能模块.比如Java串口通讯模块comm.jar.一般放置在{Java_home}\jre\lib\ext目录下&lt;/P&gt;
&lt;P class=newtext&gt;3.3 User classes&lt;/P&gt;
&lt;P class=newtext&gt;开发人员或其他第三方开发的Java程序包.通过命令行的-classpath或-cp,或者通过设置CLASSPATH环境变量来引用.JVM通过放置在{java_home}\lib\tools.jar 来寻找和调用用户级的class.常用的javac也是通过调用tools.jar来寻找用户制定的编译Java源程序.这样就引出了User class路径搜索的顺序或优先级别的问题.&lt;/P&gt;
&lt;P class=newtext&gt;3.3.1 缺省值:调用Java或javawa的当前路径(.),是开发的class所存在的当前目录&lt;/P&gt;
&lt;P class=newtext&gt;3.3.2 CLASSPATH环境变量设置的路径.如果设置了CLASSPATH,则CLASSPATH的值会覆盖缺省值&lt;/P&gt;
&lt;P class=newtext&gt;3.3.3 执行Java的命令行-classpath或-cp的值,如果制定了这两个命令行参数之一,它的值会覆盖环境变量CLASSPATH的值&lt;/P&gt;
&lt;P class=newtext&gt;3.3.4 -jar 选项:如果通过java &amp;#8211;jar 来运行一个可执行的jar包,这当前jar包会覆盖上面所有的值.换句话说,-jar 后面所跟的jar包的优先级别最高,如果指定了-jar选项,所有环境变量和命令行制定的搜索路径都将被忽略.JVM APPClassloader将只会以jar包为搜索范围.有关可执行jar有许多相关的安全方面的描述,可以参考http://java.sun.com/docs/books/tutorial/jar/ 来全面了解.&lt;/P&gt;
&lt;P class=newtext&gt;这也是为什么应用程序打包成可执行的jar包后,不能引用第三方jar包的原因.&lt;/P&gt;
&lt;P class=newtext&gt;&lt;/P&gt;
&lt;P class=newtext&gt;四、解决方案.&lt;/P&gt;
&lt;P class=newtext&gt;&lt;/P&gt;
&lt;P class=newtext&gt;首先我们简要归纳一下,为了方便理解,简化一下上面描述的架构,&lt;/P&gt;
&lt;P class=newtext&gt;Java定义了三种级别的class,分别为BootStrap class,Extend Class,User class.&lt;/P&gt;
&lt;P class=newtext&gt;其中User class限制规则最复杂.在User class中可执行的jar包,更包含独立安全规则.所以解决方案基于Java三种不同级别的class扩展机制,有三种不同的方案.&lt;/P&gt;
&lt;P class=newtext&gt;&lt;/P&gt;
&lt;P class=newtext&gt;4.1 BootStrap class扩展方案&lt;/P&gt;
&lt;P class=newtext&gt;Java 命令行提供了如何扩展bootStrap 级别class的简单方法.&lt;/P&gt;
&lt;P class=newtext&gt;-Xbootclasspath:基本核心的Java class 搜索路径.不常用,否则要重新写所有Java 核心class&lt;/P&gt;
&lt;P class=newtext&gt;-Xbootclasspath/a: 后缀在核心class搜索路径后面.常用.&lt;/P&gt;
&lt;P class=newtext&gt;-Xbootclasspath/p:前缀在核心class搜索路径前面.不常用,避免引起不必要的冲突.&lt;/P&gt;
&lt;P class=newtext&gt;&lt;/P&gt;
&lt;P class=newtext&gt;语法如下:&lt;/P&gt;
&lt;P class=newtext&gt;java &amp;#8211;Xbootclasspath/a:/path/myclass/account.jar: -jar yourself.jar(Unix用:号隔开)&lt;/P&gt;
&lt;P class=newtext&gt;java &amp;#8211;Xbootclasspath:/d:/myclass/account.jar; -jar yourself.jar(Window用;号隔开)&lt;/P&gt;
&lt;P class=newtext&gt;&lt;/P&gt;
&lt;P class=newtext&gt;4.2 extend class 扩展方案&lt;/P&gt;
&lt;P class=newtext&gt;Java exten class 存放在{Java_home}\jre\lib\ext 目录下.当调用Java时,对扩展class路径的搜索是自动的.总会搜索的.这样,解决的方案就很简单了,将所有要使用的第三方的jar包都复制到ext 目录下.&lt;/P&gt;
&lt;P class=newtext&gt;&lt;/P&gt;
&lt;P class=newtext&gt;4.3 User class扩展方案&lt;/P&gt;
&lt;P class=newtext&gt;当使用-jar执行可执行Jar包时,JVM将Jar包所在目录设置为codebase目录,所有的class搜索都在这个目录下开始.所以如果使用了其他第三方的jar包,一个比较可以接受的可配置方案,就是利用jar包的Manifest扩展机制.步骤如下&lt;/P&gt;
&lt;P class=newtext&gt;1.将需要的第三方的jar包,复制在同可执行jar所在的目录或某个子目录下.&lt;/P&gt;
&lt;P class=newtext&gt;比如:jar 包在 d:\crm\luncher.jar 那么你可以把所有jar包复制到d:\crm目录下或d:\crm\lib 子目录下.&lt;/P&gt;
&lt;P class=newtext&gt;2.修改Manifest 文件&lt;/P&gt;
&lt;P class=newtext&gt;在Manifest.mf文件里加入如下行&lt;/P&gt;
&lt;P class=newtext&gt;Class-Path:classes12.jar lib/class12.jar&lt;/P&gt;
&lt;P class=newtext&gt;Class-Path 是可执行jar包运行依赖的关键词.详细内容可以参考http://java.sun.com/docs/books/tutorial/ext/index.html&lt;/P&gt;
&lt;P class=newtext&gt;&lt;/P&gt;
&lt;P class=newtext&gt;另外编写自己的ClassLoader,来动态载入class,是更加复杂和高级技术.限于篇幅,不赘述.有兴趣了解可以去google一下custom classloader&lt;/P&gt;
&lt;P class=newtext&gt;&lt;/P&gt;
&lt;P class=newtext&gt;4.4 推荐方案 4.1，扩展性非常好．&lt;/P&gt;
&lt;P class=newtext&gt;&lt;/P&gt;
&lt;P class=newtext&gt;五、总结&lt;/P&gt;
&lt;P class=newtext&gt;Java的安全机制随不同的JDK版本有不同的变化,会影响很多核心CLASS,比如Thread,所以很多大型商业软件,要求JDK的版本很严格.部分原因也在此.这也要求在发布自己编写的应用时候,不管大小,都要说明开发和测试的JDK版本.&lt;/P&gt;
&lt;P class=newtext&gt;本文所测试基于jdk 1.4.1_03 for windows 。&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/P&gt;&lt;img src ="http://www.mscenter.edu.cn/blog/wangpeng/aggbug/2739.html" width = "1" height = "1" /&gt;</description></item><item><dc:creator>angel</dc:creator><title>servlet 在请求报头中添加属性时，是区分大小写的</title><link>http://www.mscenter.edu.cn/blog/wangpeng/archive/2005/05/15/2566.html</link><pubDate>Sun, 15 May 2005 06:55:00 GMT</pubDate><guid>http://www.mscenter.edu.cn/blog/wangpeng/archive/2005/05/15/2566.html</guid><wfw:comment>http://www.mscenter.edu.cn/blog/wangpeng/comments/2566.html</wfw:comment><comments>http://www.mscenter.edu.cn/blog/wangpeng/archive/2005/05/15/2566.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.mscenter.edu.cn/blog/wangpeng/comments/commentRss/2566.html</wfw:commentRss><trackback:ping>http://www.mscenter.edu.cn/blog/wangpeng/services/trackbacks/2566.html</trackback:ping><description>servlet 在请求报头中添加属性时，是区分大小写的&lt;img src ="http://www.mscenter.edu.cn/blog/wangpeng/aggbug/2566.html" width = "1" height = "1" /&gt;</description></item><item><dc:creator>angel</dc:creator><title>jbuilder 的servlet编程 当前路径</title><link>http://www.mscenter.edu.cn/blog/wangpeng/archive/2005/05/11/2398.html</link><pubDate>Wed, 11 May 2005 01:44:00 GMT</pubDate><guid>http://www.mscenter.edu.cn/blog/wangpeng/archive/2005/05/11/2398.html</guid><wfw:comment>http://www.mscenter.edu.cn/blog/wangpeng/comments/2398.html</wfw:comment><comments>http://www.mscenter.edu.cn/blog/wangpeng/archive/2005/05/11/2398.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.mscenter.edu.cn/blog/wangpeng/comments/commentRss/2398.html</wfw:commentRss><trackback:ping>http://www.mscenter.edu.cn/blog/wangpeng/services/trackbacks/2398.html</trackback:ping><description>在使用jbuilder开发servlet时，在servlet中引用的当前路径是以tomcat文件夹为根目录的，这与其他的application编程不同（是以jbuilder的根目录为当前路径），编程时应注意这一点。&lt;img src ="http://www.mscenter.edu.cn/blog/wangpeng/aggbug/2398.html" width = "1" height = "1" /&gt;</description></item><item><dc:creator>angel</dc:creator><title>servlet 相关的Listener应用</title><link>http://www.mscenter.edu.cn/blog/wangpeng/archive/2005/05/07/2268.html</link><pubDate>Sat, 07 May 2005 14:30:00 GMT</pubDate><guid>http://www.mscenter.edu.cn/blog/wangpeng/archive/2005/05/07/2268.html</guid><wfw:comment>http://www.mscenter.edu.cn/blog/wangpeng/comments/2268.html</wfw:comment><comments>http://www.mscenter.edu.cn/blog/wangpeng/archive/2005/05/07/2268.html#Feedback</comments><slash:comments>1040</slash:comments><wfw:commentRss>http://www.mscenter.edu.cn/blog/wangpeng/comments/commentRss/2268.html</wfw:commentRss><trackback:ping>http://www.mscenter.edu.cn/blog/wangpeng/services/trackbacks/2268.html</trackback:ping><description>&lt;H1&gt;&lt;A class=title title=回到首页 href="http://www.zhanglihai.com/"&gt;ZhangLiHai.Com Blog&lt;/A&gt;&lt;/H1&gt;
&lt;TABLE cellSpacing=1 cellPadding=1 width=750 align=center border=0&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD width=750&gt;
&lt;TABLE cellSpacing=1 cellPadding=1 width="98%" border=0&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD&gt;
&lt;H3&gt;servlet 相关的Listener应用&lt;/H3&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD height=5&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;&lt;SPAN class=date&gt;张利海 于 2004年11月22日 23:27 发表&lt;/SPAN&gt; &lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;关键词 : servlet listener timer 定时器&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;
&lt;P&gt;从作用域范围来说,Servlet的作用域有ServletContext,HttpSession,ServletRequest.&lt;BR&gt;&lt;BR&gt;Context范围:&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;BR&gt;ServletContextListener:&lt;BR&gt;对一个应用进行全局监听.随应用启动而启动,随应用消失而消失主要有两个方法:&lt;BR&gt;contextDestroyed(ServletContextEvent&amp;nbsp;event)&amp;nbsp;&lt;BR&gt;&amp;nbsp;在应用关闭的时候调用&lt;BR&gt;contextInitialized(ServletContextEvent&amp;nbsp;event)&amp;nbsp;&lt;BR&gt;在应用启动的时候调用&lt;BR&gt;&lt;BR&gt;这个监听器主要用于一些随着应用启动而要完成的工作,也就是很多人说的我想在容器&lt;BR&gt;启动的时候干..........&lt;BR&gt;一般来说对"全局变量"初始化,如&lt;BR&gt;public&amp;nbsp;void&amp;nbsp;contextInitialized(ServletContextEvent&amp;nbsp;event){&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ServletContex&amp;nbsp;sc&amp;nbsp;=&amp;nbsp;event.getServletContext();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sc.setAttribute(name,value);&lt;BR&gt;}&lt;BR&gt;以后你就可以在任何servlet中getServletContext().getAttribute(name);&lt;BR&gt;我最喜欢用它来做守护性工作,就是在contextInitialized(ServletContextEvent&amp;nbsp;event)&amp;nbsp;&lt;BR&gt;方法中实现一个Timer,然后就让应用在每次启动的时候让这个Timer工作:&lt;BR&gt;public&amp;nbsp;void&amp;nbsp;contextInitialized(ServletContextEvent&amp;nbsp;event){&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;timer&amp;nbsp;=&amp;nbsp;new&amp;nbsp;Timer();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;timer.schedule(new&amp;nbsp;TimerTask(){&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;void&amp;nbsp;run(){&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//do&amp;nbsp;any&amp;nbsp;things&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;},0,时间间隔);&lt;BR&gt;}&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;有人说Timer只能规定从现在开始的多长时间后,每隔多久做一次事或在什么时间做&lt;BR&gt;一次事,那我想在每月1号或每天12点做一项工作如何做呢?&lt;BR&gt;你只要设一个间隔,然后每次判断一下当时是不是那个时间段就行了啊,比如每月一号做,那你&lt;BR&gt;时间间隔设为天,即24小时一个循环,然后在run方法中判断当时日期new&amp;nbsp;Date().getDate()==1&lt;BR&gt;就行了啊.如果是每天的12点,那你时间间隔设为小时,然后在run中判断new&amp;nbsp;Date().getHour()&lt;BR&gt;==12,再做某事就行了.&lt;BR&gt;&lt;BR&gt;ServletContextAttributeListener:&lt;BR&gt;&lt;BR&gt;这个监听器主要监听ServletContex对象在setAttribute()和removeAttribute()的事件,注意&lt;BR&gt;也就是一个"全局变量"在被Add(第一次set),replace(对已有的变量重新赋值)和remove的时候.&lt;BR&gt;分别调用下面三个方法:&lt;BR&gt;public&amp;nbsp;void&amp;nbsp;attributeAdded(ServletContextAttributeEvent&amp;nbsp;scab)这个方法不仅可以知道&lt;BR&gt;哪些全局变量被加进来,而且可获取容器在启动时自动设置了哪些context变量:&lt;BR&gt;&lt;BR&gt;public&amp;nbsp;void&amp;nbsp;attributeAdded(ServletContextAttributeEvent&amp;nbsp;scab){&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(scab.getName());&lt;BR&gt;}&lt;BR&gt;&amp;nbsp;&amp;nbsp;public&amp;nbsp;void&amp;nbsp;attributeRemoved(ServletContextAttributeEvent&amp;nbsp;scab)&amp;nbsp;&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;public&amp;nbsp;void&amp;nbsp;attributeReplaced(ServletContextAttributeEvent&amp;nbsp;scab)&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&lt;BR&gt;&lt;BR&gt;&lt;BR&gt;&lt;BR&gt;&lt;BR&gt;&lt;BR&gt;&lt;BR&gt;&lt;BR&gt;&lt;BR&gt;Session范围:&lt;BR&gt;HttpSessionListener:&lt;BR&gt;这个监听器主要监听一个Session对象被生成和销毁时发生的事件.对应有两个方法:&lt;BR&gt;&amp;nbsp;&amp;nbsp;public&amp;nbsp;void&amp;nbsp;sessionCreated(HttpSessionEvent&amp;nbsp;se)&amp;nbsp;&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;public&amp;nbsp;void&amp;nbsp;sessionDestroyed(HttpSessionEvent&amp;nbsp;se)&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;一般来说,一个session对象被create时,可以说明有一个新客端进入.可以用来粗略统计在线人&lt;BR&gt;数,注意这不是精确的,因为这个客户端可能立即就关闭了,但sessionDestroyed方法却会按一定&lt;BR&gt;的策略很久以后才会发生.&lt;BR&gt;&lt;BR&gt;HttpSessionAttributeListener:&lt;BR&gt;和ServletContextAttributeListener一样,它监听一个session对象的Attribut被Add(一个特定&lt;BR&gt;名称的Attribute每一次被设置),replace(已有名称的Attribute的值被重设)和remove时的事件.&lt;BR&gt;对就的有三个方法.&lt;BR&gt;&amp;nbsp;&amp;nbsp;public&amp;nbsp;void&amp;nbsp;attributeAdded(HttpSessionBindingEvent&amp;nbsp;se)&amp;nbsp;&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;public&amp;nbsp;void&amp;nbsp;attributeRemoved(HttpSessionBindingEvent&amp;nbsp;se)&amp;nbsp;&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;public&amp;nbsp;void&amp;nbsp;attributeReplaced(HttpSessionBindingEvent&amp;nbsp;se)&amp;nbsp;&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;上面的几个监听器的方法,都是在监听应用逻辑中servlet逻辑中发生了什么事,一般的来说.&lt;BR&gt;我们只要完成逻辑功能,比如session.setAttribute("aaa","111");我只要把一个名为aaa的变量&lt;BR&gt;放在session中以便以后我能获取它,我并不关心当session.setAttribute("aaa","111");发生时&lt;BR&gt;我还要干什么.(当然有些时候要利用的),但对于下面这个监听器,你应该好好发解一下:&lt;BR&gt;&lt;BR&gt;HttpSessionBindingListener:&lt;BR&gt;上面的监听器都是作为一个独立的Listener在容器中控制事件的.而HttpSessionBindingListener&lt;BR&gt;对在一对象中监听该对象的状态,实现了该接口的对象如果被作为value被add到一个session中或从&lt;BR&gt;session中remove,它就会知道自己已经作为一个session对象或已经从session删除,这对于一些非&lt;BR&gt;纯JAVA对象,生命周期长于session的对象,以及其它需要释放资源或改变状态的对象非常重要.&lt;BR&gt;比如:&lt;BR&gt;session.setAttribute("abcd","1111");&lt;BR&gt;以后session.removeAttribute("abcd");因为abcd是一个字符中,你从session中remove后,它就会&lt;BR&gt;自动被垃圾回收器回收,而如果是一个connection:(只是举例,你千万不要加connection往session&lt;BR&gt;中加入)&lt;BR&gt;session.setAttribute("abcd",conn);&lt;BR&gt;以后session.removeAttribute("abcd");这时这个conn被从session中remove了,你已经无法获取它&lt;BR&gt;的句柄,所以你根本没法关闭它.而在没有remove之前你根本不知道什么时候要被remove,你又无法&lt;BR&gt;close(),那么这个connection对象就死了.另外还有一些对象可以在被加入一个session时要锁定&lt;BR&gt;还要被remove时要解锁,应因你在程序中无法判断什么时候被remove(),add还好操作,我可以先加锁&lt;BR&gt;再add,但remove就后你就找不到它的句柄了,根本没法解锁,所以这些操作只能在对象自身中实现.&lt;BR&gt;也就是在对象被add时或remove时通知对象自己回调相应的方法:&lt;BR&gt;&lt;BR&gt;MyConn&amp;nbsp;extends&amp;nbsp;Connection&amp;nbsp;implements&amp;nbsp;HttpSessionBindingListener{&lt;BR&gt;&amp;nbsp;&amp;nbsp;public&amp;nbsp;void&amp;nbsp;valueBound(HttpSessionBindingEvent&amp;nbsp;se){&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.initXXX();&lt;BR&gt;&amp;nbsp;&amp;nbsp;}&lt;BR&gt;&amp;nbsp;&amp;nbsp;public&amp;nbsp;void&amp;nbsp;valueUnbound(HttpSessionBindingEvent&amp;nbsp;se){&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.close();&lt;BR&gt;&amp;nbsp;&amp;nbsp;}&lt;BR&gt;}&lt;BR&gt;&lt;BR&gt;session.setAttribute("aaa",new&amp;nbsp;MyConn());&lt;BR&gt;这时如果调用session.removeAttribute("aaa"),则触发valueUnbound方法,就会自动关闭自己.&lt;BR&gt;而其它的需要改变状态的对象了是一样.&lt;BR&gt;&lt;BR&gt;另外还有一个HttpSessionActivationListener监听器是实现分布式应用中session同步的.不作&lt;BR&gt;多介绍,如果有要实现该功能的朋友可以和我联系.&lt;BR&gt;&lt;BR&gt;&lt;BR&gt;&lt;BR&gt;&lt;BR&gt;在servlet2.4中,对于request范围已经实现对应的监听器:&lt;BR&gt;ServletRequestListener，ServletRequestAttributeListener&lt;BR&gt;但没有找到好的容器的支持所以没有做过多的测试.虽然从API可以掌握99%,但没有经过真正的&lt;BR&gt;测试我是不会仅把API抄出来的.以后我会补齐这方面的内容 &lt;BR&gt;&lt;BR&gt;原作者:Axman&lt;BR&gt;&lt;BR&gt;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;
&lt;SCRIPT language=JavaScript&gt;
	var url = location.href;
	document.write("原文出处:"+url);
&lt;/SCRIPT&gt;
&lt;BR&gt;
&lt;SCRIPT type=text/javascript&gt;&lt;!--
google_ad_client = "pub-9146239964040731";
google_ad_width = 728;
google_ad_height = 90;
google_ad_format = "728x90_as";
google_ad_channel ="";
google_ad_type = "text";
google_color_border = "000000";
google_color_bg = "F0F0F0";
google_color_link = "0000FF";
google_color_url = "008000";
google_color_text = "000000";
//--&gt;&lt;/SCRIPT&gt;

&lt;SCRIPT src="servlet 相关的Listener应用__ZhangLiHai_Com_技术文章.files/show_ads.js" type=text/javascript&gt;
&lt;/SCRIPT&gt;
&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;img src ="http://www.mscenter.edu.cn/blog/wangpeng/aggbug/2268.html" width = "1" height = "1" /&gt;</description></item><item><dc:creator>angel</dc:creator><title>castor 中文问题</title><link>http://www.mscenter.edu.cn/blog/wangpeng/archive/2005/05/05/2246.html</link><pubDate>Thu, 05 May 2005 08:20:00 GMT</pubDate><guid>http://www.mscenter.edu.cn/blog/wangpeng/archive/2005/05/05/2246.html</guid><wfw:comment>http://www.mscenter.edu.cn/blog/wangpeng/comments/2246.html</wfw:comment><comments>http://www.mscenter.edu.cn/blog/wangpeng/archive/2005/05/05/2246.html#Feedback</comments><slash:comments>289</slash:comments><wfw:commentRss>http://www.mscenter.edu.cn/blog/wangpeng/comments/commentRss/2246.html</wfw:commentRss><trackback:ping>http://www.mscenter.edu.cn/blog/wangpeng/services/trackbacks/2246.html</trackback:ping><description>&lt;P&gt;castor 已经提供了很好的中文支持，如果在解析过程中出现乱码，很有可能是输入源出现错误，对于包含中文的输入源，建议使用流。&lt;BR&gt;package castertest;&lt;BR&gt;import java.io.*;&lt;BR&gt;import org.exolab.castor.mapping.*;&lt;BR&gt;import org.exolab.castor.xml.*;&lt;BR&gt;import java.util.List;&lt;BR&gt;import java.util.Iterator;&lt;BR&gt;import org.xml.sax.InputSource;&lt;/P&gt;
&lt;P&gt;&lt;BR&gt;public class testResponseProgram {&lt;BR&gt;&amp;nbsp; public static void main(String args[]) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; try {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // -- Load a mapping file&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Mapping mapping = new Mapping();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mapping.loadMapping("src/mapresponse.xml");&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Unmarshaller un = new Unmarshaller(Streambus.class); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; un.setMapping(mapping);&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // -- Read in the Addressbook using the mapping&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; FileInputStream input=new FileInputStream("src/response.xml");&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; InputSource in=new InputSource(input);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;//&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; FileReader in = new FileReader("src/response.xml");&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Streambus book = (Streambus) un.unmarshal(in);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; input.close();&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // -- Display the addressbook&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; System.out.println(book.getVersion());&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Response persons = book.getResponse();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; System.out.println(persons.getType());&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Iterator list=persons.getPrograms().iterator();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; while(list.hasNext()){&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Program program=(Program)list.next();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; System.out.println(program.getId());&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; System.out.println(program.getTitle());&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; System.out.println(program.getUrl());&lt;BR&gt;//&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; String gb=new String(program.getDescription(),"GB2312");&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; System.out.println(program.getDescription());&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; System.out.println(program.getPrice());&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; System.out.println(program.getPromptionURL());&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; System.out.println(program.getDuration());&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; catch (Exception e) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; System.out.println(e);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp; }&lt;BR&gt;}&lt;BR&gt;&lt;/P&gt;&lt;img src ="http://www.mscenter.edu.cn/blog/wangpeng/aggbug/2246.html" width = "1" height = "1" /&gt;</description></item><item><dc:creator>angel</dc:creator><title>品味Java子类型多态的魅力     选择自 chensheng913 的 Blog </title><link>http://www.mscenter.edu.cn/blog/wangpeng/archive/2005/04/30/2159.html</link><pubDate>Sat, 30 Apr 2005 06:00:00 GMT</pubDate><guid>http://www.mscenter.edu.cn/blog/wangpeng/archive/2005/04/30/2159.html</guid><wfw:comment>http://www.mscenter.edu.cn/blog/wangpeng/comments/2159.html</wfw:comment><comments>http://www.mscenter.edu.cn/blog/wangpeng/archive/2005/04/30/2159.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.mscenter.edu.cn/blog/wangpeng/comments/commentRss/2159.html</wfw:commentRss><trackback:ping>http://www.mscenter.edu.cn/blog/wangpeng/services/trackbacks/2159.html</trackback:ping><description>&lt;P&gt;&lt;FONT color=#a52a2a&gt;&amp;#8220;polymorphism(多态）&amp;#8221;一词来自希腊语，意为&amp;#8220;多种形式&amp;#8221;。多数Java程序员把多态看作对象的一种能力，使其能调用正确的方法版本。尽管如此，这种面向实现的观点导致了多态的神奇功能，胜于仅仅把多态看成纯粹的概念。&lt;BR&gt;&lt;BR&gt;　　Java中的多态总是子类型的多态。几乎是机械式产生了一些多态的行为，使我们不去考虑其中涉及的类型问题。本文研究了一种面向类型的对象观点，分析了如何将对象能够表现的行为和对象即将表现的行为分离开来。抛开Java中的多态都是来自继承的概念，我们仍然可以感到，Java中的接口是一组没有公共代码的对象共享实现。&lt;BR&gt;&lt;BR&gt;　　&lt;B&gt;多态的分类&lt;/B&gt; &lt;BR&gt;&lt;BR&gt;　　多态在面向对象语言中是个很普遍的概念.虽然我们经常把多态混为一谈，但实际上有四种不同类型的多态。在开始正式的子类型多态的细节讨论前，然我们先来看看普通面向对象中的多态。&lt;BR&gt;&lt;BR&gt;　　Luca Cardelli和Peter Wegner（"On Understanding Types, Data Abstraction, and Polymorphism"一文的作者， 文章参考资源链接）把多态分为两大类----特定的和通用的----四小类：强制的，重载的，参数的和包含的。他们的结构如下：&lt;BR&gt;&lt;BR&gt;&lt;IMG onerror="this.src='http://www.yesky.com/image20010518/103059.gif';" hspace=3 src="http://www.yesky.com/image20010518/103059.gif" align=center vspace=1 border=1&gt;&lt;BR&gt;&lt;BR&gt;　　在这样一个体系中，多态表现出多种形式的能力。通用多态引用有相同结构类型的大量对象，他们有着共同的特征。特定的多态涉及的是小部分没有相同特征的对象。四种多态可做以下描述：&lt;BR&gt;&lt;BR&gt;　　强制的：一种隐式做类型转换的方法。&lt;BR&gt;&lt;BR&gt;　　重载的：将一个标志符用作多个意义。&lt;BR&gt;&lt;BR&gt;　　参数的：为不同类型的参数提供相同的操作。&lt;BR&gt;&lt;BR&gt;　　包含的：类包含关系的抽象操作。&lt;BR&gt;&lt;BR&gt;　　我将在讲述子类型多态前简单介绍一下这几种多态。&lt;BR&gt;&lt;BR&gt;　　&lt;B&gt;强制的多态&lt;/B&gt;&lt;BR&gt;&lt;BR&gt;　　强制多态隐式的将参数按某种方法，转换成编译器认为正确的类型以避免错误。在以下的表达式中，编译器必须决定二元运算符&amp;#8216;+&amp;#8217;所应做的工作：&lt;BR&gt;&lt;BR&gt;　　2.0 + 2.0&lt;BR&gt;&lt;BR&gt;　　2.0 + 2&lt;BR&gt;&lt;BR&gt;　　2.0 + "2"&lt;BR&gt;&lt;BR&gt;　　第一个表达式将两个double的操作数相加；Java中特别声明了这种用法。&lt;BR&gt;&lt;BR&gt;　　第二个表达式将double型和int相加。Java中没有明确定义这种运算。不过，编译器隐式的将第二个操作数转换为double型，并作double型的加法。做对程序员来说十分方便，否则将会抛出一个编译错误，或者强制程序员显式的将int转换为double。&lt;BR&gt;&lt;BR&gt;　　第三个表达式将double与一个String相加。Java中同样没有定义这样的操作。所以，编译器将double转换成String类型，并将他们做串联。&lt;BR&gt;&lt;BR&gt;　　强制多态也会发生在方法调用中。假设类Derived继承了类Base，类C有一个方法，原型为m(Base)，在下面的代码中，编译器隐式的将Derived类的对象derived转化为Base类的对象。这种隐式的转换使m(Base)方法使用所有能转换成Base类的所有参数。&lt;BR&gt;&lt;BR&gt;C c = new C();&lt;BR&gt;&lt;BR&gt;Derived derived = new Derived();&lt;BR&gt;&lt;BR&gt;c.m( derived );&lt;BR&gt;&lt;BR&gt;　　并且，隐式的强制转换，可以避免类型转换的麻烦，减少编译错误。当然，编译器仍然会优先验证符合定义的对象类型。&lt;BR&gt;&lt;BR&gt;　　&lt;B&gt;重载的多态&lt;/B&gt;&lt;BR&gt;&lt;BR&gt;　　重载允许用相同的运算符或方法，去表示截然不同的意义。&amp;#8216;+&amp;#8217;在上面的程序中有两个意思：两个double型的数相加；两个串相连。另外还有整型相加，长整型，等等。这些运算符的重载，依赖于编译器根据上下文做出的选择。以往的编译器会把操作数隐式转换为完全符合操作符的类型。虽然Java明确支持重载，但不支持用户定义的操作符重载。&lt;BR&gt;&lt;BR&gt;　　Java支持用户定义的函数重载。一个类中可以有相同名字的方法，这些方法可以有不同的意义。这些重载的方法中，必须满足参数数目不同，相同位置上的参数类型不同。这些不同可以帮助编译器区分不同版本的方法。&lt;BR&gt;&lt;BR&gt;　　编译器以这种唯一表示的特征来表示不同的方法，比用名字表示更为有效。据此，所有的多态行为都能编译通过。&lt;BR&gt;&lt;BR&gt;　　强制和重载的多态都被分类为特定的多态，因为这些多态都是在特定的意义上的。这些被划入多态的特性给程序员带来了很大的方便。强制多态排除了麻烦的类型和编译错误。重载多态像一块糖，允许程序员用相同的名字表示不同的方法，很方便。&lt;BR&gt;&lt;BR&gt;　　&lt;B&gt;参数的多态&lt;/B&gt;&lt;BR&gt;&lt;BR&gt;　　参数多态允许把许多类型抽象成单一的表示。例如，List抽象类中，描述了一组具有同样特征的对象，提供了一个通用的模板。你可以通过指定一种类型以重用这个抽象类。这些参数可以是任何用户定义的类型，大量的用户可以使用这个抽象类，因此参数多态毫无疑问的成为最强大的多态。&lt;BR&gt;&lt;BR&gt;　　乍一看，上面抽象类好像是java.util.List的功能。然而，Java实际上并不支持真正的安全类型风格的参数多态，这也是java.util.List和java.util的其他集合类是用原始的java.lang.Object写的原因（参考我的文章"A Primordial Interface?" 以获得更多细节）。Java的单根继承方式解决了部分问题，但没有发挥出参数多态的全部功能。Eric Allen有一篇精彩的文章&amp;#8220;Behold the Power of Parametric Polymorphism&amp;#8221;，描述了Java通用类型的需求，并建议给Sun的Java规格需求#000014号文档"Add Generic Types to the Java Programming Language."（参考资源链接）&lt;BR&gt;&lt;BR&gt;　　&lt;B&gt;包含的多态&lt;/B&gt;&lt;BR&gt;&lt;BR&gt;　　包含多态通过值的类型和集合的包含关系实现了多态的行为.在包括Java在内的众多面向对象语言中，包含关系是子类型的。所以，Java的包含多态是子类型的多态。&lt;BR&gt;&lt;BR&gt;　　在早期，Java开发者们所提及的多态就特指子类型的多态。通过一种面向类型的观点，我们可以看到子类型多态的强大功能。以下的文章中我们将仔细探讨这个问题。为简明起见，下文中的多态均指包含多态。&lt;BR&gt;&lt;BR&gt;&lt;/FONT&gt;&lt;SPAN class=f14&gt;&lt;FONT color=#a52a2a&gt;　　&lt;B&gt;面向类型观点&lt;/B&gt; &lt;BR&gt;&lt;BR&gt;　　图1的UML类图给出了类和类型的简单继承关系，以便于解释多态机制。模型中包含5种类型，4个类和一个接口。虽然UML中称为类图，我把它看成类型图。如"Thanks Type and Gentle Class," 一文中所述，每个类和接口都是一种用户定义的类型。按独立实现的观点（如面向类型的观点），下图中的每个矩形代表一种类型。从实现方法看，四种类型运用了类的结构，一种运用了接口的结构。&lt;BR&gt;&lt;BR&gt;&lt;IMG onerror="this.src='http://www.yesky.com/image20010518/103060.gif';" hspace=3 src="http://www.yesky.com/image20010518/103060.gif" align=center vspace=1 border=1&gt;&lt;BR&gt;图1：示范代码的UML类图&lt;BR&gt;&lt;BR&gt;　　以下的代码实现了每个用户定义的数据类型，我把实现写得很简单。&lt;BR&gt;&lt;BR&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;
&lt;TABLE width="100%" bgColor=#ffffff&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD&gt;&lt;FONT color=#a52a2a&gt;/* Base.java */&lt;BR&gt;&lt;BR&gt;public class Base&lt;BR&gt;{&lt;BR&gt;　public String m1()&lt;BR&gt;　{&lt;BR&gt;　　return "Base.m1()";&lt;BR&gt;　}&lt;BR&gt;&lt;BR&gt;　public String m2( String s )&lt;BR&gt;　{&lt;BR&gt;　　return "Base.m2( " + s + " )";&lt;BR&gt;　}&lt;BR&gt;}&lt;BR&gt;&lt;BR&gt;/* IType.java */&lt;BR&gt;&lt;BR&gt;interface IType&lt;BR&gt;{&lt;BR&gt;　String m2( String s );&lt;BR&gt;　String m3();&lt;BR&gt;}&lt;BR&gt;&lt;BR&gt;/* Derived.java */&lt;BR&gt;&lt;BR&gt;public class Derived&lt;BR&gt;extends Base&lt;BR&gt;implements IType&lt;BR&gt;{&lt;BR&gt;　public String m1()&lt;BR&gt;　{&lt;BR&gt;　　return "Derived.m1()";&lt;BR&gt;　}&lt;BR&gt;&lt;BR&gt;　public String m3()&lt;BR&gt;　{&lt;BR&gt;　　return "Derived.m3()";&lt;BR&gt;　}&lt;BR&gt;}&lt;BR&gt;&lt;BR&gt;/* Derived2.java */&lt;BR&gt;&lt;BR&gt;public class Derived2&lt;BR&gt;extends Derived&lt;BR&gt;{&lt;BR&gt;　public String m2( String s )&lt;BR&gt;　{&lt;BR&gt;　　return "Derived2.m2( " + s + " )";&lt;BR&gt;　}&lt;BR&gt;　public String m4()&lt;BR&gt;　{&lt;BR&gt;　　return "Derived2.m4()";&lt;BR&gt;　}&lt;BR&gt;}&lt;BR&gt;&lt;BR&gt;/* Separate.java */&lt;BR&gt;&lt;BR&gt;public class Separate&lt;BR&gt;implements IType&lt;BR&gt;{&lt;BR&gt;　public String m1()&lt;BR&gt;　{&lt;BR&gt;　　return "Separate.m1()";&lt;BR&gt;　}&lt;BR&gt;　public String m2( String s )&lt;BR&gt;　{&lt;BR&gt;　　return "Separate.m2( " + s + " )";&lt;BR&gt;　}&lt;BR&gt;&lt;BR&gt;　public String m3()&lt;BR&gt;　{&lt;BR&gt;　　return "Separate.m3()";&lt;BR&gt;　}&lt;BR&gt;}&lt;BR&gt;&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/P&gt;
&lt;P&gt;&lt;BR&gt;&lt;FONT color=#a52a2a&gt;　　用这样的类型声明和类的定义，图2从概念的观点描述了Java指令。&lt;BR&gt;&lt;BR&gt;Derived2 derived2 = new Derived2();&lt;BR&gt;&lt;BR&gt;&lt;IMG onerror="this.src='http://www.yesky.com/image20010518/103061.gif';" hspace=3 src="http://www.yesky.com/image20010518/103061.gif" align=center vspace=1 border=1&gt;&lt;BR&gt;图2 ：Derived2 对象上的引用&lt;BR&gt;&lt;BR&gt;　　上文中声明了derived2这个对象，它是Derived2类的。图2种的最顶层把Derived2引用描述成一个集合的窗口，虽然其下的Derived2对象是可见的。这里为每个Derived2类型的操作留了一个孔。Derived2对象的每个操作都去映射适当的代码，按照上面的代码所描述的那样。例如，Derived2对象映射了在Derived中定义的m1()方法。而且还重载了Base类的m1()方法。一个Derived2的引用变量无权访问Base类中被重载的m1()方法。但这并不意味着不可以用super.m1()的方法调用去使用这个方法。关系到derived2这个引用的变量，这个代码是不合适的。Derived2的其他的操作映射同样表明了每种类型操作的代码执行。&lt;BR&gt;&lt;BR&gt;　　既然你有一个Derived2对象，可以用任何一个Derived2类型的变量去引用它。如图1所示，Derived, Base和IType都是Derived2的基类。所以，Base类的引用是很有用的。图3描述了以下语句的概念观点。&lt;BR&gt;&lt;BR&gt;Base base = derived2;&lt;BR&gt;&lt;BR&gt;&lt;IMG onerror="this.src='http://www.yesky.com/image20010518/103063.gif';" hspace=3 src="http://www.yesky.com/image20010518/103063.gif" align=center vspace=1 border=1&gt;&lt;BR&gt;图3：Base类引用附于Derived2对象之上&lt;BR&gt;　 &lt;BR&gt;　　虽然Base类的引用不用再访问m3()和m4()，但是却不会改变它Derived2对象的任何特征及操作映射。无论是变量derived2还是base，其调用m1()或m2(String)所执行的代码都是一样的。&lt;BR&gt;&lt;BR&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;
&lt;TABLE width="100%" bgColor=#ffffff&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD&gt;&lt;FONT color=#a52a2a&gt;String tmp;&lt;BR&gt;// Derived2 reference (Figure 2)&lt;BR&gt;tmp = derived2.m1(); // tmp is "Derived.m1()"&lt;BR&gt;tmp = derived2.m2( "Hello" ); // tmp is "Derived2.m2( Hello )"&lt;BR&gt;&lt;BR&gt;// Base reference (Figure 3)&lt;BR&gt;&lt;BR&gt;tmp = base.m1(); // tmp is "Derived.m1()"&lt;BR&gt;tmp = base.m2( "Hello" ); // tmp is "Derived2.m2( Hello )"&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/P&gt;
&lt;P&gt;&lt;BR&gt;&lt;FONT color=#a52a2a&gt;　　两个引用之所以调用同一个行为，是因为Derived2对象并不知道去调用哪个方法。对象只知道什么时候调用，它随着继承实现的顺序去执行。这样的顺序决定了Derived2对象调用Derived里的m1()方法，并调用Derived2里的m2(String)方法。这种结果取决于对象本身的类型，而不是引用的类型。&lt;BR&gt;&lt;BR&gt;　　尽管如此，但不意味着你用derived2和base引用的效果是完全一样的。如图3所示，Base的引用只能看到Base类型拥有的操作。所以，虽然Derived2有对方法m3()和m4()的映射，但是变量base不能访问这些方法。&lt;BR&gt;&lt;BR&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;
&lt;TABLE width="100%" bgColor=#ffffff&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD&gt;&lt;FONT color=#a52a2a&gt;String tmp;&lt;BR&gt;// Derived2 reference (Figure 2)&lt;BR&gt;tmp = derived2.m3(); // tmp is "Derived.m3()"&lt;BR&gt;tmp = derived2.m4(); // tmp is "Derived2.m4()"&lt;BR&gt;&lt;BR&gt;// Base reference (Figure 3)&lt;BR&gt;&lt;BR&gt;tmp = base.m3(); // Compile-time error&lt;BR&gt;tmp = base.m4(); // Compile-time error&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/P&gt;
&lt;P&gt;&lt;BR&gt;&lt;FONT color=#a52a2a&gt;　　运行期的Derived2对象保持了接受m3()和m4()方法的能力。类型的限制使Base的引用不能在编译期调用这些方法。编译期的类型检查像一套铠甲，保证了运行期对象只能和正确的操作进行相互作用。换句话说，类型定义了对象间相互作用的边界。&lt;BR&gt;&lt;BR&gt;&lt;/FONT&gt;&lt;SPAN class=f14&gt;&lt;FONT color=#a52a2a&gt;　　&lt;B&gt;多态的依附性&lt;/B&gt;&lt;BR&gt;&lt;BR&gt;　　类型的一致性是多态的核心。对象上的每一个引用，静态的类型检查器都要确认这样的依附和其对象的层次是一致的。当一个引用成功的依附于另一个不同的对象时，有趣的多态现象就产生了。（严格的说，对象类型是指类的定义。）你也可以把几个不同的引用依附于同一个对象。在开始更有趣的场景前，我们先来看一下下面的情况为什么不会产生多态。&lt;BR&gt;&lt;BR&gt;　　&lt;B&gt;多个引用依附于一个对象&lt;/B&gt;&lt;BR&gt;&lt;BR&gt;　　图2和图3描述的例子是把两个及两个以上的引用依附于一个对象。虽然Derived2对象在被依附之后仍保持了变量的类型，但是，图3中的Base类型的引用依附之后，其功能减少了。结论很明显：把一个基类的引用依附于派生类的对象之上会减少其能力。&lt;BR&gt;&lt;BR&gt;　　一个开发这怎么会选择减少对象能力的方案呢？这种选择是间接的。假设有一个名为ref的引用依附于一个包含如下方法的类的对象：&lt;BR&gt;&lt;BR&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;
&lt;TABLE width="100%" bgColor=#ffffff&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD&gt;&lt;FONT color=#a52a2a&gt;public String poly1( Base base )&lt;BR&gt;{&lt;BR&gt;　return base.m1();&lt;BR&gt;} &lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/P&gt;
&lt;P&gt;&lt;BR&gt;&lt;FONT color=#a52a2a&gt;　　用一个Derived2的参数调用poly(Base)是符合参数类型检查的：&lt;BR&gt;&lt;BR&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;
&lt;TABLE width="100%" bgColor=#ffffff&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD&gt;&lt;FONT color=#a52a2a&gt;ref.poly1( derived2 );&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/P&gt;
&lt;P&gt;&lt;BR&gt;&lt;FONT color=#a52a2a&gt;　　方法调用把一个本地Base类型的变量依附在一个引入的对象上。所以，虽然这个方法只接受Base类型的参数，但Derived2对象仍是允许的。开发这就不必选择丢失功能的方案。从人眼在通过Derived2对象时所看到的情况，Base类型引用的依附导致了功能的丧失。但从执行的观点看，每一个传入poly1(Base)的参数都认为是Base的对象。执行机并不在乎有多个引用指向同一个对象，它只注重把指向另一个对象的引用传给方法。这些对象的类型不一致并不是主要问题。执行器只关心给运行时的对象找到适当的实现。面向类型的观点展示了多态的巨大能力。&lt;BR&gt;&lt;BR&gt;　　&lt;B&gt;附于多个对象的引用&lt;/B&gt;&lt;BR&gt;&lt;BR&gt;　　让我们来看一下发生在poly1(Base)中的多态行为。下面的代码创建了三个对象，并通过引用传给poly1(Base):&lt;BR&gt;&lt;BR&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;
&lt;TABLE width="100%" bgColor=#ffffff&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD&gt;&lt;FONT color=#a52a2a&gt;Derived2 derived2 = new Derived2();&lt;BR&gt;Derived derived = new Derived();&lt;BR&gt;Base base = new Base();&lt;BR&gt;&lt;BR&gt;String tmp;&lt;BR&gt;&lt;BR&gt;tmp = ref.poly1( derived2 ); // tmp is "Derived.m1()"&lt;BR&gt;tmp = ref.poly1( derived ); // tmp is "Derived.m1()"&lt;BR&gt;tmp = ref.poly1( base ); // tmp is "Base.m1()"&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/P&gt;
&lt;P&gt;&lt;BR&gt;&lt;FONT color=#a52a2a&gt;　　poly1(Base)的实现代码是调用传进来的参数的m1()方法。图3和图4展示了把三个类的对象传给方法时，面向类型的所使用的体系结构。&lt;BR&gt;&lt;BR&gt;&lt;IMG onerror="this.src='http://www.yesky.com/image20010518/103066.gif';" hspace=3 src="http://www.yesky.com/image20010518/103066.gif" align=center vspace=1 border=1&gt;&lt;BR&gt;图4：将Base引用指向Derived类，以及Base对象&lt;BR&gt;&lt;BR&gt;　　请注意每个图中方法m1()的映射。图3中，m1()调用了Derived类的代码；上面代码中的注释标明了ploy1(Base)调用Derived.m1()。图4中Derived对象调用的仍然是Derived类的m1()方法。最后，图4中，Base对象调用的m1()是Base类中定义的代码。&lt;BR&gt;&lt;BR&gt;　　多态的魅力何在？再来看一下poly1(Base)的代码，它可以接受任何属于Base类范畴的参数。然而，当他收到一个Derived2的对象时，它实际上却调用了Derived版本的方法。当你根据Base类派生出其他类时，如Derived，Derived2，poly1(Base)都可以接受这些参数，并作出选择调用合适的方法。多态允许你在完成poly1(Base)后扩展它的用途。&lt;BR&gt;&lt;BR&gt;　　这看起来当然很神奇。基本的理解展示了多态的内部工作原理。在面向类型的观点中，底层的对象所实现的代码是非实质性的。重要的是，类型检查器会在编译期间为每个引用选择合适的代码以实现其方法。多态使开发者运用面向类型的观点，不考虑实现的细节。这样有助于把类型和实现分离（实际用处是把接口和实现分离）。&lt;BR&gt;&lt;BR&gt;&lt;/FONT&gt;&lt;SPAN class=f14&gt;&lt;FONT color=#a52a2a&gt;　　&lt;B&gt;对象接口&lt;/B&gt;&lt;BR&gt;&lt;BR&gt;　　多态依赖于类型和实现的分离，多用来把接口和实现分离。但下面的观点好像把Java的关键字interface搞得很糊涂。&lt;BR&gt;&lt;BR&gt;　　更为重要的使开发者们怎样理解短语&amp;#8220;the interface to an object"，典型地，根据上下文，这个短语的意思是指一切对象类中所定义的方法，至一切对象公开的方法。这种倾向于以实现为中心的观点较之于面向类型的观点来说，使我们更加注重于对象在运行期的能力。图3中，引用面板的对象表面被标志成"Derived2 Object"。这个面板上列出了Derived2对象的所有可用的方法。但是要理解多态，我们必须从实现这一层次上解放出来，并注意面向类型的透视图中被标为"Base Reference"的面板。在这一层意思上，引用变量的类型指明了一个对象的表面。这只是一个表面，不是接口。在类型一致的原则下，我们可以用面向类型的观点，为一个对象依附多个引用。对interface to an object这个短语的理解没有确定的理解。&lt;BR&gt;&lt;BR&gt;　　在类型概念中，the interface to an object refers 引用了面向类型观点的最大可能----如图2的情形。把一个基类的引用指向相同的对象缩小了这样的观点----如图3所示。类型概念能使人获得把对象间的相互作用同实现细节分离的要领。相对于一个对象的接口，面向类型的观点更鼓励人们去使用一个对象的引用。引用类型规定了对象间的相互作用。当你考虑一个对象能做什么的时候，只需搞明白他的类型，而不需要去考虑他的实现细节。&lt;BR&gt;&lt;BR&gt;　　&lt;B&gt;Java接口&lt;/B&gt;&lt;BR&gt;&lt;BR&gt;　　以上所谈到的多态行为用到了类的继承关系所建立起来的子类型关系。Java接口同样支持用户定义的类型，相对地，Java的接口机制启动了建立在类型层次结构上的多态行为。假设一个名为ref的引用变量，并使其指向一个包含一下方法的类对象：&lt;BR&gt;&lt;BR&gt;&lt;/FONT&gt;
&lt;TABLE width="100%" bgColor=#ffffff&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD&gt;&lt;FONT color=#a52a2a&gt;public String poly2( IType iType )&lt;BR&gt;{&lt;BR&gt;　return iType.m3();&lt;BR&gt;}&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;BR&gt;&lt;FONT color=#a52a2a&gt;　　为了弄明白poly2(IType)中的多态，以下的代码从不同的类创建两个对象，并分别把他们传给poly2(IType)：&lt;BR&gt;&lt;BR&gt;&lt;/FONT&gt;
&lt;TABLE width="100%" bgColor=#ffffff&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD&gt;&lt;FONT color=#a52a2a&gt;Derived2 derived2 = new Derived2();&lt;BR&gt;Separate separate = new Separate();&lt;BR&gt;&lt;BR&gt;String tmp;&lt;BR&gt;&lt;BR&gt;tmp = ref.poly2( derived2 ); // tmp is "Derived.m3()"&lt;BR&gt;tmp = ref.poly2( separate ); // tmp is "Separate.m3()"&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;BR&gt;&lt;FONT color=#a52a2a&gt;　　上面的代码类似于关于poly1(Base)中的多态的讨论。poly2(IType)的实现代码是调用每个对象的本地版本的m3()方法。如同以前，代码的注释表明了每次调用所返回的CString类型的结果。图5表明了两次调用poly2(IType)的概念结构：&lt;BR&gt;&lt;BR&gt;&lt;IMG onerror="this.src='http://www.yesky.com/image20010518/103067.gif';" hspace=3 src="http://www.yesky.com/image20010518/103067.gif" align=center vspace=1 border=1&gt;&lt;BR&gt;图5：指向Derived2和Separate对象的IType引用 &lt;BR&gt;&lt;BR&gt;　　方法poly1(Base)和poly2(IType)中所表现的多态行为的相似之处可以从透视图中直接看出来。把我们在实现在一层上的理解再提高一层，就可以看到这两段代码的技巧。基类的引用指向了作为参数传进的类，并且按照类型的限制调用对象的方法。引用既不知道也不关心执行哪一段代码。编译期间的子类型关系检查保证了通过的对象有能力在被调用的时候选择合适的实现代码。&lt;BR&gt;&lt;BR&gt;　　然而，他们在实现层上有一个重要的差别。在poly1(Base)的例子中（图3和图4），Base-Derived-Derived2的类继承结构为子类型关系的建立提供了条件，并决定了方法去调用哪段代码。在poly2(IType)的例子中（如图5），则是完全不同的动态发生的。Derived2和Separate不共享任何实现的层次，但是他们还是通过IType的引用展示了多态的行为。&lt;BR&gt;&lt;BR&gt;　　这样的多态行为使Java的接口的功能的重大意义显得很明显。图1中的UML类图说明了Derived是Base和IType的子类型。通过完全脱离实现细节的类型的定义方法，Java实现了多类型继承，并且不存在Java所禁止的多继承所带来的烦人的问题。完全脱离实现层次的类可以按照Java接口实现分组。在图1中，接口IType和Derived,Separate以及这类型的其他子类型应该划为一组。&lt;BR&gt;&lt;BR&gt;　　按照这种完全不同于实现层次的分类方法，Java的接口机制是多态变得很方便，哪怕不存在任何共享的实现或者复写的方法。如图5所示，一个IType的引用，用多态的方法访问到了Derived2和Separate对象的m3()方法。&lt;BR&gt;&lt;BR&gt;　　&lt;B&gt;再次探讨对象的接口&lt;/B&gt; &lt;BR&gt;&lt;BR&gt;　　注意图5中的Derived2和Separate对象的对m1()的映射方法。如前所述，每一个对象的接口都包含方法m1()。但却没有办法用这两个对象使方法m1()表现出多态的行为。每一个对象占有一个m1()方法是不够的。必须存在一个可以操作m1()方法的类型，通过这个类型可以看到对象。这些对象似乎是共享了m1()方法，但在没有共同基类的条件下，多态是不可能的。通过对象的接口来看多态，会把这个概念搞混。&lt;BR&gt;&lt;BR&gt;　　&lt;B&gt;结论&lt;/B&gt;&lt;BR&gt;&lt;BR&gt;　　从全文所述的面向对象多态所建立起来的子类型多态，你可以清楚地认识到这种面向类型的观点。如果你想理解子类型多态的思想，就应该把注意力从实现的细节转移到类型的上。类型把对象分成组，并且管理着这些对象的接口。类型的继承层次结构决定了实现多态所需的类型关系。&lt;BR&gt;&lt;BR&gt;　　有趣的是，实现的细节并不影响子类型多态的层次结构。类型决定了对象调用什么方法，而实现则决定了对象怎么执行这个方法。也就是说，类型表明了责任，而负责实施的则是具体的实现。将实现和类型分离后，我们好像看到了这两个部分在一起跳舞，类型决定了他的舞伴和舞蹈的名字，而实现则是舞蹈动作的设计师。&lt;BR&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;BR&gt;&lt;/SPAN&gt;&lt;BR&gt;&lt;/SPAN&gt;&lt;BR&gt;&lt;BR&gt;&lt;/P&gt;
&lt;P&gt;&lt;BR&gt;&amp;nbsp;&lt;/P&gt;
&lt;DIV style="FONT-SIZE: 14px; LINE-HEIGHT: 25px"&gt;&lt;STRONG&gt;作者Blog：&lt;/STRONG&gt;&lt;A id=ArticleContent1_ArticleContent1_AuthorBlogLink href="http://blog.csdn.net/chensheng913/" target=_blank&gt;http://blog.csdn.net/chensheng913/&lt;/A&gt;&lt;/DIV&gt;
&lt;DIV style="FONT-SIZE: 14px; COLOR: #900; LINE-HEIGHT: 25px"&gt;&lt;STRONG&gt;相关文章&lt;/STRONG&gt;&lt;/DIV&gt;
&lt;P&gt;
&lt;TABLE id=ArticleContent1_ArticleContent1_RelatedArticles style="BORDER-COLLAPSE: collapse" cellSpacing=0 border=0&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD&gt;&lt;A href="http://dev.csdn.net/article/47/article/69/69490.shtm"&gt;如何连接oracle数据库及故障解决办法 &lt;/A&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;&lt;A href="http://dev.csdn.net/article/47/article/69/69308.shtm"&gt;浅析Java中Data类的应用&lt;/A&gt; &lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;&lt;A href="http://dev.csdn.net/article/47/article/69/69199.shtm"&gt;探讨ORACLE数据库的数据导入方法&lt;/A&gt; &lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;&lt;A href="http://dev.csdn.net/article/47/article/69/69073.shtm"&gt;在Oracle9i中使用多种Block Size&lt;/A&gt; &lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;&lt;A href="http://dev.csdn.net/article/47/article/68/68995.shtm"&gt;JSP技巧：发送动态图像&lt;/A&gt; &lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/P&gt;&lt;img src ="http://www.mscenter.edu.cn/blog/wangpeng/aggbug/2159.html" width = "1" height = "1" /&gt;</description></item><item><dc:creator>angel</dc:creator><title>castor路径用法</title><link>http://www.mscenter.edu.cn/blog/wangpeng/archive/2005/04/29/2131.html</link><pubDate>Fri, 29 Apr 2005 09:47:00 GMT</pubDate><guid>http://www.mscenter.edu.cn/blog/wangpeng/archive/2005/04/29/2131.html</guid><wfw:comment>http://www.mscenter.edu.cn/blog/wangpeng/comments/2131.html</wfw:comment><comments>http://www.mscenter.edu.cn/blog/wangpeng/archive/2005/04/29/2131.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.mscenter.edu.cn/blog/wangpeng/comments/commentRss/2131.html</wfw:commentRss><trackback:ping>http://www.mscenter.edu.cn/blog/wangpeng/services/trackbacks/2131.html</trackback:ping><description>&lt;BR&gt;在java中路径用&amp;#8220;/&amp;#8220;&lt;BR&gt;在mapping配置文件中路径标识用&amp;#8220;.&amp;#8221;&lt;img src ="http://www.mscenter.edu.cn/blog/wangpeng/aggbug/2131.html" width = "1" height = "1" /&gt;</description></item><item><dc:creator>angel</dc:creator><title>jbuilder2005 中的目录结构</title><link>http://www.mscenter.edu.cn/blog/wangpeng/archive/2005/04/29/2129.html</link><pubDate>Fri, 29 Apr 2005 08:59:00 GMT</pubDate><guid>http://www.mscenter.edu.cn/blog/wangpeng/archive/2005/04/29/2129.html</guid><wfw:comment>http://www.mscenter.edu.cn/blog/wangpeng/comments/2129.html</wfw:comment><comments>http://www.mscenter.edu.cn/blog/wangpeng/archive/2005/04/29/2129.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.mscenter.edu.cn/blog/wangpeng/comments/commentRss/2129.html</wfw:commentRss><trackback:ping>http://www.mscenter.edu.cn/blog/wangpeng/services/trackbacks/2129.html</trackback:ping><description>jbuilder2005 是以你建立的工程文件夹，为当前目录，如果你在java文件中要引用一个外部文件，例如读文件情况。这时可以不必引用绝对路径，使用相对路径即可。但要注意&lt;BR&gt;当前路径为你所建立的工程的根目录。&lt;img src ="http://www.mscenter.edu.cn/blog/wangpeng/aggbug/2129.html" width = "1" height = "1" /&gt;</description></item></channel></rss>