<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title></title>
    <description></description>
    <link>http://chen-516888.javaeye.com</link>
    <language>UTF-8</language>
    <copyright>Copyright 2003-2008, JavaEye.com</copyright>
    <docs>http://blogs.law.harvard.edu/tech/rss</docs>
    <generator>JavaEye - 做最棒的软件开发交流社区</generator>
          <item>
        <title>Tips</title>
        <author>chen-516888</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://chen-516888.javaeye.com">chen-516888</a>&nbsp;
                    链接：<a href="http://chen-516888.javaeye.com/blog/249276" style="color:red;">http://chen-516888.javaeye.com/blog/249276</a>&nbsp;
          发表时间: 2008年10月06日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><a href="http://today.java.net/pub/a/today/2007/03/01/building-web-applications-with-maven-2.html">http://today.java.net/pub/a/today/2007/03/01/building-web-applications-with-maven-2.html</a></p>
<p>&nbsp;</p>
<p><a href="http://book.csdn.net/bookfiles/670/index.html">http://book.csdn.net/bookfiles/670/index.html</a></p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://chen-516888.javaeye.com/blog/249276#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">Windows7在微软WinHEC 2008上揭开神秘面纱</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 06 Oct 2008 11:38:19 +0800</pubDate>
        <link>http://chen-516888.javaeye.com/blog/249276</link>
        <guid>http://chen-516888.javaeye.com/blog/249276</guid>
      </item>
          <item>
        <title>Class loader and package mechanism</title>
        <author>chen-516888</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://chen-516888.javaeye.com">chen-516888</a>&nbsp;
                    链接：<a href="http://chen-516888.javaeye.com/blog/249173" style="color:red;">http://chen-516888.javaeye.com/blog/249173</a>&nbsp;
          发表时间: 2008年10月05日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><span class="a14c" id="zoom">&nbsp;
<p style="text-indent: 2em;">&nbsp;</p>
<p><span style="font-size: small; font-family: Times New Roman;">为了深入了解Java的ClassLoader机制，我们先来做以下实验：</span></p>
<p><span style="font-size: small; font-family: Times New Roman;">package java.lang;<br />public class Test {<br />&nbsp;&nbsp;&nbsp; public static void main(String[] args) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char[] c = "1234567890".toCharArray();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String s = new String(0, 10, c);<br />&nbsp;&nbsp;&nbsp; }<br />}</span></p>
<p><span style="font-size: small; font-family: Times New Roman;">String类有一个Package权限的构造函数String(int offset, int length, char[] array)，按照默认的访问权限，由于Test属于java.lang包，因此理论上应该可以访问String的这个构造函数。编译通过！执行时结果如下：</span></p>
<p><span style="font-size: small; font-family: Times New Roman;">Exception in thread "main" java.lang.SecurityException: Prohibited package name:<br />&nbsp;java.lang<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at java.lang.ClassLoader.defineClass(Unknown Source)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at java.security.SecureClassLoader.defineClass(Unknown Source)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at java.net.URLClassLoader.defineClass(Unknown Source)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at java.net.URLClassLoader.access$100(Unknown Source)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at java.net.URLClassLoader$1.run(Unknown Source)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at java.security.AccessController.doPrivileged(Native Method)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at java.net.URLClassLoader.findClass(Unknown Source)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at java.lang.ClassLoader.loadClass(Unknown Source)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at java.lang.ClassLoader.loadClass(Unknown Source)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at java.lang.ClassLoader.loadClassInternal(Unknown Source)</span></p>
<p><span style="font-size: small; font-family: Times New Roman;">奇怪吧？要弄清为什么会有SecurityException，就必须搞清楚ClassLoader的机制。</span></p>
<p><span style="font-size: small; font-family: Times New Roman;">Java的ClassLoader就是用来动态装载class的，ClassLoader对一个class只会装载一次，JVM使用的ClassLoader一共有4种：</span></p>
<p><span style="font-size: small; font-family: Times New Roman;">启动类装载器，标准扩展类装载器，类路径装载器和网络类装载器。</span></p>
<p><span style="font-size: small; font-family: Times New Roman;">这4种ClassLoader的优先级依次从高到低，使用所谓的&ldquo;双亲委派模型&rdquo;。确切地说，如果一个网络类装载器被请求装载一个java.lang.Integer，它会首先把请求发送给上一级的类路径装载器，如果返回已装载，则网络类装载器将不会装载这个java.lang.Integer，如果上一级的类路径装载器返回未装载，它才会装载java.lang.Integer。</span></p>
<p><span style="font-size: small; font-family: Times New Roman;">类似的，类路径装载器收到请求后（无论是直接请求装载还是下一级的ClassLoader上传的请求），它也会先把请求发送到上一级的标准扩展类装载器，这样一层一层上传，于是启动类装载器优先级最高，如果它按照自己的方式找到了java.lang.Integer，则下面的ClassLoader 都不能再装载java.lang.Integer，尽管你自己写了一个java.lang.Integer，试图取代核心库的java.lang.Integer是不可能的，因为自己写的这个类根本无法被下层的ClassLoader装载。</span></p>
<p><span style="font-size: small; font-family: Times New Roman;">再说说Package权限。Java语言规定，在同一个包中的class，如果没有修饰符，默认为Package权限，包内的class都可以访问。但是这还不够准确。确切的说，只有由同一个ClassLoader装载的class才具有以上的Package权限。比如启动类装载器装载了java.lang.String，类路径装载器装载了我们自己写的java.lang.Test，它们不能互相访问对方具有Package权限的方法。这样就阻止了恶意代码访问核心类的Package权限方法。</span></p>
</span></p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://chen-516888.javaeye.com/blog/249173#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">Windows7在微软WinHEC 2008上揭开神秘面纱</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sun, 05 Oct 2008 23:57:00 +0800</pubDate>
        <link>http://chen-516888.javaeye.com/blog/249173</link>
        <guid>http://chen-516888.javaeye.com/blog/249173</guid>
      </item>
          <item>
        <title>常用的算法的时间复杂度和空间复杂度</title>
        <author>chen-516888</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://chen-516888.javaeye.com">chen-516888</a>&nbsp;
                    链接：<a href="http://chen-516888.javaeye.com/blog/245681" style="color:red;">http://chen-516888.javaeye.com/blog/245681</a>&nbsp;
          发表时间: 2008年09月22日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><span class="myfont3">
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<div>
<table border="1" width="587" style="height: 1px;">
<tbody>
<tr>
<td height="37" valign="middle" width="587">
<p align="center"><span style="color: #555555; font-family: 宋体;">排序法 </span></p>
</td>
<td height="37" width="587"><span style="color: #555555; font-family: 宋体;">最差时间分析</span></td>
<td height="37" width="587"><span style="color: #555555; font-family: 宋体;">平均时间复杂度 </span></td>
<td height="37" width="587"><span style="color: #555555;">稳定度 </span></td>
<td height="37" width="587"><span style="color: #555555;">空间复杂度 </span></td>
</tr>
<tr>
<td align="center" height="42" width="587"><span style="color: #555555; font-family: 宋体;">冒泡排序</span></td>
<td align="center" height="42" width="587"><span style="color: #555555; font-family: 宋体;">O(n<sup>2</sup>)</span></td>
<td align="center" height="42" width="587"><span style="color: #555555;">O(n<sup>2</sup>) </span></td>
<td align="center" height="42" width="587"><span style="color: #555555;">稳定 </span></td>
<td align="center" height="42" width="587"><span style="color: #555555;">O(1) </span></td>
</tr>
<tr>
<td align="center" height="39" width="587"><span style="color: #555555; font-family: 宋体;">快速排序</span></td>
<td align="center" height="39" width="587"><span style="color: #555555; font-family: 宋体;">O(n<sup>2</sup>)</span></td>
<td align="center" height="39" width="587"><span style="color: #555555;">O(n*log<sub>2</sub>n) </span></td>
<td align="center" height="39" width="587"><span style="color: #555555;">不稳定 </span></td>
<td align="center" height="39" width="587"><span style="color: #555555;">O(log<sub>2</sub>n)~O(n) </span></td>
</tr>
<tr>
<td align="center" height="39" width="587"><span style="color: #555555; font-family: 宋体;">选择排序</span></td>
<td align="center" height="39" width="587"><span style="color: #555555; font-family: 宋体;">O(n<sup>2</sup>)</span></td>
<td align="center" height="39" width="587"><span style="color: #555555;">O(n<sup>2</sup>) </span></td>
<td align="center" height="39" width="587"><span style="color: #555555;">稳定 </span></td>
<td align="center" height="39" width="587"><span style="color: #555555;">O(1) </span></td>
</tr>
<tr>
<td align="center" height="39" width="587"><span style="color: #555555; font-family: 宋体;">二叉树排序</span></td>
<td align="center" height="39" width="587"><span style="color: #555555; font-family: 宋体;">O(n<sup>2</sup>)</span></td>
<td align="center" height="39" width="587"><span style="color: #555555;">O(n*log<sub>2</sub>n) </span></td>
<td align="center" height="39" width="587"><span style="color: #555555;">不一顶 </span></td>
<td align="center" height="39" width="587"><span style="color: #555555;">O(n) </span></td>
</tr>
<tr>
<td align="center" height="39" width="587">
<p align="center"><span style="color: #555555; font-family: 宋体;">插入排序 </span></p>
</td>
<td align="center" height="39" width="587"><span style="color: #555555; font-family: 宋体;">O(n<sup>2</sup>)</span></td>
<td align="center" height="39" width="587"><span style="color: #555555;">O(n<sup>2</sup>) </span></td>
<td align="center" height="39" width="587"><span style="color: #555555;">稳定 </span></td>
<td align="center" height="39" width="587"><span style="color: #555555;">O(1) </span></td>
</tr>
<tr>
<td align="center" height="39" width="587"><span style="color: #555555; font-family: 宋体;">堆排序</span></td>
<td align="center" height="39" width="587"><span style="color: #555555; font-family: 宋体;">O(n*log<sub>2</sub>n) </span></td>
<td align="center" height="39" width="587"><span style="color: #555555;">O(n*log<sub>2</sub>n) </span></td>
<td align="center" height="39" width="587"><span style="color: #555555;">不稳定 </span></td>
<td align="center" height="39" width="587"><span style="color: #555555;">O(1) </span></td>
</tr>
<tr>
<td align="center" height="39" width="587"><span style="color: #555555; font-family: 宋体;">希尔排序</span></td>
<td align="center" height="39" width="587"><span style="color: #555555; font-family: 宋体;">O</span></td>
<td align="center" height="39" width="587"><span style="color: #555555;">O </span></td>
<td align="center" height="39" width="587"><span style="color: #555555;">不稳定 </span></td>
<td align="center" height="39" width="587"><span style="color: #555555;">O(1)</span></td>
</tr>
</tbody>
</table>
</div>
</span></p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://chen-516888.javaeye.com/blog/245681#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">Windows7在微软WinHEC 2008上揭开神秘面纱</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 22 Sep 2008 23:43:41 +0800</pubDate>
        <link>http://chen-516888.javaeye.com/blog/245681</link>
        <guid>http://chen-516888.javaeye.com/blog/245681</guid>
      </item>
          <item>
        <title>Spring中的事务传播机制</title>
        <author>chen-516888</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://chen-516888.javaeye.com">chen-516888</a>&nbsp;
                    链接：<a href="http://chen-516888.javaeye.com/blog/245672" style="color:red;">http://chen-516888.javaeye.com/blog/245672</a>&nbsp;
          发表时间: 2008年09月22日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><strong>概述</strong></p>
<p>当我们调用一个基于Spring的Service接口方法（如UserService#addUser()）时，它将运行于Spring管理的事务环境中，Service接口方法可能会在内部调用其它的Service接口方法以共同完成一个完整的业务操作，因此就会产生服务接口方法嵌套调用的情况，Spring通过事务传播行为控制当前的事务如何传播到被嵌套调用的目标服务接口方法中。</p>
<p>事务传播是Spring进行事务管理的重要概念，其重要性怎么强调都不为过。但是事务传播行为也是被误解最多的地方，在本文里，我们将详细分析不同事务传播行为的表现形式，掌握它们之间的区别。</p>
<p><strong>事务传播行为种类</strong></p>
<p>Spring在TransactionDefinition接口中规定了7种类型的事务传播行为，它们规定了事务方法和事务方法发生嵌套调用时事务如何进行传播：</p>
<p><a name="_Ref160706115">表</a>1事务传播行为类型</p>
<table cellspacing="1" bordercolor="#cccccc" border="1" cellpadding="1">
<tbody>
<tr class="textblack">
<td width="201">
<p align="center">事务传播行为类型</p>
</td>
<td width="358">
<p align="center">说明</p>
</td>
</tr>
<tr class="textblack">
<td valign="top" width="201">
<p>PROPAGATION_REQUIRED</p>
</td>
<td valign="top" width="358">
<p>如果当前没有事务，就新建一个事务，如果已经存在一个事务中，加入到这个事务中。这是最常见的选择。</p>
</td>
</tr>
<tr class="textblack">
<td valign="top" width="201">
<p>PROPAGATION_SUPPORTS</p>
</td>
<td valign="top" width="358">
<p>支持当前事务，如果当前没有事务，就以非事务方式执行。</p>
</td>
</tr>
<tr class="textblack">
<td valign="top" width="201">
<p>PROPAGATION_MANDATORY</p>
</td>
<td valign="top" width="358">
<p>使用当前的事务，如果当前没有事务，就抛出异常。</p>
</td>
</tr>
<tr class="textblack">
<td valign="top" width="201">
<p>PROPAGATION_REQUIRES_NEW</p>
</td>
<td valign="top" width="358">
<p>新建事务，如果当前存在事务，把当前事务挂起。</p>
</td>
</tr>
<tr class="textblack">
<td valign="top" width="201">
<p>PROPAGATION_NOT_SUPPORTED</p>
</td>
<td valign="top" width="358">
<p>以非事务方式执行操作，如果当前存在事务，就把当前事务挂起。</p>
</td>
</tr>
<tr class="textblack">
<td valign="top" width="201">
<p>PROPAGATION_NEVER</p>
</td>
<td valign="top" width="358">
<p>以非事务方式执行，如果当前存在事务，则抛出异常。</p>
</td>
</tr>
<tr class="textblack">
<td valign="top" width="201">
<p>PROPAGATION_NESTED</p>
</td>
<td valign="top" width="358">
<p>如果当前存在事务，则在嵌套事务内执行。如果当前没有事务，则执行与PROPAGATION_REQUIRED类似的操作。</p>
</td>
</tr>
</tbody>
</table>
<p>当使用PROPAGATION_NESTED时，底层的数据源必须基于JDBC 3.0，并且实现者需要支持保存点事务机制。</p>
<p><strong>几种容易引起误解的组合事务传播行为</strong></p>
<p>当服务接口方法分别使用表1中不同的事务传播行为，且这些接口方法又发生相互调用的情况下，大部分组合都是一目了然，容易理解的。但是，也存在一些容易引起误解的组合事务传播方式。</p>
<p>下面，我们通过两个具体的服务接口的组合调用行为来破解这一难点。这两个服务接口分别是UserService和ForumService，UserSerice有一个addCredits()方法，ForumSerivce#addTopic()方法调用了UserSerice#addCredits()方法，发生关联性服务方法的调用：</p>
<p>public class ForumService {</p>
<p>private UserService userService;</p>
<p>public void <strong>addTopic()</strong>{<strong>①调用其它服务接口的方法</strong></p>
<p>//add Topic&hellip;</p>
<p>userService.<strong>addCredits()</strong>;<strong>②被关联调用的业务方法</strong></p>
<p>}</p>
<p>}</p>
<p>嵌套调用的事务方法</p>
<p>对Spring事务传播行为最常见的一个误解是：当服务接口方法发生嵌套调用时，被调用的服务方法只能声明为PROPAGATION_NESTED。这种观点犯了望文生义的错误，误认为PROPAGATION_NESTED是专为方法嵌套准备的。这种误解遗害不浅，执有这种误解的开发者错误地认为：应尽量不让Service类的业务方法发生相互的调用，Service类只能调用DAO层的DAO类，以避免产生嵌套事务。</p>
<p>其实，这种顾虑是完全没有必要的，PROPAGATION_REQUIRED已经清楚地告诉我们：事务的方法会足够&ldquo;聪明&rdquo;地判断上下文是否已经存在一个事务中，如果已经存在，就加入到这个事务中，否则创建一个新的事务。</p>
<p>依照上面的例子，假设我们将ForumService#addTopic()和UserSerice#addCredits()方法的事务传播行为都设置为PROPAGATION_REQUIRED，这两个方法将运行于同一个事务中。</p>
<p>为了清楚地说明这点，可以将Log4J的日志设置为DEBUG级别，以观察Spring事务管理器内部的运行情况。下面将两个业务方法都设置为PROPAGATION_REQUIRED，Spring所输出的日志信息如下：</p>
<p>Using transaction object </p>
<p>[org.springframework.jdbc.datasource.DataSourceTransactionManager$DataSourceTransactionObject@e3849c]</p>
<p><strong>①为</strong><strong>ForumService#addTopic()</strong><strong>新建一个事务</strong><strong></strong></p>
<p><strong>Creating new transaction with name [com.baobaotao.service.ForumService.addTopic]:</strong> PROPAGATION_REQUIRED,ISOLATION_DEFAULT</p>
<p>Acquired Connection [org.apache.commons.dbcp.PoolableConnection@dc41c5] for JDBC transaction</p>
<p>Switching JDBC Connection [org.apache.commons.dbcp.PoolableConnection@dc41c5] to manual commit</p>
<p>Bound value [org.springframework.jdbc.datasource.ConnectionHolder@ee1ede] for key [org.apache.commons.dbcp.BasicDataSource@4204] to thread [main]</p>
<p>Initializing transaction synchronization</p>
<p>Getting transaction for [com.baobaotao.service.ForumService.addTopic]</p>
<p>Retrieved value [org.springframework.jdbc.datasource.ConnectionHolder@ee1ede] for key [org.apache.commons.dbcp.BasicDataSource@4204] bound to thread [main]</p>
<p>Using transaction object [org.springframework.jdbc.datasource.DataSourceTransactionManager$DataSourceTransactionObject@8b8a47]</p>
<p><strong>②</strong><strong>UserService#addCredits()</strong><strong>简单地加入到已存在的事务中（即①处创建的事务）</strong><strong></strong></p>
<p><strong>Participating in existing transaction</strong></p>
<p>Getting transaction for [com.baobaotao.service.UserService.addCredits]</p>
<p>Completing transaction for [com.baobaotao.service.UserService.addCredits]</p>
<p>Completing transaction for [com.baobaotao.service.ForumService.addTopic]</p>
<p>Triggering beforeCommit synchronization</p>
<p>Triggering beforeCompletion synchronization</p>
<p>Initiating transaction commit</p>
<p>&nbsp;</p>
<p><strong>③调用底层</strong><strong>Connection#commit()</strong><strong>方法提交事务</strong></p>
<p>Committing JDBC transaction on Connection [org.apache.commons.dbcp.PoolableConnection@dc41c5]</p>
<p>Triggering afterCommit synchronization</p>
<p>Triggering afterCompletion synchronization</p>
<p>Clearing transaction synchronization</p>
<p>嵌套事务</p>
<p>将ForumService#addTopic()设置为PROPAGATION_REQUIRED时，UserSerice#addCredits()设置为PROPAGATION_REQUIRED、PROPAGATION_SUPPORTS、PROPAGATION_MANDATORY时，运行的效果都是一致的（当然，如果单独调用addCredits()就另当别论了）。</p>
<p>当addTopic()运行在一个事务下（如设置为PROPAGATION_REQUIRED），而addCredits()设置为PROPAGATION_NESTED时，如果底层数据源支持保存点，Spring将为内部的addCredits()方法产生的一个内嵌的事务。如果addCredits()对应的内嵌事务执行失败，事务将回滚到addCredits()方法执行前的点，并不会将整个事务回滚。内嵌事务是内层事务的一部分，所以只有外层事务提交时，嵌套事务才能一并提交。</p>
<p>嵌套事务不能够提交，它必须通过外层事务来完成提交的动作，外层事务的回滚也会造成内部事务的回滚。</p>
<p>嵌套事务和新事务</p>
<p>PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED也是容易混淆的两个传播行为。PROPAGATION_REQUIRES_NEW 启动一个新的、和外层事务无关的&ldquo;内部&rdquo;事务。该事务拥有自己的独立隔离级别和锁，不依赖于外部事务，独立地提交和回滚。当内部事务开始执行时，外部事务将被挂起，内务事务结束时，外部事务才继续执行。</p>
<p>由此可见， PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED 的最大区别在于：PROPAGATION_REQUIRES_NEW 将创建一个全新的事务，它和外层事务没有任何关系，而 PROPAGATION_NESTED 将创建一个依赖于外层事务的子事务，当外层事务提交或回滚时，子事务也会连带提交和回滚。</p>
<p>其它需要注意问题</p>
<p>以下几个问题值得注意：</p>
<p>1) 当业务方法被设置为PROPAGATION_MANDATORY时，它就不能被非事务的业务方法调用。如将ForumService#addTopic()设置为PROPAGATION_MANDATORY，如果展现层的Action直接调用addTopic()方法，将引发一个异常。正确的情况是：addTopic()方法必须被另一个带事务的业务方法调用（如ForumService#otherMethod()）。所以PROPAGATION_MANDATORY的方法一般都是被其它业务方法间接调用的。</p>
<p>2) 当业务方法被设置为PROPAGATION_NEVER时，它将不能被拥有事务的其它业务方法调用。假设UserService#addCredits()设置为PROPAGATION_NEVER，当ForumService# addTopic()拥有一个事务时，addCredits()方法将抛出异常。所以PROPAGATION_NEVER方法一般是被直接调用的。</p>
<p>3)当方法被设置为PROPAGATION_NOT_SUPPORTED时，外层业务方法的事务会被挂起，当内部方法运行完成后，外层方法的事务重新运行。如果外层方法没有事务，直接运行，不需要做任何其它的事。</p>
<p><strong>小结</strong></p>
<p>在Spring声明式事务管理的配置中，事务传播行为是最容易被误解的配置项，原因在于事务传播行为名称（如PROPAGATION_NESTED：嵌套式事务）和代码结构的类似性上（业务类方法嵌套调用另一个业务类方法）。这种误解在很多Spring开发者中广泛存在，本文深入讲解了Spring事务传播行为对业务方法嵌套调用的真实影响，希望能帮助读者化解对事务传播行为的困惑。</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://chen-516888.javaeye.com/blog/245672#comments" style="color:red;">已有 <strong>1</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">Windows7在微软WinHEC 2008上揭开神秘面纱</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 22 Sep 2008 23:06:48 +0800</pubDate>
        <link>http://chen-516888.javaeye.com/blog/245672</link>
        <guid>http://chen-516888.javaeye.com/blog/245672</guid>
      </item>
          <item>
        <title>The Life Circle of Java Servlet</title>
        <author>chen-516888</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://chen-516888.javaeye.com">chen-516888</a>&nbsp;
                    链接：<a href="http://chen-516888.javaeye.com/blog/245595" style="color:red;">http://chen-516888.javaeye.com/blog/245595</a>&nbsp;
          发表时间: 2008年09月22日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><span><span style="font-size: small;"><strong>&nbsp;&nbsp; </strong><br /></span><strong><span style="font-size: small;">　　1、加载和实例化<br /><br />　　容器负责加载和实例化一个servlet。实例化和加载可以发生在引擎启动的时候，也可以推迟到容器需要该servlet为客户请求服务的时候。<br /><br />　　首先容器必须先定位servlet类，在必要的情况下，容器使用通常的Java类加载工具加载该servlet，可能是从本机文件系统，也可以是从远程文件系统甚至其它的网络服务。容器加载servlet类以后，它会实例化该类的一个实例。需要注意的是可能会实例化多个实例，例如一个servlet类因为有不同的初始参数而有多个定义，或者servlet实现SingleThreadModel而导致容器为之生成一个实例池。<br /><br />　　2、初始化<br /><br />　　servlet加载并实例化后，容器必须在它能够处理客户端请求前初始化它。初始化的过程主要是读取永久的配置信息，昂贵资源（例如JDBC连接）以及其它仅仅需要执行一次的任务。通过调用它的init方法并给它传递唯一的一个（每个servlet定义一个）ServletConfig对象完成这个过程。给它传递的这个配置对象允许servlet访问容器的配置信息中的名称－值对（name-value）初始化参数。这个配置对象同时给servlet提供了访问实现了ServletContext接口的具体对象的方法，该对象描述了servlet的运行环境。<br /><br />　　2.1初始化的错误处理<br /><br />　　在初始化期间，servlet实例可能通过抛出UnavailableException 或者 ServletException异常表明它不能进行有效服务。如果一个servlet抛出一个这样的异常，它将不会被置入有效服务并且应该被容器立即释放。在此情况下destroy方法不会被调用因为初始化没有成功完成。在失败的实例被释放后，容器可能在任何时候实例化一个新的实例，对这个规则的唯一例外是如果失败的servlet抛出的异常是UnavailableException并且该异常指出了最小的无效时间，那么容器就会至少等待该时间指明的时限才会重新试图创建一个新的实例。<br /><br />　　2.2、工具因素<br /><br />　　当工具（注：根据笔者的理解，这个工具可能是应用服务器的某些检查工具，通常是验证应用的合法性和完整性）加载和内省（introspect）一个web应用时，它可能加载和内省该应用中的类，这个行为将触发那些类的静态初始方法被执行，因此，开发者不能假定只要当servlet的init方法被调用后它才处于活动容器运行状态（active container runtime）。作为一个例子，这意味着servlet不能在它的静态（类）初始化方法被调用时试图建立数据库连接或者连接EJB容器。<br /><br />　　3、处理请求<br /><br />　　在servlet被适当地初始化后，容器就可以使用它去处理请求了。每一个请求由ServletRequest类型的对象代表，而servlet使用ServletResponse回应该请求。这些对象被作为service方法的参数传递给servlet。在HTTP请求的情况下，容器必须提供代表请求和回应的HttpServletRequest和HttpServletResponse的具体实现。需要注意的是容器可能会创建一个servlet实例并将之放入等待服务的状态，但是这个实例在它的生存期中可能根本没有处理过任何请求。<br /><br />　　3.1、多线程问题<br /><br />　　容器可能同时将多个客户端的请求发送给一个实例的service方法，这也就意味着开发者必须确保编写的servlet可以处理并发问题。如果开发者想防止这种缺省的行为，那么他可以让他编写的servlet实现SingleThreadModel。实现这个类可以保证一次只会有一个线程在执行service方法并且一次性执行完。容器可以通过将请求排队或者维护一个servlet实例池满足这一点。如果servlet是分布式应用的一部分，那么，那么容器可能在该应用分布的每个JVM中都维护一个实例池。如果开发者使用synchronized关键字定义service方法(或者是doGet和doPost)，容器将排队处理请求，这是由底层的java运行时系统要求的。我们强烈推荐开发者不要同步service方法或者HTTPServlet的诸如doGet和doPost这样的服务方法。<br /><br />　　3.2、处理请求中的异常<br /><br />　　servlet在对请求进行服务的时候有可能抛出ServletException或者UnavailableException异常。ServletException表明在处理请求的过程中发生了错误容器应该使用合适的方法清除该请求。UnavailableException表明servlet不能对请求进行处理，可能是暂时的，也可能是永久的。如果UnavailableException指明是永久性的，那么容器必须将servlet从服务中移除，调用它的destroy方法并释放它的实例。如果指明是暂时的，那么容器可以选择在异常信息里面指明的这个暂时无法服务的时间段里面不向它发送任何请求。在这个时间段里面被被拒绝的请求必须使用SERVICE_UNAVAILABLE (503)返回状态进行响应并且应该携带稍后重试（Retry-After）的响应头表明不能服务只是暂时的。容器也可以选择不对暂时性和永久性的不可用进行区分而全部当作永久性的并移除抛出异常的servlet。<br /><br />　　3.3线程安全<br /><br />　　开发者应该注意容器实现的请求和响应对象（注：即容器实现的HttpServletRequest和HttpServletResponese）没有被保证是线程安全的，这就意味着他们只能在请求处理线程的范围内被使用，这些对象不能被其它执行线程所引用，因为引用的行为是不确定的。<br /><br />　　4、服务结束<br /><br />　　容器没有被要求将一个加载的servlet保存多长时间，因此一个servlet实例可能只在容器中存活了几毫秒，当然也可能是其它更长的任意时间（但是肯定会短于容器的生存期）当容器决定将之移除时（原因可能是保存内存资源或者自己被关闭），那么它必须允许servlet释放它正在使用的任何资源并保存任何永久状态（这个过程通过调用destroy方法达到）。容器在能够调用destroy方法前，它必须允许那些正在service方法中执行的线程执行完或者在服务器定义的一段时间内执行（这个时间段在容器调用destroy之前）。一旦destroy方法被调用，容器就不会再向该实例发送任何请求。如果容器需要再使用该servlet，它必须创建新的实例。destroy方法完成后，容器必须释放servlet实例以便它能够被垃圾回收。</span></strong></span><span style="font-size: small;"> </span></p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://chen-516888.javaeye.com/blog/245595#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">Windows7在微软WinHEC 2008上揭开神秘面纱</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 22 Sep 2008 18:49:47 +0800</pubDate>
        <link>http://chen-516888.javaeye.com/blog/245595</link>
        <guid>http://chen-516888.javaeye.com/blog/245595</guid>
      </item>
          <item>
        <title>体验Java 5.0的新增语言特性</title>
        <author>chen-516888</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://chen-516888.javaeye.com">chen-516888</a>&nbsp;
                    链接：<a href="http://chen-516888.javaeye.com/blog/244947" style="color:red;">http://chen-516888.javaeye.com/blog/244947</a>&nbsp;
          发表时间: 2008年09月20日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <h1 id="artibodyTitle"><span style="font-size: small;">我们将从最简单的特性开始，逐步过渡到高级特性。泛型所包含的内容特别丰富，因此占了本文一半的篇幅。</span>
<p><span style="font-size: small;">　　增强的for循环<br /><br />　　为了迭代集合和数组，增强的for循环提供了一个简单、兼容的语法。有两点值得一提： </span></p>
<span style="font-size: small;">　　Init表达式<br /><br />　　在循环中，初始化表达式只计算一次。这意味着您通常可以移除一个变量声明。在这个例子中，我们必须创建一个整型数组来保存computeNumbers()的结果，以防止每一次循环都重新计算该方法。您可以看到，下面的代码要比上面的代码整洁一些，并且没有泄露变量numbers： <br /></span>
<pre class="code"><span style="font-size: small;">　　未增强的For：
　　int sum = 0;
　　Integer[] numbers = computeNumbers();
　　for (int i=0; i &lt; numbers.length ; i++)
    sum += numbers[i];

　
　　增强后的For： 
　　　int sum = 0;

　　for ( int number: computeNumbers() )
    sum += number;</span></pre>
<span style="font-size: small;">　　局限性<br /><br />　　有时需要在迭代期间访问迭代器或下标，看起来增强的for循环应该允许该操作，但事实上不是这样，请看下面的例子： </span>
<pre class="code"><span style="font-size: small;">for (int i=0; i &lt; numbers.length ; i++) {
    if (i != 0) System.out.print(",");
    System.out.print(numbers[i]);
}</span></pre>
<p><span style="font-size: small;">　　我们希望将数组中的值打印为一个用逗号分隔的清单。我们需要知道目前是否是第一项，以便确定是否应该打印逗号。使用增强的for循环是无法获知这种信息的。我们需要自己保留一个下标或一个布尔值来指示是否经过了第一项。 　　这是另一个例子： </span></p>
<pre class="code"><span style="font-size: small;">for (Iterator&lt;integer&gt; it = n.iterator() ; it.hasNext() ; )
    if (it.next() &lt; 0)
        it.remove();</span></pre>
<p><span style="font-size: small;">　　在此例中，我们想从整数集合中删除负数项。为此，需要对迭代器调用一个方法，但是当使用增强的for 循环时，迭代器对我们来说是看不到的。因此，我们只能使用Java 5之前版本的迭代方法。 　　顺便说一下，这里需要注意的是，由于Iterator是泛型，所以其声明是Iterator&lt;Integer&gt;。许多人都忘记了这一点而使用了Iterator的原始格式。 </span></p>
<span style="font-size: small;">　　注释<br /><br />　　注释处理是一个很大的话题。因为本文只关注核心的语言特性，所以我们不打算涵盖它所有的可能形式和陷阱。　　我们将讨论内置的注释（SuppressWarnings，Deprecated和Override）以及一般注释处理的局限性。 </span>
<p><span style="font-size: small;">　　Suppress Warnings<br /><br />　　该注释关闭了类或方法级别的编译器警告。有时候您比编译器更清楚地知道，代码必须使用一个被否决的方法或执行一些无法静态确定是否类型安全的动作，而使用：</span></p>
<pre class="code"><span style="font-size: small;">@SuppressWarnings("deprecation")
public static void selfDestruct() {
    Thread.currentThread().stop();
}</span></pre>
<p><span style="font-size: small;">　　这可能是内置注释最有用的地方。遗憾的是，1.5.0_04的javac不支持它。但是1.6支持它，并且Sun正在努力将其向后移植到1.5中。 <br />Eclipse 3.1中支持该注释，其他IDE也可能支持它。这允许您把代码彻底地从警告中解脱出来。如果在编译时出现警告，可以确定是您刚刚把它添加进来&mdash;&mdash;以帮助查看那些可能不安全的代码。随着泛型的添加，它使用起来将更趁手。 </span></p>
<span style="font-size: small;">　　Deprecated<br /><br />　　遗憾的是，Deprecated没那么有用。它本来旨在替换@deprecated javadoc标签，但是由于它不包含任何字段，所以也就没有方法来建议deprecated类或方法的用户应该使用什么做为替代品。大多数用法都同时需要javadoc标签和这个注释。 Override </span>
<p><span style="font-size: small;">　　Override表示，它所注释的方法应该重写超类中具有相同签名的方法： </span></p>
<pre class="code"><span style="font-size: small;">@Override
public int hashCode() {
    ...
}</span></pre>
<p><span style="font-size: small;">　　看上面的例子，如果没有在hashCode中将&ldquo;C&rdquo;大写，在编译时不会出现错误，但是在运行时将无法像期望的那样调用该方法。通过添加Override标签，编译器会提示它是否真正地执行了重写。 <br /><br />　　在超类发生改变的情况中，这也很有帮助。如果向该方法中添加一个新参数，而且方法本身也被重命名了，那么子类将突然不能编译，因为它不再重写超类的任何东西。 </span></p>
<p><span style="font-size: small;">　　其它注释<br /><br />　　注释在其他场景中非常有用。当不是直接修改行为而是增强行为时，特别是在添加样板代码的情况下，注释在诸如EJB和</span><a href="http://dev2dev.bea.com/pub/a/2004/10/Anil_WServices.html" target="_blank"><span style="font-size: small;">Web services</span></a><span style="font-size: small;">这样的框架中运行得非常好。 <br />注释不能用做预处理器。Sun的设计特别预防了完全因为注释而修改类的字节码。这样可以正确地理解该语言的成果，而且IDE之类的工具也可以执行深入的代码分析和重构之类的功能。 <br /><br />　　注释不是银弹。第一次遇到的时候，人们试图尝试各种技巧。请看下面这个从别人那里获得的建议： </span></p>
<pre class="code"><span style="font-size: small;">public class Foo {
 
    @Property
    private int bar;
 
}</span></pre>
<p><span style="font-size: small;">　　其思想是为私有字段bar自动创建getter和setter方法。遗憾的是，这个想法有两个失败之处：1)它不能运行，2)它使代码难以阅读和处理。 　　它是无法实现的，因为前面已经提到了，Sun特别阻止了对出现注释的类进行修改。 <br /><br />　　即使是可能的，它也不是一个好主意，因为它使代码可读性差。第一次看到这段代码的人会不知道该注释创建了方法。此外，如果将来您需要在这些方法内部执行一些操作，注释也是没用的。<br /><br />　　总之，不要试图用注释去做那些常规代码可以完成的事情。 </span></p>
<p><span style="font-size: small;">　　枚举 <br /><br />　　enum非常像public static final int声明，后者作为枚举值已经使用了很多年。对int所做的最大也是最明显的改进是类型安全&mdash;&mdash;您不能错误地用枚举的一种类型代替另一种类型，这一点和int不同，所有的int对编译器来说都是一样的。除去极少数例外的情况，通常都应该用enum实例替换全部的枚举风格的int结构。 <br /><br />　　枚举提供了一些附加的特性。EnumMap和EnumSet这两个实用类是专门为枚举优化的标准集合实现。如果知道集合只包含枚举类型，那么应该使用这些专门的集合来代替Has　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　hMap或HashSet。 <br /><br />　　大部分情况下，可以使用enum对代码中的所有public static final int做插入替换。它们是可比的，并且可以静态导入，所以对它们的引用看起来是等同的，即使是对于内部类（或内部枚举类型）。注意，比较枚举类型的时候，声明它们的指令表明了它们的顺序值。 <br /><br />　　&ldquo;隐藏的&rdquo;静态方法 <br /><br />　　两个静态方法出现在所有枚举类型声明中。因为它们是枚举子类上的静态方法，而不是Enum本身的方法，所以它们在java.lang.Enum的javadoc中没有出现。 <br /><br />　　第一个是values()，返回一个枚举类型所有可能值的数组。 <br /><br />　　第二个是valueOf()，为提供的字符串返回一个枚举类型，该枚举类型必须精确地匹配源代码声明。 <br /></span><br /><span style="font-size: small;">　　方法<br /></span><br /><span style="font-size: small;">　　关于枚举类型，我们最喜欢的一个方面是它可以有方法。过去您可能需要编写一些代码，对public static final int进行转换，把它从数据库类型转换为JDBC URL。而现在则可以让枚举类型本身带一个整理代码的方法。下面就是一个例子，包括DatabaseType枚举类型的抽象方法以及每个枚举实例中提供的实现： <br /></span></p>
<pre class="code"><span style="font-size: small;">  public enum  DatabaseType {
  ORACLE {
  public String getJdbcUrl() {...}
  },
  MYSQL {
  public String getJdbcUrl() {...}
  };
  public abstract String getJdbcUrl();
  }</span></pre>
<span style="font-size: small;">　　现在枚举类型可以直接提供它的实用方法。例如：<br /><br />DatabaseType dbType = ...;<br />String jdbcURL = dbType.getJdbcUrl();<br /><br />　　要获取URL，必须预先知道该实用方法在哪里。 </span>
<p><span style="font-size: small;">　　可变参数(Vararg)<br /><br />　　正确地使用可变参数确实可以清理一些垃圾代码。典型的例子是一个带有可变的String参数个数的log方法：&nbsp;<br /><br />&nbsp;&nbsp;&nbsp; Log.log(String code)<br />&nbsp;&nbsp;&nbsp; Log.log(String code,&nbsp; String arg)<br />&nbsp;&nbsp;&nbsp; Log.log(String code,&nbsp; String arg1, String arg2)<br />&nbsp;&nbsp;&nbsp; Log.log(String code,&nbsp; String[] args)</span></p>
<span style="font-size: small;">　　当讨论可变参数时，比较有趣的是，如果用新的可变参数替换前四个例子，将是兼容的： <br /><br />Log.log(String code, String... args)<br /><br />　　所有的可变参数都是源兼容的&mdash;&mdash;那就是说，如果重新编译log()方法的所有调用程序，可以直接替换全部的四个方法。然而，如果需要向后的二进制兼容性，那么就需要舍去前三个方法。只有最后那个带一个字符串数组参数的方法等效于可变参数版本，因此可以被可变参数版本替换。 <br /></span><br /><span style="font-size: small;">　　类型强制转换 </span><br /><br /><span style="font-size: small;">　　如果希望调用程序了解应该使用哪种类型的参数，那么应该避免用可变参数进行类型强制转换。看下面这个例子，第一项希望是String，第二项希望是Exception： <br /></span>
<pre class="code"><span style="font-size: small;">    Log.log(Object...  objects) {
    String message = (String)objects[0];
    if (objects.length &gt; 1) {
    Exception e = (Exception)objects[1];
    // Do something with the exception
    }
    }</span></pre>
<span style="font-size: small;">　　方法签名应该如下所示，相应的可变参数分别使用String和Exception声明： <br /><br />Log.log(String message, Exception e, Object... objects) {...}<br /><br />　　不要使用可变参数破坏类型系统。需要强类型化时才可以使用它。对于这个规则，PrintStream.printf()是一个有趣的例外：它提供类型信息作为自己的第一个参数，以便稍后可以接受那些类型。 <br /></span><br /><span style="font-size: small;">　　协变返回 </span><br /><br /><span style="font-size: small;">　　协变返回的基本用法是用于在已知一个实现的返回类型比API更具体的时候避免进行类型强制转换。在下面这个例子中，有一个返回Animal对象的Zoo接口。我们的实现返回一个AnimalImpl对象，但是在JDK 1.5之前，要返回一个Animal对象就必须声明。:<br /></span>
<pre class="code"><span style="font-size: small;">    public interface Zoo  {
    public Animal getAnimal();
    }
  public class ZooImpl  implements Zoo {
  public Animal getAnimal(){
  return new AnimalImpl();
  }
  }</span></pre>
<span style="font-size: small;">　　协变返回的使用替换了三个反模式： </span>
<p>&nbsp;</p>
<ul>
<li><span style="font-size: small;">直接字段访问。为了规避API限制，一些实现把子类直接暴露为字段： ZooImpl._animal<br /></span></li>
<li><span style="font-size: small;">另一种形式是，在知道实现的实际上是特定的子类的情况下，在调用程序中执行向下转换： ((AnimalImpl)ZooImpl.getAnimal()).implMethod();<br /></span></li>
<li><span style="font-size: small;">我看到的最后一种形式是一个具体的方法，该方法用来避免由一个完全不同的签名所引发的问题： ZooImpl._getAnimal();</span></li>
</ul>
<br /><span style="font-size: small;">　　这三种模式都有它们的问题和局限性。要么是不够整洁，要么就是暴露了不必要的实现细节。 <br /></span><br /><span style="font-size: small;">　　协变 <br /></span><br /><span style="font-size: small;">　　协变返回模式就比较整洁、安全并且易于维护，它也不需要类型强制转换或特定的方法或字段： <br /><br />public AnimalImpl getAnimal(){<br />return new AnimalImpl();<br />}<br /><br />　　使用结果： <br />ZooImpl.getAnimal().implMethod();<br /><br /></span><span style="font-size: small;">　　使用泛型<br /><br />　　我们将从两个角度来了解泛型：使用泛型和构造泛型。我们不讨论List、Set和Map的显而易见的用法。知道泛型集合是强大的并且应该经常使用就足够了。 <br /><br />　　我们将讨论泛型方法的使用以及编译器推断类型的方法。通常这些都不会出问题，但是当出问题时，错误信息会非常令人费解，所以需要了解如何修复这些问题。<br /></span></h1>
<p><span style="font-size: small;"><strong>范型方法<br /><br />　　除了泛型类型，Java 5还引入了泛型方法。在这个来自java.util.Collections的例子中，构造了一个单元素列表。新的List的元素类型是根据传入方法的对象的类型来推断的： </strong></span></p>
<pre class="code"><span style="font-size: small;"><strong>static &lt;T&gt; List&lt;T&gt; Collections.singletonList(T o)

　　示例用法：

public List&lt;Integer&gt; getListOfOne() {
    return Collections.singletonList(1);
}</strong></span></pre>
<p><span style="font-size: small;"><strong>　　在示例用法中，我们传入了一个int。所以方法的返回类型就是List&lt;Integer&gt;。编译器把T推断为Integer。这和泛型类型是不同的，因为您通常不需要显式地指定类型参数。 <br />这也显示了自动装箱和泛型的相互作用。类型参数必须是引用类型：这就是为什么我们得到的是List&lt;Integer&gt;而不是List&lt;int&gt;。 </strong></span></p>
<p><span style="font-size: small;"><strong>　　不带参数的泛型方法<br /><br />　　emptyList()方法与泛型一起引入，作为java.util.Collections中EMPTY_LIST字段的类型安全置换： </strong></span></p>
<pre class="code"><span style="font-size: small;"><strong>static &lt;T&gt; List&lt;T&gt; Collections.emptyList()

　　示例用法： 

public List&lt;Integer&gt; getNoIntegers() {
    return Collections.emptyList();
}</strong></span></pre>
<p><span style="font-size: small;"><strong>　　与先前的例子不同，这个方法没有参数，那么编译器如何推断T的类型呢？基本上，它将尝试使用一次参数。如果没有起作用，它再次尝试使用返回或赋值类型。在本例中，返回的是List&lt;Integer&gt;，所以T被推断为Integer。 <br /><br />　　如果在返回语句或赋值语句之外的位置调用泛型方法会怎么样呢？那么编译器将无法执行类型推断的第二次传送。在下面这个例子中，emptyList()是从条件运算符内部调用的： </strong></span></p>
<pre class="code"><span style="font-size: small;"><strong>public List&lt;Integer&gt; getNoIntegers() {
    return x ? Collections.emptyList() : null;
}</strong></span></pre>
<p><span style="font-size: small;"><strong>　　因为编译器看不到返回上下文，也不能推断T，所以它放弃并采用Object。您将看到一个错误消息，比如：&ldquo;无法将List&lt;Object&gt;转换为List&lt;Integer&gt;。&rdquo; <br />为了修复这个错误，应显式地向方法调用传递类型参数。这样，编译器就不会试图推断类型参数，就可以获得正确的结果： </strong></span></p>
<pre class="code"><span style="font-size: small;"><strong>return x ? Collections.&lt;Integer&gt;emptyList() : null;</strong></span></pre>
<p><span style="font-size: small;"><strong>　　这种情况经常发生的另一个地方是在方法调用中。如果一个方法带一个List&lt;String&gt;参数，并且需要为那个参数调用这个传递的emptyList()，那么也需要使用这个语法。 </strong></span></p>
<p><span style="font-size: small;"><strong>　　集合之外<br /><br />　　这里有三个泛型类型的例子，它们不是集合，而是以一种新颖的方式使用泛型。这三个例子都来自标准的Java库： </strong></span></p>
<ul>
<li><span style="font-size: small;"><strong>Class&lt;T&gt;<br />Class在类的类型上被参数化了。这就使无需类型强制转换而构造一个newInstance成为可能。 </strong></span></li>
<li><span style="font-size: small;"><strong>Comparable&lt;T&gt;<br />Comparable被实际的比较类型参数化。这就在compareTo()调用时提供了更强的类型化。例如，String实现Comparable&lt;String&gt;。对除String之外的任何东西调用compareTo()，都会在编译时失败。 </strong></span></li>
<li><span style="font-size: small;"><strong>Enum&lt;E extends Enum&lt;E&gt;&gt;<br />Enum被枚举类型参数化。一个名为Color的枚举类型将扩展Enum&lt;Color&gt;。getDeclaringClass()方法返回枚举类型的类对象，在这个例子中就是一个Color对象。它与getClass()不同，后者可能返回一个无名类。 </strong></span></li>
</ul>
<p><span style="font-size: small;"><strong>　　通配符<br /><br />　　泛型最复杂的部分是对通配符的理解。我们将讨论三种类型的通配符以及它们的用途。 <br /><br />　　首先让我们了解一下数组是如何工作的。可以从一个Integer[]为一个Number[]赋值。如果尝试把一个Float写到Number[]中，那么可以编译，但在运行时会失败，出现一个ArrayStoreException： </strong></span></p>
<pre class="code"><span style="font-size: small;"><strong>Integer[] ia = new Integer[5];
Number[] na = ia;
na[0] = 0.5; // compiles, but fails at runtime

　　如果试图把该例直接转换成泛型，那么会在编译时失败，因为赋值是不被允许的：

List&lt;Integer&gt; iList = new ArrayList&lt;Integer&gt;();
List&lt;Number&gt; nList = iList; // not allowed
nList.add(0.5);</strong></span></pre>
<p><span style="font-size: small;"><strong>　　如果使用泛型，只要代码在编译时没有出现警告，就不会遇到运行时ClassCastException。 </strong></span></p>
<p><span style="font-size: small;"><strong>　　上限通配符<br /><br />　　我们想要的是一个确切元素类型未知的列表，这一点与数组是不同的。 <br /><br />　　List&lt;Number&gt;是一个列表，其元素类型是具体类型Number。 <br />　　List&lt;? extends Number&gt;是一个确切元素类型未知的列表。它是Number或其子类型。 </strong></span></p>
<p><span style="font-size: small;"><strong>　　上限<br /><br />　　如果我们更新初始的例子，并赋值给List&lt;? extends Number&gt;，那么现在赋值就会成功了： </strong></span></p>
<pre class="code"><span style="font-size: small;"><strong>List&lt;Integer&gt; iList = new ArrayList&lt;Integer&gt;();
List&lt;? extends Number&gt; nList = iList;
Number n = nList.get(0);
nList.add(0.5); // Not allowed</strong></span></pre>
<p><span style="font-size: small;"><strong>　　我们可以从列表中得到Number，因为无论列表的确切元素类型是什么（Float、Integer或Number），我们都可以把它赋值给Number。 <br /><br />　　我们仍然不能把浮点类型插入列表中。这会在编译时失败，因为我们不能证明这是安全的。如果我们想要向列表中添加浮点类型，它将破坏iList的初始类型安全&mdash;&mdash;它只存储Integer。 <br /><br />　　通配符给了我们比数组更多的表达能力。 </strong></span></p>
<p><span style="font-size: small;"><strong>　　为什么使用通配符<br /><br />　　在下面这个例子中，通配符用于向API的用户隐藏类型信息。在内部，Set被存储为CustomerImpl。而API的用户只知道他们正在获取一个Set，从中可以读取Customer。 <br />此处通配符是必需的，因为无法从Set&lt;CustomerImpl&gt;向Set&lt;Customer&gt;赋值： </strong></span></p>
<pre class="code"><span style="font-size: small;"><strong>public class CustomerFactory {
    private Set&lt;CustomerImpl&gt; _customers;
    public Set&lt;? extends Customer&gt; getCustomers() {
        return _customers;
    }
}</strong></span></pre>
<p><span style="font-size: small;"><strong>　　通配符和协变返回<br /><br />　　通配符的另一种常见用法是和协变返回一起使用。与赋值相同的规则可以应用到协变返回上。如果希望在重写的方法中返回一个更具体的泛型类型，声明的方法必须使用通配符： </strong></span></p>
<pre class="code"><span style="font-size: small;"><strong>public interface NumberGenerator {
    public List&lt;? extends Number&gt; generate();
}
public class FibonacciGenerator extends NumberGenerator {
    public List&lt;Integer&gt; generate() {
        ...
    }
}</strong></span></pre>
<p><span style="font-size: small;"><strong>　　如果要使用数组，接口可以返回Number[]，而实现可以返回Integer[]。 </strong></span></p>
<p><span style="font-size: small;"><strong>　　下限 <br /><br />　　我们所谈的主要是关于上限通配符的。还有一个下限通配符。List&lt;? super Number&gt;是一个确切&ldquo;元素类型&rdquo;未知的列表，但是可能是Mnumber，或者Number的超类型。所以它可能是一个List&lt;Number&gt;或一个List&lt;Object&gt;。 <br /><br />　　下限通配符远没有上限通配符那样常见，但是当需要它们的时候，它们就是必需的。 </strong></span></p>
<p><span style="font-size: small;"><strong>　　下限与上限<br /></strong></span></p>
<pre class="code"><span style="font-size: small;"><strong>List&lt;? extends Number&gt; readList = new ArrayList&lt;Integer&gt;();
Number n = readList.get(0);

List&lt;? super Number&gt; writeList = new ArrayList&lt;Object&gt;();
writeList.add(new Integer(5));</strong></span></pre>
<p><span style="font-size: small;"><strong>　　第一个是可以从中读数的列表。 <br />　　第二个是可以向其写数的列表。 </strong></span></p>
<p><span style="font-size: small;"><strong>　　无界通配符<br /><br />　　最后，List&lt;?&gt;列表的内容可以是任何类型，而且它与List&lt;? extends Object&gt;几乎相同。可以随时读取Object，但是不能向列表中写入内容。 公共API中的通配符 </strong></span></p>
<p><span style="font-size: small;"><strong>　　总之，正如前面所说，通配符在向调用程序隐藏实现细节方面是非常重要的，但即使下限通配符看起来是提供只读访问，由于remove(int position)之类的非泛型方法，它们也并非如此。如果您想要一个真正不变的集合，可以使用java.util.Collection上的方法，比如unmodifiableList()。 <br /><br />　　编写API的时候要记得通配符。通常，在传递泛型类型时，应该尝试使用通配符。它使更多的调用程序可以访问API。 <br /><br />　　通过接收List&lt;? extends Number&gt;而不是List&lt;Number&gt;，下面的方法可以由许多不同类型的列表调用： </strong></span></p>
<pre class="code"><span style="font-size: small;"><strong>void removeNegatives(List&lt;? extends Number&gt; list);</strong></span></pre>
<p><span style="font-size: small;"><strong>　　构造泛型类型<br /><br />　　现在我们将讨论构造自己的泛型类型。我们将展示一些例子，其中通过使用泛型可以提高类型安全性，我们还将讨论一些实现泛型类型时的常见问题。<br /><br />　　集合风格(Collection-like)的函数 </strong></span></p>
<p><span style="font-size: small;"><strong>　　第一个泛型类的例子是一个集合风格的例子。Pair有两个类型参数，而且字段是类型的实例： </strong></span></p>
<pre class="code"><span style="font-size: small;"><strong>public final class Pair&lt;A,B&gt; {
    public final A first;
    public final B second;

    public Pair(A first, B second) {
        this.first = first;
        this.second = second;
    }
}</strong></span></pre>
<p><span style="font-size: small;"><strong>　　这使从方法返回两个项而无需为每个两种类型的组合编写专用的类成为可能。另一种方法是返回Object[]，而这样是类型不安全或者不整洁的。 <br /><br />　　在下面的用法中，我们从方法返回一个File和一个Boolean。方法的客户端可以直接使用字段而无需类型强制转换： </strong></span></p>
<pre class="code"><span style="font-size: small;"><strong>public Pair&lt;File,Boolean&gt; getFileAndWriteStatus(String path){
    // create file and status
    return new Pair&lt;File,Boolean&gt;(file, status);
}

Pair&lt;File,Boolean&gt; result = getFileAndWriteStatus("...");
File f = result.first;
boolean writeable = result.second;</strong></span></pre>
<p><span style="font-size: small;"><strong>　　集合之外 <br /><br />　　在下面这个例子中，泛型被用于附加的编译时安全性。通过把DBFactory类参数化为所创建的Peer类型，您实际上是在强制Factory子类返回一个Peer的特定子类型： </strong></span></p>
<pre class="code"><span style="font-size: small;"><strong>public abstract class DBFactory&lt;T extends DBPeer&gt; {
    protected abstract T createEmptyPeer();
    public List&lt;T&gt; get(String constraint) {
        List&lt;T&gt; peers = new ArrayList&lt;T&gt;();
        // database magic
        return peers;
    }
}

　　通过实现DBFactory&lt;Customer&gt;，CustomerFactory必须从createEmptyPeer()返回一个Customer：

public class CustomerFactory extends DBFactory&lt;Customer&gt;{

    public Customer createEmptyPeer() {
        return new Customer();
    }
}</strong></span></pre>
<p><span style="font-size: small;"><strong>　　泛型方法<br /><br />　　不管想要对参数之间还是参数与返回类型之间的泛型类型施加约束，都可以使用泛型方法： <br /><br />　　例如，如果编写的反转函数是在位置上反转，那么可能不需要泛型方法。然而，如果希望反转返回一个新的List，那么可能会希望新List的元素类型与传入的List的类型相同。在这种情况下，就需要一个泛型方法： </strong></span></p>
<p><br /><span style="font-size: small;"><strong>&lt;T&gt; List&lt;T&gt; reverse(List&lt;T&gt; list) </strong></span></p>
<p><span style="font-size: small;"><strong>　　具体化<br /><br />　　当实现一个泛型类时，您可能想要构造一个数组T[]。因为泛型是通过擦除(erasure)实现的，所以这是不允许的。 <br /><br />　　您可以尝试把Object[]强制转换为T[]。但这是不安全的。 </strong></span></p>
<p><span style="font-size: small;"><strong>　　具体化解决方案<br /><br />　　按照泛型教程的惯例，解决方案使用的是&ldquo;类型令牌&rdquo;，通过向构造函数添加一个Class&lt;T&gt;参数，可以强制客户端为类的类型参数提供正确的类对象： </strong></span></p>
<pre class="code"><span style="font-size: small;"><strong>public class ArrayExample&lt;T&gt; {
    private Class&lt;T&gt; clazz;

    public ArrayExample(Class&lt;T&gt; clazz) {
        this.clazz = clazz;
    }

    public T[] getArray(int size) {
        return (T[])Array.newInstance(clazz, size);
    }
}</strong></span></pre>
<p><span style="font-size: small;"><strong>　　为了构造ArrayExample&lt;String&gt;，客户端必须把String.class传递给构造函数，因为String.class的类型是Class&lt;String&gt;。 <br /><br />　　拥有类对象使构造一个具有正确元素类型的数组成为可能。</strong></span></p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://chen-516888.javaeye.com/blog/244947#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">Windows7在微软WinHEC 2008上揭开神秘面纱</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sat, 20 Sep 2008 17:04:25 +0800</pubDate>
        <link>http://chen-516888.javaeye.com/blog/244947</link>
        <guid>http://chen-516888.javaeye.com/blog/244947</guid>
      </item>
          <item>
        <title>MVC 模式中的设计模式</title>
        <author>chen-516888</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://chen-516888.javaeye.com">chen-516888</a>&nbsp;
                    链接：<a href="http://chen-516888.javaeye.com/blog/244141" style="color:red;">http://chen-516888.javaeye.com/blog/244141</a>&nbsp;
          发表时间: 2008年09月19日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>&nbsp;&nbsp;MVC,即Model-View-Controller模式.常作为一种设计模式出现在各种讨论中,但是个人觉得MVC设计模式实际上是架构模式,而不是设计模式.</p>
<p>&nbsp; John Vlissides在"GOF95"中提到:</p>
<p>&nbsp; "避免了可以分割成较小模式的大的模式.比如,我们没有把Smalltalk的模型-视图-控制器(Model-View-Controller,MVC)当作一个模式提出,因为他很大程度上是有我们已有的较小的模式组成的.我承认,MVC模式比单纯的合成模式加策略模式加观察者模式要多一些东西,但是我们不想在有更基础的模式需要讨论的时候,把时间花费在讨论MVC模式之上."</p>
<p>&nbsp;&nbsp;&nbsp;MVC模式主要有以下三种设计模式组成:</p>
<p>&nbsp;&nbsp; 1.Composite Pattern.</p>
<p>&nbsp;&nbsp; 2.Strategy Pattern.</p>
<p>&nbsp;&nbsp; 3.Observer Pattern.</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;</p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://chen-516888.javaeye.com/blog/244141#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">Windows7在微软WinHEC 2008上揭开神秘面纱</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 19 Sep 2008 14:45:47 +0800</pubDate>
        <link>http://chen-516888.javaeye.com/blog/244141</link>
        <guid>http://chen-516888.javaeye.com/blog/244141</guid>
      </item>
          <item>
        <title>Java 5.0 new feature</title>
        <author>chen-516888</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://chen-516888.javaeye.com">chen-516888</a>&nbsp;
                    链接：<a href="http://chen-516888.javaeye.com/blog/242653" style="color:red;">http://chen-516888.javaeye.com/blog/242653</a>&nbsp;
          发表时间: 2008年09月16日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>静态导入，在你自己的类中使用静态导入，可以让你使用其它类中定义的类方法和类变量，而且这些类方法和类变量就像在本地定义的一样。也就是说，静态导入允许您在调用其它类中定义的静态成员时，可以忽略类名。 <br /><br />代码:</p>
<p><br /><span style="color: violet;">Test类里定义了一些静态常量和方法</span></p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a href="http://www.javaeye.com/topic/241322#" title="复制代码" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;"><img src="http://www.javaeye.com/images/icon_copy.gif" alt="复制代码" /></a></div>
</div>
<ol class="dp-j">
<li><span><span class="keyword"><strong><span style="color: #7f0055;">package</span></strong></span><span>&nbsp;org.yaoyuan.test; &nbsp;&nbsp;</span></span></li>
<li><span>&nbsp;&nbsp;</span></li>
<li><span class="keyword"><strong><span style="color: #7f0055;">public</span></strong></span><span>&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">class</span></strong></span><span>&nbsp;Test&nbsp;{ &nbsp;&nbsp;</span></li>
<li><span>&nbsp;&nbsp;</span></li>
<li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">public</span></strong></span><span>&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">static</span></strong></span><span>&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">final</span></strong></span><span>&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">int</span></strong></span><span>&nbsp;A&nbsp;=&nbsp;</span><span class="number"><span style="color: #c00000;">10</span></span><span>; &nbsp;&nbsp;</span></li>
<li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">public</span></strong></span><span>&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">static</span></strong></span><span>&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">final</span></strong></span><span>&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">double</span></strong></span><span>&nbsp;B&nbsp;=&nbsp;</span><span class="number"><span style="color: #c00000;">10.00</span></span><span>; &nbsp;&nbsp;</span></li>
<li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">public</span></strong></span><span>&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">static</span></strong></span><span>&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">final</span></strong></span><span>&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">double</span></strong></span><span>&nbsp;C&nbsp;=&nbsp;</span><span class="number"><span style="color: #c00000;">20.00</span></span><span>; &nbsp;&nbsp;</span></li>
<li><span>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
<li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">public</span></strong></span><span>&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">static</span></strong></span><span>&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">double</span></strong></span><span>&nbsp;add(</span><span class="keyword"><strong><span style="color: #7f0055;">double</span></strong></span><span>&nbsp;double1,&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">double</span></strong></span><span>&nbsp;double2){ &nbsp;&nbsp;</span></li>
<li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">return</span></strong></span><span>&nbsp;double1&nbsp;+&nbsp;double2; &nbsp;&nbsp;</span></li>
<li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
<li><span>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
<li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">public</span></strong></span><span>&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">static</span></strong></span><span>&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">double</span></strong></span><span>&nbsp;Threeadd(</span><span class="keyword"><strong><span style="color: #7f0055;">double</span></strong></span><span>&nbsp;double1,&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">double</span></strong></span><span>&nbsp;double2,&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">double</span></strong></span><span>&nbsp;double3){ &nbsp;&nbsp;</span></li>
<li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">return</span></strong></span><span>&nbsp;double1&nbsp;+&nbsp;double2&nbsp;+&nbsp;double3; &nbsp;&nbsp;</span></li>
<li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
<li><span>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
<li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">public</span></strong></span><span>&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">static</span></strong></span><span>&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">void</span></strong></span><span>&nbsp;p(String&nbsp;str){ &nbsp;&nbsp;</span></li>
<li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(str); &nbsp;&nbsp;</span></li>
<li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
<li><span>}&nbsp;&nbsp;</span></li>
</ol></div>
<pre name="code" class="java">package org.yaoyuan.test;

public class Test {

	public static final int A = 10;
	public static final double B = 10.00;
	public static final double C = 20.00;
	
	public static double add(double double1, double double2){
		return double1 + double2;
	}
	
	public static double Threeadd(double double1, double double2, double double3){
		return double1 + double2 + double3;
	}
	
	public static void p(String str){
		System.out.println(str);
	}
}
</pre>
<p><br /><br />Test2静态导入了Test类里的常量和方法</p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a href="http://www.javaeye.com/topic/241322#" title="复制代码" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;"><img src="http://www.javaeye.com/images/icon_copy.gif" alt="复制代码" /></a></div>
</div>
<ol class="dp-j">
<li><span><span class="keyword"><strong><span style="color: #7f0055;">package</span></strong></span><span>&nbsp;org.yaoyuan.test; &nbsp;&nbsp;</span></span></li>
<li><span class="keyword"><strong><span style="color: #7f0055;">import</span></strong></span><span>&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">static</span></strong></span><span>&nbsp;org.yaoyuan.test.Test.A; &nbsp;&nbsp;</span></li>
<li><span class="keyword"><strong><span style="color: #7f0055;">import</span></strong></span><span>&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">static</span></strong></span><span>&nbsp;org.yaoyuan.test.Test.B; &nbsp;&nbsp;</span></li>
<li><span class="keyword"><strong><span style="color: #7f0055;">import</span></strong></span><span>&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">static</span></strong></span><span>&nbsp;org.yaoyuan.test.Test.C; &nbsp;&nbsp;</span></li>
<li><span class="keyword"><strong><span style="color: #7f0055;">import</span></strong></span><span>&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">static</span></strong></span><span>&nbsp;org.yaoyuan.test.Test.add; &nbsp;&nbsp;</span></li>
<li><span class="keyword"><strong><span style="color: #7f0055;">import</span></strong></span><span>&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">static</span></strong></span><span>&nbsp;org.yaoyuan.test.Test.Threeadd; &nbsp;&nbsp;</span></li>
<li><span class="keyword"><strong><span style="color: #7f0055;">import</span></strong></span><span>&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">static</span></strong></span><span>&nbsp;org.yaoyuan.test.Test.p; &nbsp;&nbsp;</span></li>
<li><span>&nbsp;&nbsp;</span></li>
<li><span class="keyword"><strong><span style="color: #7f0055;">public</span></strong></span><span>&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">class</span></strong></span><span>&nbsp;Test2&nbsp;{ &nbsp;&nbsp;</span></li>
<li><span>&nbsp;&nbsp;</span></li>
<li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">public</span></strong></span><span>&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">static</span></strong></span><span>&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">void</span></strong></span><span>&nbsp;main(String[]&nbsp;args){ &nbsp;&nbsp;</span></li>
<li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
<li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span class="string"><span style="color: #0000ff;">"A的值是:"</span></span><span>&nbsp;+&nbsp;A); &nbsp;&nbsp;</span></li>
<li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span class="string"><span style="color: #0000ff;">"B的值是:"</span></span><span>&nbsp;+&nbsp;B); &nbsp;&nbsp;</span></li>
<li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span class="string"><span style="color: #0000ff;">"C的值是:"</span></span><span>&nbsp;+&nbsp;C); &nbsp;&nbsp;</span></li>
<li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
<li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">double</span></strong></span><span>&nbsp;E&nbsp;=&nbsp;add(A,&nbsp;B); &nbsp;&nbsp;</span></li>
<li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">double</span></strong></span><span>&nbsp;F&nbsp;=&nbsp;Threeadd(A,&nbsp;B,&nbsp;C); &nbsp;&nbsp;</span></li>
<li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
<li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span class="string"><span style="color: #0000ff;">"E的值是:"</span></span><span>&nbsp;+&nbsp;E&nbsp;); &nbsp;&nbsp;</span></li>
<li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span class="string"><span style="color: #0000ff;">"F的值是:"</span></span><span>&nbsp;+&nbsp;F); &nbsp;&nbsp;</span></li>
<li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
<li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p(</span><span class="string"><span style="color: #0000ff;">"こんにちな,JDK新新特性---静态导入!"</span></span><span>); &nbsp;&nbsp;</span></li>
<li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
<li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
<li><span>}&nbsp;&nbsp;</span></li>
</ol></div>
<pre name="code" class="java">package org.yaoyuan.test;
import static org.yaoyuan.test.Test.A;
import static org.yaoyuan.test.Test.B;
import static org.yaoyuan.test.Test.C;
import static org.yaoyuan.test.Test.add;
import static org.yaoyuan.test.Test.Threeadd;
import static org.yaoyuan.test.Test.p;

public class Test2 {

	public static void main(String[] args){
		
		System.out.println("A的值是:" + A);
		System.out.println("B的值是:" + B);
		System.out.println("C的值是:" + C);
		
		double E = add(A, B);
		double F = Threeadd(A, B, C);
		
		System.out.println("E的值是:" + E );
		System.out.println("F的值是:" + F);
		
		p("こんにちな,JDK新新特性---静态导入!");
		
	}
}

</pre>
<p><br /><br />控制台输出信息： <br /></p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a href="http://www.javaeye.com/topic/241322#" title="复制代码" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;"><img src="http://www.javaeye.com/images/icon_copy.gif" alt="复制代码" /></a></div>
</div>
<ol class="dp-j">
<li><span><span>&nbsp;A的值是:</span><span class="number"><span style="color: #c00000;">10</span></span><span>&nbsp;&nbsp;</span></span></li>
<li><span>B的值是:</span><span class="number"><span style="color: #c00000;">10.0</span></span><span>&nbsp;&nbsp;</span></li>
<li><span>&nbsp;C的值是:</span><span class="number"><span style="color: #c00000;">20.0</span></span><span>&nbsp;&nbsp;</span></li>
<li><span>E的值是:</span><span class="number"><span style="color: #c00000;">20.0</span></span><span>&nbsp;&nbsp;</span></li>
<li><span>&nbsp;F的值是:</span><span class="number"><span style="color: #c00000;">40.0</span></span><span>&nbsp;&nbsp;</span></li>
<li><span>新特性---静态导入!&nbsp;&nbsp;</span></li>
</ol></div>
<pre name="code" class="java">A的值是:10
B的值是:10.0
C的值是:20.0
E的值是:20.0
F的值是:40.0
JDK新特性---静态导入!
</pre>
          <br/><br/>
          <span style="color:red;">
            <a href="http://chen-516888.javaeye.com/blog/242653#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">Windows7在微软WinHEC 2008上揭开神秘面纱</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 16 Sep 2008 11:34:55 +0800</pubDate>
        <link>http://chen-516888.javaeye.com/blog/242653</link>
        <guid>http://chen-516888.javaeye.com/blog/242653</guid>
      </item>
          <item>
        <title>Java Classloader and Class</title>
        <author>chen-516888</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://chen-516888.javaeye.com">chen-516888</a>&nbsp;
                    链接：<a href="http://chen-516888.javaeye.com/blog/242480" style="color:red;">http://chen-516888.javaeye.com/blog/242480</a>&nbsp;
          发表时间: 2008年09月15日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>使用JDBC时，我们都会很自然得使用下列语句： </p>
<div class="code_title">java 代码 :</div>
<div class="dp-highlighter"><ol class="dp-j">
<li class="alt"><span><span>Class.forName(</span><span class="string"><span style="color: #0000ff;">"com.mysql.jdbc.Driver"</span></span><span>); &nbsp;&nbsp;</span></span> </li>
<li><span>String&nbsp;url&nbsp;=&nbsp;</span><span class="string"><span style="color: #0000ff;">"jdbc:mysql://127.0.0.1/test?useUnicode=true&amp;characterEncoding=utf-8"</span></span><span>; &nbsp;&nbsp;</span> </li>
<li class="alt"><span>String&nbsp;user&nbsp;=&nbsp;</span><span class="string"><span style="color: #0000ff;">""</span></span><span>; &nbsp;&nbsp;</span> </li>
<li><span>String&nbsp;psw&nbsp;=&nbsp;</span><span class="string"><span style="color: #0000ff;">""</span></span><span>; &nbsp;&nbsp;</span> </li>
<li class="alt"><span>Connection&nbsp;con&nbsp;=&nbsp;DriverManager.getConnection(url,user,psw);&nbsp;&nbsp;</span> </li>
</ol></div>
<p><br />&nbsp;&nbsp;&nbsp; 为什么说很自然呢，因为无论是网上还是书本教程上得例子都是这样的，而且程序也确实正常运行了，于是大家也就心安理得的找葫芦画瓢下去了。<br />&nbsp;&nbsp;&nbsp; 一定要有这一句吗？不是的，我们完全可以用这样一句代替它：</p>
<div class="code_title">java 代码 :</div>
<div class="dp-highlighter"><ol class="dp-j">
<li class="alt"><span><span>com.mysql.jdbc.Driver&nbsp;driver&nbsp;=&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">new</span></strong></span><span>&nbsp;com.mysql.jdbc.Driver(); &nbsp;&nbsp;</span></span> </li>
<li><span class="comment"><span style="color: #008200;">//</span></span><span>&nbsp;</span> </li>
<li class="alt"><span class="comment"><span style="color: #008200;">//new&nbsp;com.mysql.jdbc.Driver(); </span></span><span>&nbsp;&nbsp;</span> </li>
<li><span>String&nbsp;url&nbsp;=&nbsp;</span><span class="string"><span style="color: #0000ff;">"jdbc:mysql://127.0.0.1/test?useUnicode=true&amp;characterEncoding=utf-8"</span></span><span>; &nbsp;&nbsp;</span> </li>
<li class="alt"><span>String&nbsp;user&nbsp;=&nbsp;</span><span class="string"><span style="color: #0000ff;">""</span></span><span>; &nbsp;&nbsp;</span> </li>
<li><span>String&nbsp;psw&nbsp;=&nbsp;</span><span class="string"><span style="color: #0000ff;">""</span></span><span>; &nbsp;&nbsp;</span> </li>
<li class="alt"><span>Connection&nbsp;con&nbsp;=&nbsp;DriverManager.getConnection(url,user,psw); &nbsp;&nbsp;</span> </li>
<li><span>&nbsp;&nbsp;</span> </li>
</ol></div>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; 大家可能都看出个大概来了，我们只需要在调用DriverManager的getConnection方法之前，保证相应的Driver类已经被加载到jvm中，并且完成了类的初始化工作就行了，而具体是怎样实现这个功能却是没有讲究的。上面两种方法都可以实现这个功能，因此程序可以正常运行。注意了，如果我们进行如下操作，程序是不能正常运行的，因为这样仅仅使Driver类被装载到jvm中，却没有进行相应的初始化工作。 </p>
<div class="code_title">java 代码 :</div>
<div class="dp-highlighter"><ol class="dp-j">
<li class="alt"><span><span>com.mysql.jdbc.Driver&nbsp;driver&nbsp;=&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">null</span></strong></span><span>; &nbsp;&nbsp;</span></span> </li>
<li><span class="comment"><span style="color: #008200;">//or： </span></span><span>&nbsp;&nbsp;</span> </li>
<li class="alt"><span><span class="hilite1"><span style="background-color: #ffffff;">ClassLoader</span></span>&nbsp;cl&nbsp;=&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">new</span></strong></span><span>&nbsp;<span class="hilite1"><span style="background-color: #ffffff;">ClassLoader</span></span>(); &nbsp;&nbsp;</span> </li>
<li><span>cl.loadClass(</span><span class="string"><span style="color: #0000ff;">"com.mysql.jdbc.Driver"</span></span><span>);&nbsp;&nbsp;</span> </li>
</ol></div>
<p><br />&nbsp;&nbsp;&nbsp;&nbsp; 我们都知道JDBC是使用Bridge模式进行设计的，DriverManager就是其中的Abstraction，java.sql.Driver是Implementor，com.mysql.jdbc.Driver是Implementor的一个具体实现（请参考GOF的Bridge模式的描述）。大家注意了，前一个Driver是一个接口，后者却是一个类，它实现了前面的Driver接口。<br />&nbsp;&nbsp;&nbsp;&nbsp; Bridge模式中，Abstraction（DriverManager）是要拥有一个Implementor（Driver）的引用的，但是我们在使用过程中，并没有将Driver对象注册到DriverManager中去啊，这是怎么回事呢？jdk文档对Driver的描述中有这么一句：<br />&nbsp;&nbsp;&nbsp;&nbsp; <strong>When a Driver class is loaded, it should create an instance of itself and register it with the DriverManager <br /></strong>哦，原来是com.mysql.jdbc.Driver在装载完后自动帮我们完成了这一步骤。源代码是这样的： </p>
<div class="code_title">java 代码 :</div>
<div class="dp-highlighter"><ol class="dp-j">
<li class="alt"><span><span class="keyword"><strong><span style="color: #7f0055;">package</span></strong></span><span>&nbsp;com.mysql.jdbc &nbsp;&nbsp;</span></span> </li>
<li><span>&nbsp;&nbsp;</span> </li>
<li class="alt"><span class="keyword"><strong><span style="color: #7f0055;">public</span></strong></span><span>&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">class</span></strong></span><span>&nbsp;Driver&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">extends</span></strong></span><span>&nbsp;NonRegisteringDriver&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">implements</span></strong></span><span>&nbsp;java.sql.Driver&nbsp;{ &nbsp;&nbsp;</span> </li>
<li><span>&nbsp;</span><span class="comment"><span style="color: #008200;">//&nbsp;~&nbsp;Static&nbsp;fields/initializers </span></span><span>&nbsp;&nbsp;</span> </li>
<li class="alt"><span>&nbsp;</span><span class="comment"><span style="color: #008200;">//&nbsp;---------------------------------------------&nbsp;// </span></span><span>&nbsp;&nbsp;</span> </li>
<li><span>&nbsp;</span><span class="comment"><span style="color: #008200;">//&nbsp;Register&nbsp;ourselves&nbsp;with&nbsp;the&nbsp;DriverManager </span></span><span>&nbsp;&nbsp;</span> </li>
<li class="alt"><span>&nbsp;</span><span class="comment"><span style="color: #008200;">// </span></span><span>&nbsp;&nbsp;</span> </li>
<li><span>&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">static</span></strong></span><span>&nbsp;{ &nbsp;&nbsp;</span> </li>
<li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;t&nbsp;ry&nbsp;{ &nbsp;&nbsp;</span> </li>
<li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;java.sql.DriverManager.registerDriver(</span><span class="keyword"><strong><span style="color: #7f0055;">new</span></strong></span><span>&nbsp;Driver()); &nbsp;&nbsp;</span> </li>
<li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">catch</span></strong></span><span>&nbsp;(SQLException&nbsp;E)&nbsp;{ &nbsp;&nbsp;</span> </li>
<li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">throw</span></strong></span><span>&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">new</span></strong></span><span>&nbsp;RuntimeException(</span><span class="string"><span style="color: #0000ff;">"Can't&nbsp;register&nbsp;driver!"</span></span><span>); &nbsp;&nbsp;</span> </li>
<li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span> </li>
<li><span>&nbsp;&nbsp;} &nbsp;&nbsp;</span> </li>
<li class="alt"><span class="comment"><span style="color: #008200;">//&nbsp;~&nbsp;Constructors </span></span><span>&nbsp;&nbsp;</span> </li>
<li><span>&nbsp;</span><span class="comment"><span style="color: #008200;">//&nbsp;----------------------------------------------------------- </span></span><span>&nbsp;&nbsp;</span> </li>
<li class="alt"><span class="comment"><span style="color: #008200;">/** </span></span>&nbsp; </li>
<li><span><span class="comment"><span style="color: #008200;">&nbsp;&nbsp;*&nbsp;Construct&nbsp;a&nbsp;new&nbsp;driver&nbsp;and&nbsp;register&nbsp;it&nbsp;with&nbsp;DriverManager </span></span>&nbsp;</span> </li>
<li class="alt"><span><span class="comment"><span style="color: #008200;">&nbsp;&nbsp;*&nbsp; </span></span>&nbsp;</span> </li>
<li><span><span class="comment"><span style="color: #008200;">&nbsp;&nbsp;*&nbsp;@throws&nbsp;SQLException </span></span>&nbsp;</span> </li>
<li class="alt"><span><span class="comment"><span style="color: #008200;">&nbsp;&nbsp;*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;a&nbsp;database&nbsp;error&nbsp;occurs. </span></span>&nbsp;</span> </li>
<li><span><span class="comment"><span style="color: #008200;">&nbsp;&nbsp;*/</span></span><span>&nbsp;&nbsp;</span></span> </li>
<li class="alt"><span>&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">public</span></strong></span><span>&nbsp;Driver()&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">throws</span></strong></span><span>&nbsp;SQLException&nbsp;{ &nbsp;&nbsp;</span> </li>
<li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment"><span style="color: #008200;">//&nbsp;Required&nbsp;for&nbsp;Class.forName().newInstance() </span></span><span>&nbsp;&nbsp;</span> </li>
<li class="alt"><span>&nbsp;} &nbsp;&nbsp;</span> </li>
<li><span>}&nbsp;&nbsp;</span> </li>
</ol></div>
<p>Class.forName和 <span class="hilite1"><span style="background-color: #ffffff;">ClassLoader</span></span>.loadClass是两码事，一个实例化类，一个加载类</p>
<p>这里<span class="hilite1"><span style="background-color: #ffffff;">ClassLoader</span></span>为什么不行，是类加载器的机制决定的 <a href="http://www.javaeye.com/topic/25053"><span style="color: #108ac6;">www.javaeye.com/topic/25053<strong></strong></span></a></p>
<p><strong>static块在什么时候执行?</strong> <br />1)当调用forName(String)载入class时执行,如果调用<span style="background-color: #ffffff;"><span class="hilite1"><span style="background-color: #ffffff;">ClassLoader</span></span>.</span>loadClass并不会执行.forName(String,false,<span class="hilite1"><span style="background-color: #ffffff;">ClassLoader</span></span>)时也不会执行. <br />2)如果载入Class时没有执行static块则在第一次实例化时执行.比如new ,Class.newInstance()操作 <br />3)static块仅执行一次</p>
<p>&nbsp;</p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://chen-516888.javaeye.com/blog/242480#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">Windows7在微软WinHEC 2008上揭开神秘面纱</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 15 Sep 2008 15:02:56 +0800</pubDate>
        <link>http://chen-516888.javaeye.com/blog/242480</link>
        <guid>http://chen-516888.javaeye.com/blog/242480</guid>
      </item>
          <item>
        <title>Java NIO</title>
        <author>chen-516888</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://chen-516888.javaeye.com">chen-516888</a>&nbsp;
                    链接：<a href="http://chen-516888.javaeye.com/blog/242478" style="color:red;">http://chen-516888.javaeye.com/blog/242478</a>&nbsp;
          发表时间: 2008年09月15日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p class="MsoNormal" style="margin: 0in 0in 0pt;"><span style="font-size: small;"><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">&nbsp;&nbsp; <strong>自从</strong></span><strong><span style="font-family: Times New Roman;">J2SE 1.4</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">版本以来，</span><span style="font-family: Times New Roman;">JDK</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">发布了全新的</span><span style="font-family: Times New Roman;">I/O</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">类库，简称</span><span style="font-family: Times New Roman;">NIO</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">，其不但引入了全新的高效的</span><span style="font-family: Times New Roman;">I/O</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">机制，同时，也引入了多路复用的异步模式。</span><span style="font-family: Times New Roman;">NIO</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">的包中主要包含了这样几种抽象数据类型：</span></strong></span></p>
<p class="MsoNormal" style="margin: 0in 0in 0pt;"><span style="font-size: small; font-family: Times New Roman;"><strong>&nbsp;</strong></span></p>
<p class="MsoNormal" style="margin: 0in 0in 0pt; mso-list: l2 level1 lfo1; tab-stops: list .5in;"><strong><span style="font-size: small;"><span style="font-family: Times New Roman;">&nbsp;&nbsp; 1.Buffer</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">：包含数据且用于读写的线形表结构。其中还提供了一个特殊类用于内存映射文件的</span><span style="font-family: Times New Roman;">I/O</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">操作。</span> </span></strong></p>
<p class="MsoNormal" style="margin: 0in 0in 0pt; mso-list: l2 level1 lfo1; tab-stops: list .5in;"><strong><span style="font-size: small;"><span style="font-family: Times New Roman;">&nbsp;&nbsp; 2.Charset</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">：它提供</span><span style="font-family: Times New Roman;">Unicode</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">字符串影射到字节序列以及逆映射的操作。</span> </span></strong></p>
<p class="MsoNormal" style="margin: 0in 0in 0pt; mso-list: l2 level1 lfo1; tab-stops: list .5in;"><strong><span style="font-size: small;"><span style="font-family: Times New Roman;">&nbsp;&nbsp; 3.Channels</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">：包含</span><span style="font-family: Times New Roman;">socket</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">，</span><span style="font-family: Times New Roman;">file</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">和</span><span style="font-family: Times New Roman;">pipe</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">三种管道，都是全双工的通道。</span> </span></strong></p>
<p class="MsoNormal" style="margin: 0in 0in 0pt; mso-list: l2 level1 lfo1; tab-stops: list .5in;"><span style="font-size: small;"><strong><span style="font-family: Times New Roman;">&nbsp;&nbsp; 4.Selector</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">：多个异步</span><span style="font-family: Times New Roman;">I/O</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">操作集中到一个或多个线程中（可以被看成是</span><span style="font-family: Times New Roman;">Unix</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">中</span><span style="font-family: Times New Roman;">select()</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman';">函数的面向对象版本）。</span></strong> </span></p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://chen-516888.javaeye.com/blog/242478#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">Windows7在微软WinHEC 2008上揭开神秘面纱</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 15 Sep 2008 14:53:35 +0800</pubDate>
        <link>http://chen-516888.javaeye.com/blog/242478</link>
        <guid>http://chen-516888.javaeye.com/blog/242478</guid>
      </item>
          <item>
        <title>C++中引用和指针</title>
        <author>chen-516888</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://chen-516888.javaeye.com">chen-516888</a>&nbsp;
                    链接：<a href="http://chen-516888.javaeye.com/blog/241438" style="color:red;">http://chen-516888.javaeye.com/blog/241438</a>&nbsp;
          发表时间: 2008年09月13日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>C++中引用和指针的区别:</p>
<p><br />&nbsp;★ 相同点：<br />&nbsp;1. 都是地址的概念；<br />&nbsp; &nbsp;&nbsp; 指针指向一块内存，它的内容是所指内存的地址；引用是某块内存的别名。<br /><br />&nbsp;★ 区别：<br />&nbsp;1. 指针是一个实体，而引用仅是个别名；<br />&nbsp;2. 引用使用时无需解引用(*)，指针需要解引用；<br />&nbsp;3. 引用只能在定义时被初始化一次，之后不可变；指针可变；<br />&nbsp;&nbsp;&nbsp; &nbsp;引用&ldquo;从一而终&rdquo; ^_^<br />&nbsp;4. 引用没有 const，指针有 const，const 的指针不可变；<br />&nbsp;5. 引用不能为空，指针可以为空；<br />&nbsp;6. &ldquo;sizeof 引用&rdquo;得到的是所指向的变量(对象)的大小，而&ldquo;sizeof 指针&rdquo;得到的是指针本身(所指向的变量或对象的&nbsp;&nbsp; </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 地址)的大小；<br />&nbsp; &nbsp;&nbsp; typeid(T) == typeid(T&amp;) 恒为真，sizeof(T) == sizeof(T&amp;) 恒为真，<br />&nbsp; &nbsp;&nbsp; 但是当引用作为成员时，其占用空间与指针相同（没找到标准的规定）。<br />&nbsp;7 . 指针和引用的自增(++)运算意义不一样；<br /><br />&nbsp;★ 联系<br />&nbsp;1. 引用在语言内部用指针实现（如何实现？）。<br />&nbsp;2. 对一般应用而言，把引用理解为指针，不会犯严重语义错误。引用是操作受限了的指针（仅容许取内容操作）。</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://chen-516888.javaeye.com/blog/241438#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">Windows7在微软WinHEC 2008上揭开神秘面纱</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sat, 13 Sep 2008 13:06:55 +0800</pubDate>
        <link>http://chen-516888.javaeye.com/blog/241438</link>
        <guid>http://chen-516888.javaeye.com/blog/241438</guid>
      </item>
          <item>
        <title>转载文章</title>
        <author>chen-516888</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://chen-516888.javaeye.com">chen-516888</a>&nbsp;
                    链接：<a href="http://chen-516888.javaeye.com/blog/237118" style="color:red;">http://chen-516888.javaeye.com/blog/237118</a>&nbsp;
          发表时间: 2008年09月04日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <div class="blog_content">
<p>离职了。职业目标却在心里更加清晰起来，来北京两个月了，不知道自己收获了多少。关于技术和行业吗，还有自己真正意义上的进入社会。。。</p>
<p>离职前，老总陈正给了许多建议，既有前瞻性又告诫。老总的水平非常高。无论从学识谈吐还是礼仪上都是自己前方的一座巍巍之山。长远难忘，陈正，超图应用软件事业部实施总监。</p>
<p>老总是湖南人，有天生的大将风范，而且生性乐观。猪皮炒黄豆，很湖南的菜。老总是纯技术出身，刚开始进入超图的公司时候，公司人很少，那时用VB做开发，后来转到C#上做开发；再以后陈总做了技术架构方面的工作，负责技术选型；最后陈总成为了实施总监，既负责技术选型，又通过经验控制技术选型，规避项目风险。</p>
<p>现在的陈总是由技术出身的复合型人才。</p>
<p>其实一个Coder的成长之路有两条，一是向架构方向上转，还有一个是向商务方向转。发现自己更多的兴趣是在架构方向，而更多的劣势在商务应用上，无论是待人接物还是别有用心上，自己都差了很多。</p>
<p>自己对新的技术很感兴趣，而且希望能去一些产品方面的架构工作，现在的我终于弄清楚了自己的方向。做架构需要积累经验，需要了解新的技术，需要从技术角度规避项目风险。这都是自己需要努力的方向。</p>
<p>&nbsp;</p>
<p>下面是陈总给的一些建议。因为自己是个笨人，先记录下来，以防忘记。待以后慢慢细咂。</p>
<p><span style="color: #3366ff;">1.专注_沉淀_成长_收获</span></p>
<p>羊一处吃一根草，到处吃草，最终没有长成牛。牛吃一片草，非常专注。</p>
<p>老总以同学和自己的成长历程作比。老总是1999年到北京的。第一份工资800，同学的第一份工资1500，1年后老总的工资涨到1500，而他的同学经过几次跳槽后到了1800，第二年的时候老总的工资略提，而他的同学再次跳槽，工资也长到了4000.第三年的时候老总工资涨到了3000，而他的同学的工资涨到了7000，开始进入金融领域，做了二年后，居然跳到了GIS领域，而工资则在7000-8000见碰到了瓶颈。老总第四年的时候工资开始和同学持平，并在第五年开始担任总经理，在收入和地位上与他的同学相比也远非他的同学能比。现在老总在奥运村附近买了房，有自己的车，他在北京已经做出了一番了不起的事业。而他的同学只是在回龙观(五环)附近贷款买了房。<span style="color: #ff0000;"><span>8年的时间，差距显而易见。</span><span>专注于一个公司，专注于一个领域。</span></span></p>
<p>&nbsp;</p>
<p><span style="color: #3366ff;">2.事业为重_扛压是关键</span></p>
<p>来北京就不要给自己打退堂鼓，来就是做一番事业的。来北京意味着吃苦，如果只是来混日子，确实罔度时间。陈总如斯对我说，当我说出几年后要回青岛的话后。我也不明白自己无论什么事情都喜欢给子自己留后路，也许是因为自己太过胆小，承压力和胆识永远没有超人之处。<span style="color: #ff0000;">扛压是关键，在IT行业里只有能承压的人才能获得晋升机会。</span><span style="color: #000000;">老实的说一句，目前我是不能承压的。自己习惯了逃跑，习惯了在别人的伞里过安逸的生活。这也是自己离职的根本原因吧。我是不能承压的，而老总是洞若观火的。记得面试时老总说给我一个产品，能不能用Java实现C#已经实现的东西，我回答说能；然后老总又问，能不能在项目迁移的同时对项目做一些升级和创新，结果我又说能。而实际上，我没有实现我的话，因为在还没有尝试之前，我已经退回了自己划定的一个安全圈。愧对老总的伯乐之恩德。</span></p>
<p><span style="color: #808080;">一个人只有能承压，才能收获。如果不能立时收获，付出的努力肯定会转换为其他的东西，比如晋升的筹码等。</span></p>
<p>&nbsp;</p>
<p><span style="color: #808080;"><span style="color: #3366ff;">3.执着_主见_坚持<br /></span><span style="color: #000000;">做事是需要主见的。听风即是雨，永远没有方向。对一个自己兴趣所在的东西，执着是必须的素质。坚持的是信念，判断。收获的是能力和回报。坚持的是孤独。方法是忍耐。</span></span></p>
<p>&nbsp;</p>
<p><span style="color: #3366ff;">4能力背后_成长空间_机遇</span></p>
<p><span style="color: #000000;">目前的岗位是缺人的，这不单纯是一个项目的问题，牵扯到公司的产品布局和战略远景。能在1年内把项目从C#上迁移到Java上，手底下就会有3-4人；第二年如果能对项目进行升级和优化，有可能手下就会升级到10人左右。能管10人左右就不再单纯是一个Coder了。当然所有的一切美好远景是你能承受住压力，做出成绩，付注了大量的热情。</span></p>
<p>&nbsp;</p>
<p><span style="color: #3366ff;">5红海战略与蓝海战略</span></p>
<p>&nbsp;红海是血腥的，无论是金融还是OA等传统软件行业领域。而Gis作为一个新起步的行业，无疑是身处蓝海的。人均产值能到100万元，好恐怖的数字。而普通的软件行业，只有人均30万的产值。</p>
<p>&nbsp;</p>
<p>闲话花絮：</p>
<p>期间曾说起想能做金融软件方面的工作。老总简单问了几个问题，凯恩斯是谁？斯伯恩思是谁？</p>
<p>我都不知道。</p>
<p>还有就是问到兴趣所在时，从兄弟的角度，陈总给出的建议是做什么都别做操盘手，手里握着几两银子，着实没意思，如果是做有贡献的理论分析，还是很值得鼓励的。</p>
<p>一个人的自身价值有限，身后的团队价值无限，有潜力的团队战斗素质高超，与团队一起成长才能有大的收获，无论是技术，还是收益。</p>
</div>
          <br/><br/>
          <span style="color:red;">
            <a href="http://chen-516888.javaeye.com/blog/237118#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">Windows7在微软WinHEC 2008上揭开神秘面纱</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 04 Sep 2008 17:54:00 +0800</pubDate>
        <link>http://chen-516888.javaeye.com/blog/237118</link>
        <guid>http://chen-516888.javaeye.com/blog/237118</guid>
      </item>
          <item>
        <title>Open Session in View and Transaction...</title>
        <author>chen-516888</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://chen-516888.javaeye.com">chen-516888</a>&nbsp;
                    链接：<a href="http://chen-516888.javaeye.com/blog/231519" style="color:red;">http://chen-516888.javaeye.com/blog/231519</a>&nbsp;
          发表时间: 2008年08月22日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>在没有使用Spring提供的Open Session In View情况下，因需要在service(or Dao)层里把session关闭，所以lazy loading 为true的话，要在应用层内把关系集合都初始化，如 company.getEmployees()，否则Hibernate抛session already closed Exception; Open Session In View提供了一种简便的方法，较好地解决了lazy loading问题. <br />它有两种配置方式OpenSessionInViewInterceptor和OpenSessionInViewFilter(具体参看SpringSide)，功能相同，只是一个在web.xml配置，另一个在application.xml配置而已。 <br />Open Session In View在request把session绑定到当前thread期间一直保持hibernate session在open状态，使session在request的整个期间都可以使用，如在View层里PO也可以lazy loading数据，如 ${ company.employees }。当View 层逻辑完成后，才会通过Filter的doFilter方法或Interceptor的postHandle方法自动关闭session。 <br />OpenSessionInViewInterceptor配置</p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Xml代码 <a href="http://www.javaeye.com/topic/186068" title="复制代码" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;"><img src="http://www.javaeye.com/images/icon_copy.gif" alt="复制代码" /></a></div>
</div>
<ol class="dp-xml">
<li><span><span>&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li>
<li><strong><span style="color: #006699;"><span class="tag">&lt;</span><span class="tag-name">beans</span><span class="tag">&gt;</span></span></strong><span>&nbsp; &nbsp;&nbsp;</span></li>
<li><strong><span style="color: #006699;"><span class="tag">&lt;</span><span class="tag-name">bean</span></span></strong><span>&nbsp;</span><span class="attribute"><span style="color: #ff0000;">name</span></span><span>=</span><span class="attribute-value"><span style="color: #0000ff;">"openSessionInViewInterceptor"</span></span><span>&nbsp;</span><span class="attribute"><span style="color: #ff0000;">class</span></span><span>=</span><span class="attribute-value"><span style="color: #0000ff;">"org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor"</span></span><span class="tag"><strong><span style="color: #006699;">&gt;</span></strong></span><span>&nbsp; &nbsp;&nbsp;</span></li>
<li><strong><span style="color: #006699;"><span class="tag">&lt;</span><span class="tag-name">property</span></span></strong><span>&nbsp;</span><span class="attribute"><span style="color: #ff0000;">name</span></span><span>=</span><span class="attribute-value"><span style="color: #0000ff;">"sessionFactory"</span></span><span class="tag"><strong><span style="color: #006699;">&gt;</span></strong></span><span>&nbsp; &nbsp;&nbsp;</span></li>
<li><strong><span style="color: #006699;"><span class="tag">&lt;</span><span class="tag-name">ref</span></span></strong><span>&nbsp;</span><span class="attribute"><span style="color: #ff0000;">bean</span></span><span>=</span><span class="attribute-value"><span style="color: #0000ff;">"sessionFactory"</span></span><span class="tag"><strong><span style="color: #006699;">/&gt;</span></strong></span><span>&nbsp; &nbsp;&nbsp;</span></li>
<li><strong><span style="color: #006699;"><span class="tag">&lt;/</span><span class="tag-name">property</span><span class="tag">&gt;</span></span></strong><span>&nbsp; &nbsp;&nbsp;</span></li>
<li><strong><span style="color: #006699;"><span class="tag">&lt;/</span><span class="tag-name">bean</span><span class="tag">&gt;</span></span></strong><span>&nbsp; &nbsp;&nbsp;</span></li>
<li><strong><span style="color: #006699;"><span class="tag">&lt;</span><span class="tag-name">bean</span></span></strong><span>&nbsp;</span><span class="attribute"><span style="color: #ff0000;">id</span></span><span>=</span><span class="attribute-value"><span style="color: #0000ff;">"urlMapping"</span></span><span>&nbsp;</span><span class="attribute"><span style="color: #ff0000;">class</span></span><span>=</span><span class="attribute-value"><span style="color: #0000ff;">"org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"</span></span><span class="tag"><strong><span style="color: #006699;">&gt;</span></strong></span><span>&nbsp; &nbsp;&nbsp;</span></li>
<li><strong><span style="color: #006699;"><span class="tag">&lt;</span><span class="tag-name">property</span></span></strong><span>&nbsp;</span><span class="attribute"><span style="color: #ff0000;">name</span></span><span>=</span><span class="attribute-value"><span style="color: #0000ff;">"interceptors"</span></span><span class="tag"><strong><span style="color: #006699;">&gt;</span></strong></span><span>&nbsp; &nbsp;&nbsp;</span></li>
<li><strong><span style="color: #006699;"><span class="tag">&lt;</span><span class="tag-name">list</span><span class="tag">&gt;</span></span></strong><span>&nbsp; &nbsp;&nbsp;</span></li>
<li><strong><span style="color: #006699;"><span class="tag">&lt;</span><span class="tag-name">ref</span></span></strong><span>&nbsp;</span><span class="attribute"><span style="color: #ff0000;">bean</span></span><span>=</span><span class="attribute-value"><span style="color: #0000ff;">"openSessionInViewInterceptor"</span></span><span class="tag"><strong><span style="color: #006699;">/&gt;</span></strong></span><span>&nbsp; &nbsp;&nbsp;</span></li>
<li><strong><span style="color: #006699;"><span class="tag">&lt;/</span><span class="tag-name">list</span><span class="tag">&gt;</span></span></strong><span>&nbsp; &nbsp;&nbsp;</span></li>
<li><strong><span style="color: #006699;"><span class="tag">&lt;/</span><span class="tag-name">property</span><span class="tag">&gt;</span></span></strong><span>&nbsp; &nbsp;&nbsp;</span></li>
<li><strong><span style="color: #006699;"><span class="tag">&lt;</span><span class="tag-name">property</span></span></strong><span>&nbsp;</span><span class="attribute"><span style="color: #ff0000;">name</span></span><span>=</span><span class="attribute-value"><span style="color: #0000ff;">"mappings"</span></span><span class="tag"><strong><span style="color: #006699;">&gt;</span></strong></span><span>&nbsp; &nbsp;&nbsp;</span></li>
<li><span>...&nbsp; &nbsp;&nbsp;</span></li>
<li><strong><span style="color: #006699;"><span class="tag">&lt;/</span><span class="tag-name">property</span><span class="tag">&gt;</span></span></strong><span>&nbsp; &nbsp;&nbsp;</span></li>
<li><strong><span style="color: #006699;"><span class="tag">&lt;/</span><span class="tag-name">bean</span><span class="tag">&gt;</span></span></strong><span>&nbsp;...&nbsp;</span><strong><span style="color: #006699;"><span class="tag">&lt;/</span><span class="tag-name">beans</span><span class="tag">&gt;</span></span></strong><span>&nbsp;&nbsp;&nbsp;</span></li>
</ol></div>
<pre name="code" class="xml">  
&lt;beans&gt; 
&lt;bean name="openSessionInViewInterceptor" class="org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor"&gt; 
&lt;property name="sessionFactory"&gt; 
&lt;ref bean="sessionFactory"/&gt; 
&lt;/property&gt; 
&lt;/bean&gt; 
&lt;bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"&gt; 
&lt;property name="interceptors"&gt; 
&lt;list&gt; 
&lt;ref bean="openSessionInViewInterceptor"/&gt; 
&lt;/list&gt; 
&lt;/property&gt; 
&lt;property name="mappings"&gt; 
... 
&lt;/property&gt; 
&lt;/bean&gt; ... &lt;/beans&gt; 
</pre>
<p><br />OpenSessionInViewFilter配置</p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Xml代码 <a href="http://www.javaeye.com/topic/186068" title="复制代码" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;"><img src="http://www.javaeye.com/images/icon_copy.gif" alt="复制代码" /></a></div>
</div>
<ol class="dp-xml">
<li><span><span>&nbsp; &nbsp;&nbsp;</span></span></li>
<li><strong><span style="color: #006699;"><span class="tag">&lt;</span><span class="tag-name">web-app</span><span class="tag">&gt;</span></span></strong><span>&nbsp; &nbsp;&nbsp;</span></li>
<li><span>...&nbsp; &nbsp;&nbsp;</span></li>
<li><strong><span style="color: #006699;"><span class="tag">&lt;</span><span class="tag-name">filter</span><span class="tag">&gt;</span></span></strong><span>&nbsp; &nbsp;&nbsp;</span></li>
<li><strong><span style="color: #006699;"><span class="tag">&lt;</span><span class="tag-name">filter-name</span><span class="tag">&gt;</span></span></strong><span>hibernateFilter</span><strong><span style="color: #006699;"><span class="tag">&lt;/</span><span class="tag-name">filter-name</span><span class="tag">&gt;</span></span></strong><span>&nbsp; &nbsp;&nbsp;</span></li>
<li><strong><span style="color: #006699;"><span class="tag">&lt;</span><span class="tag-name">filter-class</span><span class="tag">&gt;</span></span></strong><span>&nbsp;org.springframework.orm.hibernate3.support.OpenSessionInViewFilter&nbsp;</span><strong><span style="color: #006699;"><span class="tag">&lt;/</span><span class="tag-name">filter-class</span><span class="tag">&gt;</span></span></strong><span>&nbsp; &nbsp;&nbsp;</span></li>
<li><span class="comments"><span style="color: #008200;">&lt;!--&nbsp;singleSession默认为true,若设为false则等于没用OpenSessionInView&nbsp;--&gt;</span></span><span>&nbsp; &nbsp;&nbsp;</span></li>
<li><strong><span style="color: #006699;"><span class="tag">&lt;</span><span class="tag-name">init-param</span><span class="tag">&gt;</span></span></strong><span>&nbsp; &nbsp;&nbsp;</span></li>
<li><strong><span style="color: #006699;"><span class="tag">&lt;</span><span class="tag-name">param-name</span><span class="tag">&gt;</span></span></strong><span>singleSession</span><strong><span style="color: #006699;"><span class="tag">&lt;/</span><span class="tag-name">param-name</span><span class="tag">&gt;</span></span></strong><span>&nbsp; &nbsp;&nbsp;</span></li>
<li><strong><span style="color: #006699;"><span class="tag">&lt;</span><span class="tag-name">param-value</span><span class="tag">&gt;</span></span></strong><span>true</span><strong><span style="color: #006699;"><span class="tag">&lt;/</span><span class="tag-name">param-value</span><span class="tag">&gt;</span></span></strong><span>&nbsp; &nbsp;&nbsp;</span></li>
<li><strong><span style="color: #006699;"><span class="tag">&lt;/</span><span class="tag-name">init-param</span><span class="tag">&gt;</span></span></strong><span>&nbsp; &nbsp;&nbsp;</span></li>
<li><strong><span style="color: #006699;"><span class="tag">&lt;/</span><span class="tag-name">filter</span><span class="tag">&gt;</span></span></strong><span>&nbsp;...&nbsp;</span><strong><span style="color: #006699;"><span class="tag">&lt;</span><span class="tag-name">filter-mapping</span><span class="tag">&gt;</span></span></strong><span>&nbsp; &nbsp;&nbsp;</span></li>
<li><strong><span style="color: #006699;"><span class="tag">&lt;</span><span class="tag-name">filter-name</span><span class="tag">&gt;</span></span></strong><span>hibernateFilter</span><strong><span style="color: #006699;"><span class="tag">&lt;/</span><span class="tag-name">filter-name</span><span class="tag">&gt;</span></span></strong><span>&nbsp; &nbsp;&nbsp;</span></li>
<li><strong><span style="color: #006699;"><span class="tag">&lt;</span><span class="tag-name">url-pattern</span><span class="tag">&gt;</span></span></strong><span>*.do</span><strong><span style="color: #006699;"><span class="tag">&lt;/</span><span class="tag-name">url-pattern</span><span class="tag">&gt;</span></span></strong><span>&nbsp; &nbsp;&nbsp;</span></li>
<li><strong><span style="color: #006699;"><span class="tag">&lt;/</span><span class="tag-name">filter-mapping</span><span class="tag">&gt;</span></span></strong><span>&nbsp;...&nbsp;</span><strong><span style="color: #006699;"><span class="tag">&lt;/</span><span class="tag-name">web-app</span><span class="tag">&gt;</span></span></strong><span>&nbsp;&nbsp;&nbsp;</span></li>
</ol></div>
<pre name="code" class="xml"> 
&lt;web-app&gt; 
... 
&lt;filter&gt; 
&lt;filter-name&gt;hibernateFilter&lt;/filter-name&gt; 
&lt;filter-class&gt; org.springframework.orm.hibernate3.support.OpenSessionInViewFilter &lt;/filter-class&gt; 
&lt;!-- singleSession默认为true,若设为false则等于没用OpenSessionInView --&gt; 
&lt;init-param&gt; 
&lt;param-name&gt;singleSession&lt;/param-name&gt; 
&lt;param-value&gt;true&lt;/param-value&gt; 
&lt;/init-param&gt; 
&lt;/filter&gt; ... &lt;filter-mapping&gt; 
&lt;filter-name&gt;hibernateFilter&lt;/filter-name&gt; 
&lt;url-pattern&gt;*.do&lt;/url-pattern&gt; 
&lt;/filter-mapping&gt; ... &lt;/web-app&gt; 
</pre>
<p><br />很多人在使用OpenSessionInView过程中提及一个错误： <br />org.springframework.dao.InvalidDataAccessApiUsageException: Write operations are not allowed in read-only mode (FlushMode.NEVER) - turn your Session into FlushMode.AUTO or remove 'readOnly' marker from transaction definition <br />看看OpenSessionInViewFilter里的几个方法</p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a href="http://www.javaeye.com/topic/186068" title="复制代码" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;"><img src="http://www.javaeye.com/images/icon_copy.gif" alt="复制代码" /></a></div>
</div>
<ol class="dp-j">
<li><span><span>&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li>
<li><span>&nbsp;&nbsp;</span></li>
<li><span class="keyword"><strong><span style="color: #7f0055;">protected</span></strong></span><span>&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">void</span></strong></span><span>&nbsp;doFilterInternal(HttpServletRequest&nbsp;request,&nbsp; &nbsp;&nbsp;</span></li>
<li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HttpServletResponse&nbsp;response, &nbsp;&nbsp;</span></li>
<li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FilterChain&nbsp;filterChain)&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">throws</span></strong></span><span>&nbsp;ServletException,&nbsp;IOException&nbsp;{　 &nbsp;&nbsp;</span></li>
<li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SessionFactory&nbsp;sessionFactory&nbsp;=&nbsp;lookupSessionFactory();　 &nbsp;&nbsp;</span></li>
<li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.debug(</span><span class="string"><span style="color: #0000ff;">"Opening&nbsp;Hibernate&nbsp;Session&nbsp;in&nbsp;OpenSessionInViewFilter"</span></span><span>);　 &nbsp;&nbsp;</span></li>
<li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Session&nbsp;session&nbsp;=&nbsp;getSession(sessionFactory);　 &nbsp;&nbsp;</span></li>
<li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TransactionSynchronizationManager.bindResource(　　 &nbsp;&nbsp;</span></li>
<li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sessionFactory,&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">new</span></strong></span><span>&nbsp;SessionHolder(session));　 &nbsp;&nbsp;</span></li>
<li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword"><strong><span style="color: #7f0055;">try</span></strong></span><span>&nbsp;{　　 &nbsp;&nbsp;</span></li>
<li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;filterChain.doFilter(request,&nbsp;response);　 &nbsp;&nbsp;</span></li>
<li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}　 &nbsp;&nbsp;</span></li>
<li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&