﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>IT博客-Favor Soup | 反胃书屋-随笔分类-Java Related</title><link>http://www.cnitblog.com/dickznew/category/4132.html</link><description>斯是陋室，惟吾德馨。</description><language>zh-cn</language><lastBuildDate>Wed, 28 Sep 2011 16:25:19 GMT</lastBuildDate><pubDate>Wed, 28 Sep 2011 16:25:19 GMT</pubDate><ttl>60</ttl><item><title>当Return遇到Finally续集（ZZ）</title><link>http://www.cnitblog.com/dickznew/archive/2010/05/11/65948.html</link><dc:creator>D主</dc:creator><author>D主</author><pubDate>Tue, 11 May 2010 10:38:00 GMT</pubDate><guid>http://www.cnitblog.com/dickznew/archive/2010/05/11/65948.html</guid><wfw:comment>http://www.cnitblog.com/dickznew/comments/65948.html</wfw:comment><comments>http://www.cnitblog.com/dickznew/archive/2010/05/11/65948.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/dickznew/comments/commentRss/65948.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/dickznew/services/trackbacks/65948.html</trackback:ping><description><![CDATA[<p>finally 区域内的代码块在 return 之前被执行 <br>
由于 Java 程序中，所有的对象都是在堆上（ Heap
）分配存储空间的，这些空间完全由垃圾回收机制来对它们进行管理。因此，从这一点可以分析得出一个推论： Java 中的异常处理模型的实现，其实要比
C++ 异常处理模型简单得多。例如，它首先不需要像 C++
异常处理模型中那样，必须要跟踪栈上的每一个&#8220;对象&#8221;的构造和析构过程（只有跟踪并掌握了这些信息，发生异常时， C++
系统它才会知道当前应该析构销毁哪些对象呀！），这是因为 Java 程序中，栈上是绝对没有&#8220;对象&#8221;的（实际只是对堆上对象的引用）。另外，还有
Java 语言中的异常对象的传递也更为简单和容易了，它只需传递一个引用指针而已，而完全不用考虑异常对象的构造、复制和销毁过程。 </p>
<p>当然， Java 异常处理模型较 C++ 异常处理模型复杂的地方是，它引入了 finally 机制（主要用于数据库连接的关闭、
Socket 关闭、文件流的关闭等）。其实，我们也知道 finally 语法最早是在微软的 SEH
所设计出的一种机制，虽然它功能很强大，但是实现起来却并不是很难，从表象上来理解：当代码在执行过程中，遭遇到 return 和 goto
等类似的语句所引发作用域（代码执行流）转移时，便会产生一个局部展开（ Local Unwinding ）；而由于异常而导致的 finally
块被执行的过程，往往被称为全局展开（ Global Unwinding ）。由于展开（ Unwinding ）而导致的 finally
块被执行的过程，非常类似于一个子函数（或子过程）被调用的过程。例如，当在 try 块中最后一条语句 return
被执行到的时候，一个展开操作便发生了，可以把展开操作想象成，是编译器在 return 语句之前插入了一些代码（这些代码完成对 finally
块的调用），因此可以得出结论： finally 区域内的代码块，肯定是在 return 之前被执行。 </p>
<p>但是，请特别注意， finally 块区域中的代码虽然在 return 语句之前被执行，但是 finally 块区域中的代码是不能够通过重新赋值的方式来改变 return 语句的返回值。请看如下的示例代码： </p>
<p>import java.io.*; </p>
<p>public class Trans </p>
<p>{ </p>
<p>public static void main(String[] args) </p>
<p>{ </p>
<p>// 你认为 test 函数返回的值是多少呢？ </p>
<p>System.out.println(\"test 的返回值为： \" + test()); </p>
<p>} </p>
<p>public static int test() </p>
<p>{ </p>
<p>int ret = 1; </p>
<p>try </p>
<p>{ </p>
<p>System.out.println(\"in try block\"); </p>
<p>// 是返回 1 ，还是返回 2 呢？ </p>
<p>return (ret); </p>
<p>} </p>
<p>catch(Exception e) </p>
<p>{ </p>
<p>System.out.println(\"in catch block\"); </p>
<p>e.printStackTrace(); </p>
<p>} </p>
<p>finally </p>
<p>{ </p>
<p>// 注意，这里重新改变了 ret 的值。 </p>
<p>ret = 2; </p>
<p>System.out.println(\"in finally block!\"); </p>
<p>} </p>
<p>return 0; </p>
<p>} </p>
<p>} </p>
<p>上面的示例程序中，本来是想在 finally 区域中通过改变 ret 的值，来影响 test 函数最终 return 的值。但是真的影响了吗？否！否！否！不信，看看运行结果吧！ </p>
<p>in try block </p>
<p>in finally block! </p>
<p>test 的返回值为： 1 </p>
<p>其实，在 SEH 异常处理模型中， try-finally 语句对此情况也是有相同结果的处理结果，同样是上面的那个程序，把它改称 C 语言的形式，用 VC 编译运行一把，验证一下结果，代码如下： </p>
<p>#include \"stdio.h\" </p>
<p>int test() </p>
<p>{ </p>
<p>int ret = 1; </p>
<p>__try </p>
<p>{ </p>
<p>printf(\"in try block<br>
\"); </p>
<p>return ret; </p>
<p>} </p>
<p>__finally </p>
<p>{ </p>
<p>ret = 2; </p>
<p>printf(\"in finally block!<br>
\"); </p>
<p>} </p>
<p>return 0; </p>
<p>} </p>
<p>void main() </p>
<p>{ </p>
<p>printf(\"test 的返回值为： %d<br>
\", test()); </p>
<p>} </p>
<p><br>
通过调试可以很容易看出，在 return ret 之前，编译器实际上对 ret 赋值了一份临时变量，为的就是防止 finally
区域中的代码对这个 ret 值的改变。当然这只是 debug 版本的情况，实际上，在 release 版本， return ret
语句直接被编译器编译成 mov eax, 1 指令。 </p>
<p>所以说，无论是在 SEH 异常处理模型中，还是 Java 的异常处理模型中， finally 块区域中的代码都是不能够通过重新赋值的方式来改变 try 区域中 return 语句的返回值。 </p>
<p>强烈建议不要在 finally 内部使用 return 语句 <br>
上面刚刚说了， finally 块区域中的代码不会轻易影响 try 区域中 return 语句的返回值，但是有一种情况例外，那就是在 finally 内部使用 return 语句。示例程序如下： </p>
<p>// 示例程序 1 ， Java 程序 </p>
<p>import java.io.*; </p>
<p>public class Trans </p>
<p>{ </p>
<p>public static void main(String[] args) </p>
<p>{ </p>
<p>System.out.println(\"test 的返回值为： \" + test()); </p>
<p>} </p>
<p>public static int test() </p>
<p>{ </p>
<p>int ret = 1; </p>
<p>try </p>
<p>{ </p>
<p>System.out.println(\"in try block\"); </p>
<p>return (ret); </p>
<p>} </p>
<p>catch(Exception e) </p>
<p>{ </p>
<p>System.out.println(\"in catch block\"); </p>
<p>e.printStackTrace(); </p>
<p>} </p>
<p>finally </p>
<p>{ </p>
<p>ret = 2; </p>
<p>System.out.println(\"in finally block!\"); </p>
<p>// 这里添加了一条 return 语句 </p>
<p>return ret; </p>
<p>} </p>
<p>} </p>
<p>} </p>
<p>// 示例程序 2 ， C 程序 </p>
<p>#include \"stdio.h\" </p>
<p>int test() </p>
<p>{ </p>
<p>int ret = 1; </p>
<p>__try </p>
<p>{ </p>
<p>printf(\"in try block<br>
\"); </p>
<p>return ret; </p>
<p>} </p>
<p>__finally </p>
<p>{ </p>
<p>ret = 2; </p>
<p>printf(\"in finally block!<br>
\"); </p>
<p>return ret; </p>
<p>} </p>
<p>printf(\" 多余的 <br>
\"); </p>
<p>return 0; </p>
<p>} </p>
<p>void main() </p>
<p>{ </p>
<p>printf(\"test 的返回值为： %d<br>
\", test()); </p>
<p>} </p>
<p>上面的程序运行结果如下： </p>
<p>in try block </p>
<p>in finally block! </p>
<p>test 的返回值为： 2 </p>
<p>也许大多数朋友都估计到，上面的 test 函数返回值是 2 。也即是说， finally 内部使用 return
语句后，它影响（覆盖了） try 区域中 return
语句的返回值。这真是一种特别糟糕的情况，虽然它表面上看起来不是那么严重，但是这种程序极易给它人造成误解（使得阅读该代码的人总得担心或考虑，是否有
其它地方影响了这里的 return 的返回值）。 </p>
<p>之所以出现这种现象的真正原因是，由于 finally 区域中的代码先于 return 语句（ try
作用域中的）被执行，但是，如果此时在 finally 内部也有一个 return 语句，这将会导致该函数直接就返回了，而致使 try
作用域中的 return 语句再也得不到执行机会（实际就是无效代码，被覆盖了）。 </p>
<p>面对上述情况，其实更合理的做法是，既不在 try block 内部中使用 return 语句，也不在 finally 内部使用
return 语句，而应该在 finally 语句之后使用 return 来表示函数的结束和返回，把上面的程序改造一下，代码如下 </p>
<p>import java.io.*; </p>
<p>public class Trans </p>
<p>{ </p>
<p>public static void main(String[] args) </p>
<p>{ </p>
<p>try </p>
<p>{ </p>
<p>System.out.println(\"test 的返回值为： \" + test()); </p>
<p>} </p>
<p>catch(Exception e) </p>
<p>{ </p>
<p>e.printStackTrace(); </p>
<p>} </p>
<p>} </p>
<p>public static int test() throws RuntimeException </p>
<p>{ </p>
<p>int ret = 1; </p>
<p>try </p>
<p>{ </p>
<p>System.out.println(\"in try block\"); </p>
<p>} </p>
<p>catch(RuntimeException e) </p>
<p>{ </p>
<p>System.out.println(\"in catch block\"); </p>
<p>e.printStackTrace(); </p>
<p>throw e; </p>
<p>} </p>
<p>finally </p>
<p>{ </p>
<p>ret = 2; </p>
<p>System.out.println(\"in finally block!\"); </p>
<p>} </p>
<p>// 把 return 语句放在最后，这最为妥当 </p>
<p>return ret; </p>
<p>} </p>
<p>} </p>
<p>另一种更糟糕的情况 <br>
上面刚刚讲到， finally 内部使用 return 语句会覆盖 try 区域中 return 语句的返回值。不仅与此， finally
内部使用 return 语句还会导致出现另外一种更为糟糕的局面。到底是何种糟糕情况呢？还是先看看下面的示例程序再说吧！代码如下： </p>
<p>import java.io.*; </p>
<p>public class Trans </p>
<p>{ </p>
<p>public static void main(String[] args) </p>
<p>{ </p>
<p>try </p>
<p>{ </p>
<p>System.out.println(\"test 的返回值为： \" + test()); </p>
<p>} </p>
<p>catch(Exception e) </p>
<p>{ </p>
<p>e.printStackTrace(); </p>
<p>} </p>
<p>} </p>
<p>public static int test() throws RuntimeException </p>
<p>{ </p>
<p>int ret = 0; </p>
<p>try </p>
<p>{ </p>
<p>System.out.println(\"in try block\"); </p>
<p>// 这里会导致出现一个运行态异常 </p>
<p>int i=4,j=0; </p>
<p>ret = i/j; </p>
<p>} </p>
<p>catch(RuntimeException e) </p>
<p>{ </p>
<p>System.out.println(\"in catch block\"); </p>
<p>e.printStackTrace(); </p>
<p>// 异常被重新抛出，上层函数可以进一步处理此异常 </p>
<p>throw e; </p>
<p>} </p>
<p>finally </p>
<p>{ </p>
<p>System.out.println(\"in finally block!\"); </p>
<p>// 注意，这里有一个 return 语句 </p>
<p>return ret; </p>
<p>} </p>
<p>} </p>
<p>} </p>
<p>是不是觉得上面示例程序中的代码写的挺好的，挺简洁的，还挺严谨的，应该不会有什么 BUG
！阿愚告诉你，错了！绝对错了！而且问题很严重！要不，朋友们在编译运行此程序前，先预期一下它的运行结果，大家是不是觉得运行流程应该是这样子的：
首先在终端输出&#8220; in try block &#8221;，接着，由于程序运行时出现了一个被 0 处的异常（ ArithmeticException
）；于是，进入到 catch block 中，这里的代码将继续向终端输出了&#8220; in catch block
&#8221;信息，以及输出异常的堆栈信息等；接着，由于异常在 catch block 中又被重新抛出了，所以控制权返回到 main 函数的 catch
block 中；对了，补充一点，也许大家会觉得，由于异常的 rethrow ，使得控制权离开 test 函数作用域的时候， finally
内的代码会被执行，也即&#8220; in finally block &#8221;信息也会被打印到终端上了 。仅仅如此吗？不妨看一下实际的运行结果，如下： </p>
<p>in try block </p>
<p>in catch block </p>
<p>java.lang.ArithmeticException: / by zero </p>
<p>at Trans.test(Trans.java:27) </p>
<p>at Trans.main(Trans.java:10) </p>
<p>in finally block! </p>
<p>test 的返回值为： 0 </p>
<p>看了实际的运行结果，是不是觉得大吃一惊！被重新抛出（ rethrow ）的异常居然&#8220;丢弃了&#8221;，也即 main 函数中，并没有捕获到
test 函数中的任何异常，这也许大大出乎当初写这段代码的程序员的预料吧！究竟原因何在呢？其实， 罪魁祸首就是 finally block
内部的那条 return 语句 。因为这段程序的运行流程基本如刚才我们预期描述的那样，但是有一点是不对的，那就是当 test
函数中把异常重新抛出后，这将导致又一次的 catch 的搜索和匹配过程，以及 test 函数中的 UnWinding 操作，也即
finally 被调用执行，但是由于 finally 内部的 return 语句，不仅使得它结束了 test
函数的执行（并返回一个值给上层函数），而且这还使得上面的那个对异常进行进一步的操作过程给终止了（也即控制权进入到 catch block
的过程）。瞧瞧！后果严重吧！ </p>
<p>是呀！如果 Java 程序员不注意这种问题，养成一个严谨的、好的编程习惯，它将会导致实际的许多 Java
应用系统中出现一些莫名奇妙的现象（总感觉系统中出现了某类异常，有一些问题，但上层的模块中却总是捕获不到相关的异常，感觉一些良好！其实不然，它完全
是由于 finally 块中的 return 语句不小心把异常给屏蔽丢弃掉了）。 </p>
<p>总结 <br>
&#8226;&nbsp;&nbsp;&nbsp;&nbsp; finally 区域内的代码总在 return 之前被执行； </p>
&#8226;&nbsp;&nbsp;&nbsp;&nbsp; 强烈建议不要在 finally 内部使用 return 语句。它不仅会影响函数的正确返回值，而且它可能还会导致一些异常处理过程的意外终止，最终导致某些异常的丢失。  <img src ="http://www.cnitblog.com/dickznew/aggbug/65948.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/dickznew/" target="_blank">D主</a> 2010-05-11 18:38 <a href="http://www.cnitblog.com/dickznew/archive/2010/05/11/65948.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>当Return遇到Finally（ZZ）</title><link>http://www.cnitblog.com/dickznew/archive/2007/10/23/35238.html</link><dc:creator>D主</dc:creator><author>D主</author><pubDate>Tue, 23 Oct 2007 09:34:00 GMT</pubDate><guid>http://www.cnitblog.com/dickznew/archive/2007/10/23/35238.html</guid><wfw:comment>http://www.cnitblog.com/dickznew/comments/35238.html</wfw:comment><comments>http://www.cnitblog.com/dickznew/archive/2007/10/23/35238.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/dickznew/comments/commentRss/35238.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/dickznew/services/trackbacks/35238.html</trackback:ping><description><![CDATA[<p>最近研究Java，发现很多有趣的事情。今天又是一例。<br>先看代码（注意第5行和第8行的两个&#8221;return&#8221;）</p>
<div class=hl-surround>
<ol class="hl-main ln-show" ondblclick=linenumber(this) title="Double click to hide line number.">
    <li class=hl-firstline><span style="COLOR: green">public</span><span style="COLOR: gray"> </span><span style="COLOR: green">class</span><span style="COLOR: gray"> </span><span style="COLOR: blue">TestClass</span><span style="COLOR: olive">{</span>
    <li><span style="COLOR: gray">&nbsp; &nbsp; </span><span style="COLOR: green">public</span><span style="COLOR: gray">&nbsp;</span><span class=hl-types>int</span><span style="COLOR: gray"> </span><span style="COLOR: blue">test</span><span style="COLOR: olive">(){</span>
    <li><span style="COLOR: gray">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="COLOR: green">try</span><span style="COLOR: olive">{</span>
    <li><span style="COLOR: gray">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="COLOR: blue">System</span><span style="COLOR: gray">.</span><span style="COLOR: blue">out</span><span style="COLOR: gray">.</span><span style="COLOR: blue">println</span><span style="COLOR: olive">(</span><span style="COLOR: #8b0000">"</span><span style="COLOR: red">step1</span><span style="COLOR: #8b0000">"</span><span style="COLOR: olive">)</span><span style="COLOR: gray">;</span>
    <li><span style="COLOR: gray">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="COLOR: green">return</span><span style="COLOR: gray">&nbsp;</span><span style="COLOR: maroon">1</span><span style="COLOR: gray">;</span>
    <li><span style="COLOR: gray">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="COLOR: olive">}</span><span style="COLOR: green">finally</span><span style="COLOR: olive">{</span>
    <li><span style="COLOR: gray">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="COLOR: blue">System</span><span style="COLOR: gray">.</span><span style="COLOR: blue">out</span><span style="COLOR: gray">.</span><span style="COLOR: blue">println</span><span style="COLOR: olive">(</span><span style="COLOR: #8b0000">"</span><span style="COLOR: red">step2</span><span style="COLOR: #8b0000">"</span><span style="COLOR: olive">)</span><span style="COLOR: gray">;</span><span style="COLOR: #ffa500">//会执行吗？</span>
    <li><span style="COLOR: gray">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="COLOR: green">return</span><span style="COLOR: gray">&nbsp;</span><span style="COLOR: maroon">2</span><span style="COLOR: gray">;</span>
    <li><span style="COLOR: gray">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="COLOR: olive">}</span>
    <li><span style="COLOR: gray">&nbsp; &nbsp; </span><span style="COLOR: olive">}</span>
    <li><span style="COLOR: gray">&nbsp; &nbsp; </span><span style="COLOR: green">public</span><span style="COLOR: gray">&nbsp;</span><span class=hl-types>static</span><span style="COLOR: gray"> </span><span class=hl-types>void</span><span style="COLOR: gray"> </span><span style="COLOR: blue">main</span><span style="COLOR: olive">(</span><span style="COLOR: blue">String</span><span style="COLOR: olive">[]</span><span style="COLOR: gray"> </span><span style="COLOR: blue">args</span><span style="COLOR: olive">){</span>
    <li><span style="COLOR: gray">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="COLOR: blue">TestClass</span><span style="COLOR: gray">&nbsp;</span><span style="COLOR: blue">te</span><span style="COLOR: gray">=</span><span style="COLOR: green">new</span><span style="COLOR: gray"> </span><span style="COLOR: blue">TestClass</span><span style="COLOR: olive">()</span><span style="COLOR: gray">;</span>
    <li><span style="COLOR: gray">&nbsp; &nbsp; &nbsp; &nbsp; </span><span class=hl-types>int</span><span style="COLOR: gray">&nbsp;</span><span style="COLOR: blue">t</span><span style="COLOR: gray">=</span><span style="COLOR: blue">te</span><span style="COLOR: gray">.</span><span style="COLOR: blue">test</span><span style="COLOR: olive">()</span><span style="COLOR: gray">;</span>
    <li><span style="COLOR: gray">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="COLOR: blue">System</span><span style="COLOR: gray">.</span><span style="COLOR: blue">out</span><span style="COLOR: gray">.</span><span style="COLOR: blue">println</span><span style="COLOR: olive">(</span><span style="COLOR: blue">t</span><span style="COLOR: olive">)</span><span style="COLOR: gray">;</span>
    <li><span style="COLOR: gray">&nbsp; &nbsp; </span><span style="COLOR: olive">}</span>
    <li><span style="COLOR: olive">}</span> </li>
</ol>
</div>
<p>按理说，一个方法执行到return就应该返回，但是按照Java的规范，finally中的代码又是一定要被执行的。<br>先看看上面这个程序的运行结果：</p>
<div class=hl-surround>
<div class=hl-main>step1<br>step2<br>2</div>
</div>
<p>可以看到，虽然在try块中遇到了return，但finally中的代码仍然被执行了。test()方法的返回值最终为2。</p>
<p>那么try块中的return语句没有用吗？不是的。<br>如果你注释掉第8行，即finally中的return语句，你会发现test方法最终会返回1。结果如下：</p>
<div class=hl-surround>
<div class=hl-main>step1<br>step2<br>1</div>
</div>
<p>发散一下，如果我在catch中返回一个值，同时也在finally中加入一个return语句，结果会怎么样呢？<br>答案是：现象相同。catch中的return和finally中的return都会执行。有兴趣的可以试试。</p>
<img src ="http://www.cnitblog.com/dickznew/aggbug/35238.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/dickznew/" target="_blank">D主</a> 2007-10-23 17:34 <a href="http://www.cnitblog.com/dickznew/archive/2007/10/23/35238.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>private default protected public 访问权限一目了然</title><link>http://www.cnitblog.com/dickznew/archive/2007/03/09/23779.html</link><dc:creator>D主</dc:creator><author>D主</author><pubDate>Fri, 09 Mar 2007 02:41:00 GMT</pubDate><guid>http://www.cnitblog.com/dickznew/archive/2007/03/09/23779.html</guid><wfw:comment>http://www.cnitblog.com/dickznew/comments/23779.html</wfw:comment><comments>http://www.cnitblog.com/dickznew/archive/2007/03/09/23779.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cnitblog.com/dickznew/comments/commentRss/23779.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/dickznew/services/trackbacks/23779.html</trackback:ping><description><![CDATA[
		<div class="tit"> </div>
		<table style="TABLE-LAYOUT: fixed">
				<tbody>
						<tr>
								<td>
										<div class="cnt">                      同一个类           同一个包       不同包的子类      不同包的非子类<br /><br /><strong>private  </strong>             yes<br /><br /><strong>default</strong>               yes                  yes<br /><br /><strong>protected</strong>           yes                  yes                   yes<br />   <br /><strong>public</strong>                 yes                  yes                   yes                    yes</div>
								</td>
						</tr>
				</tbody>
		</table>
<img src ="http://www.cnitblog.com/dickznew/aggbug/23779.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/dickznew/" target="_blank">D主</a> 2007-03-09 10:41 <a href="http://www.cnitblog.com/dickznew/archive/2007/03/09/23779.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Observable与Observer </title><link>http://www.cnitblog.com/dickznew/archive/2007/03/08/23749.html</link><dc:creator>D主</dc:creator><author>D主</author><pubDate>Thu, 08 Mar 2007 06:28:00 GMT</pubDate><guid>http://www.cnitblog.com/dickznew/archive/2007/03/08/23749.html</guid><wfw:comment>http://www.cnitblog.com/dickznew/comments/23749.html</wfw:comment><comments>http://www.cnitblog.com/dickznew/archive/2007/03/08/23749.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/dickznew/comments/commentRss/23749.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/dickznew/services/trackbacks/23749.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 在		Java		中通过		Observable		类和		Observer		接口实现了观察者模式。一个		Observer		对象监视着一个		Observable		对象的变化，当		Observable		对象发生变化时，		Observer		得到通知，就可以进行相应的工作。例如在文档		/		视图结构中，文档被修改了，视图...&nbsp;&nbsp;<a href='http://www.cnitblog.com/dickznew/archive/2007/03/08/23749.html'>阅读全文</a><img src ="http://www.cnitblog.com/dickznew/aggbug/23749.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/dickznew/" target="_blank">D主</a> 2007-03-08 14:28 <a href="http://www.cnitblog.com/dickznew/archive/2007/03/08/23749.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>从持久化说开去（资料整理）</title><link>http://www.cnitblog.com/dickznew/archive/2006/12/18/20743.html</link><dc:creator>D主</dc:creator><author>D主</author><pubDate>Mon, 18 Dec 2006 06:40:00 GMT</pubDate><guid>http://www.cnitblog.com/dickznew/archive/2006/12/18/20743.html</guid><wfw:comment>http://www.cnitblog.com/dickznew/comments/20743.html</wfw:comment><comments>http://www.cnitblog.com/dickznew/archive/2006/12/18/20743.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/dickznew/comments/commentRss/20743.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/dickznew/services/trackbacks/20743.html</trackback:ping><description><![CDATA[        持久化是将Java虚拟机对象持久保存，而不是将数据库映射为对象，通常数据的存储是用数据库实现的；当然，如果你有更好的存储系统，也可以映射到系统中的存储设备中，这可能需要你自行开发持久化框架来进行持久化一个Java对象。如果是持久化到数据库，现在已经涌出许多ORM框架，像Hibernate，轻量级的ibatis，都是不错的选择。<br /> <br />        现在大部分数据库还是关系型的，而Java是面向对象的语言，很明显将一个对象型的数据如何保存到关系型数据库中呢？这就要借助强大的ORM框架解决这个问题。 比如ibatis框架，使用时只要配置好sqlMapConfig及相应的sqlMap配置文件，只要保存对象或更新对象及可，编程时不再需要写sql才能操作数据，查找时同样查到的是对象数据而不是关系型数据，通过对象set(para),get()方法插入及取得对应数据，Hibernate也是同样的，这里不再祥述。<br />         <br />        以数据库为核心的软件时代已经过去，数据库时代早已结束，当我看到J2EE征途中那么多人在对象和数据库之间彷徨痛苦ing的时候，我想我该出来喊一声了。 　　<br />        其实这句话在几年前肯定有人喊过，因为中间件时代的来临，实际意味着数据库时代终结，正所谓一山无二虎：如果你重视数据库，你的J2EE系统就无法完全OO，只有你忽视数据库，你的系统才有可能完全迈向OO，至于数据库性能调优等特定功能都可交由EJB容器或O/R Mapping工具实现。 　　<br />        很多年前，包括我自己在内的大部分企业程序员都是从数据库开始我们的职业生涯，最早的是dBase/FoxPro，后来有了 SQL系列数据库, Oracle将数据库时代推向了顶峰。 　　<br />        每当有一个新项目时，第一步就是首先设计出数据表结构(Table Schema)，然后开始使用SQL语句实现业务逻辑，这种开发模式一直重复，就是后来加入了DelPhI/VB，他们也只是承担图形显示实现，这种C/S结构带来最大问题是：非常难于维护，修改起来，迁一动百。 　　<br />软件的生命在于运动，当它需要发展时，最棒的软件人员如果对他也束手无策，这是谁的悲哀？ 　　<br />        现在更多人开始接受B/S结构，但是他们中很多人还没有真正明白为什么需要B/S结构，B/S代表的多层架构才是真正目的（因此，伪多层的B/S系统遍地皆是）。 　　<br />        多层架构实际是将以前系统中的显示功能、业务运算功能和数据库功能完全分开，杜绝彼此的耦合与影响，从而实现松耦合和良好的可维护性。<br /> 　　<br />一. 从设计上说：由于实现层次完全分离，业务运算功能成为一种中间功能（中间层），它不依赖具体的表现层技术(Jsp/Html Applet等)，也不依赖具体数据库技术（Oracle/SQL Server），业务运算功能运行在J2EE应用服务器中，当我们的业务运算功能不再依赖数据库时，是否意味着数据库已经不是重点？<br /> 　　<br />二. 当然，多层结构带来了性能问题：客户端访问数据库中的数据时，通常需要经过多个层次，非常耗费性能， 如何尽量减少数据库访问是J2EE应用系统首要解决的问题，使用存储过程并没有解决这个问题，存储过程的执行还是属于后端，并没有缩短客户端请求所要经历的坎坷路途。<br /> 　　<br />        解决性能问题的根本解决之道是使用对象缓存，现在， 64位CPU提供的巨大内存空间为单台缓存计算提供了硬件基础，更重要的是，这种缓存计算是可伸缩的，通过集群的缓存机制（如JBossCache）， 通过增加应用服务器的数量，可以提高整个业务逻辑层的缓存计算能力，抛弃过去那种为内存斤斤计较的老思维吧。 <br />　　<br />三. 在系统分析之初是否首先需要数据表设计呢？回答是否定的， 以UML为代表面向对象的分析设计方法已经成为强大工具，随着面向模型驱动分析设计（MDA）的普及， 面向数据库分析方法正在逐步被抛弃，拥有深厚传统数据库分析习惯的程序员必须面对和接受这种挑战。<br /> 　　<br />        <strong>纵观整个J2EE系统开发过程，数据库已经从过去的中心位置降为一种纯技术实现，数据库只是状态持久化的一种手段（文件是另外一种实现手段）；什么是持久化？这是相对于内存缓存状态而言，持久化就是当内存断电情况下能永久保存状态数据，但是如果J2EE应用服务器是7X24小时集群运行；几乎永不当机，是否有持久化的必要呢？<br /></strong>　　<br />        很显然，数据库已经沦为与操作系统中文件系统同样的层面，以它为中心的时代真的结束了，IBM早期将DB2数据库开源已经强烈向我们昭示这点。<br /> 　　<br />        对于J2EE初学者来说，尽早抛弃过去的两种影响：过程语言编程习惯和以数据库为中心的设计习惯，从全新的面向对象角度(OOA、OOD和OOP、AOP)来设计开发你的J2EE系统，J2EE设计开发三件宝：Model、Patterns和Framework。<br /> 　　<br />        以上不只是理论，而是我每天正在做的，如果你也是或赞同请广为传播，唤醒更多彷徨痛苦的初学者。 <img src ="http://www.cnitblog.com/dickznew/aggbug/20743.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/dickznew/" target="_blank">D主</a> 2006-12-18 14:40 <a href="http://www.cnitblog.com/dickznew/archive/2006/12/18/20743.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>解决taglib在servlet2.4和jsp2.0下写入web.xml的问题</title><link>http://www.cnitblog.com/dickznew/archive/2006/12/01/19797.html</link><dc:creator>D主</dc:creator><author>D主</author><pubDate>Fri, 01 Dec 2006 02:15:00 GMT</pubDate><guid>http://www.cnitblog.com/dickznew/archive/2006/12/01/19797.html</guid><wfw:comment>http://www.cnitblog.com/dickznew/comments/19797.html</wfw:comment><comments>http://www.cnitblog.com/dickznew/archive/2006/12/01/19797.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cnitblog.com/dickznew/comments/commentRss/19797.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/dickznew/services/trackbacks/19797.html</trackback:ping><description><![CDATA[
		<span style="FONT-SIZE: 12pt">注意：如果所建项目是servlet2.4的，那么在web.xml中写taglib就要加一个<br /><strong>&lt;jsp-config&gt;</strong>标记，如下所示： 
<p><font face="Courier New" size="2">&lt;?xml version="1.0" encoding="UTF-8"?&gt;<br />&lt;web-app id="WebApp_ID" version="2.4" xmlns="</font><a href="http://java.sun.com/xml/ns/j2ee"><font face="Courier New" size="2">http://java.sun.com/xml/ns/j2ee</font></a><font face="Courier New" size="2">" xmlns:xsi="</font><a href="http://www.w3.org/2001/XMLSchema-instance"><font face="Courier New" size="2">http://www.w3.org/2001/XMLSchema-instance</font></a><font face="Courier New" size="2">" xsi:schemaLocation="</font><a href="http://java.sun.com/xml/ns/j2ee"><font face="Courier New" size="2">http://java.sun.com/xml/ns/j2ee</font></a><a href="http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"><font face="Courier New" size="2">http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd</font></a><font face="Courier New" size="2">"&gt;<br /> &lt;display-name&gt;<br /> TagStudy2<br /> &lt;/display-name&gt;<br /> <br /><font color="#ff1111">  &lt;jsp-config&gt;</font><br />       &lt;taglib&gt;<br />           &lt;taglib-uri&gt;/hello&lt;/taglib-uri&gt;<br />           &lt;taglib-location&gt;/WEB-INF/HelloTag.tld&lt;/taglib-location&gt;<br />      &lt;/taglib&gt;<br />   </font><font size="2"><font face="Courier New"><font color="#ff1111">&lt;/jsp-config&gt; <br /></font>   </font></font></p><p><font face="Courier New" size="2"> &lt;welcome-file-list&gt;<br />  &lt;welcome-file&gt;default.jsp&lt;/welcome-file&gt;<br /> &lt;/welcome-file-list&gt;<br /> </font></p><p><font face="Courier New" size="2">&lt;/web-app&gt;</font><br /><br />从servlet2.4开始，taglib的uri是在标签库描述符中(tld)指定的，就像下面：</p><p><font face="Courier New"><font size="2"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" twffan="done" /><span style="COLOR: #0000ff" twffan="done">&lt;?</span><span style="COLOR: #ff00ff" twffan="done">xml version="1.0" encoding="UTF-8"</span><span style="COLOR: #0000ff" twffan="done">?&gt;</span></font></font><span style="COLOR: #000000" twffan="done"><br /><font face="Courier New" size="2"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" twffan="done" /></font></span><span style="COLOR: #0000ff" twffan="done"><font face="Courier New" size="2">&lt;!</font></span><font face="Courier New"><font size="2"><span style="COLOR: #ff00ff" twffan="done">DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag <br /><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" twffan="done" />Library 1.1//EN" "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd"</span><span style="COLOR: #0000ff" twffan="done">&gt;</span></font></font><span style="COLOR: #000000" twffan="done"><br /><font face="Courier New" size="2"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" twffan="done" /></font></span><font face="Courier New"><font size="2"><span style="COLOR: #0000ff" twffan="done">&lt;</span><span style="COLOR: #800000" twffan="done">taglib</span><span style="COLOR: #0000ff" twffan="done">&gt;</span></font></font><span style="COLOR: #000000" twffan="done"><br /><font face="Courier New" size="2"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" twffan="done" />  </font></span><font face="Courier New"><font size="2"><span style="COLOR: #0000ff" twffan="done">&lt;</span><span style="COLOR: #800000" twffan="done">tlibversion</span><span style="COLOR: #0000ff" twffan="done">&gt;</span><span style="COLOR: #000000" twffan="done">1.0</span><span style="COLOR: #0000ff" twffan="done">&lt;/</span><span style="COLOR: #800000" twffan="done">tlibversion</span><span style="COLOR: #0000ff" twffan="done">&gt;</span></font></font><span style="COLOR: #000000" twffan="done"><br /><font face="Courier New" size="2"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" twffan="done" />  </font></span><font face="Courier New"><font size="2"><span style="COLOR: #0000ff" twffan="done">&lt;</span><span style="COLOR: #800000" twffan="done">jspversion</span><span style="COLOR: #0000ff" twffan="done">&gt;</span><span style="COLOR: #000000" twffan="done">1.1</span><span style="COLOR: #0000ff" twffan="done">&lt;/</span><span style="COLOR: #800000" twffan="done">jspversion</span><span style="COLOR: #0000ff" twffan="done">&gt;</span></font></font><span style="COLOR: #000000" twffan="done"><br /><font face="Courier New" size="2"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" twffan="done" />  </font></span><font face="Courier New"><font size="2"><span style="COLOR: #0000ff" twffan="done">&lt;</span><span style="COLOR: #800000" twffan="done">shortname</span><span style="COLOR: #0000ff" twffan="done">&gt;</span><span style="COLOR: #000000" twffan="done">bean</span><span style="COLOR: #0000ff" twffan="done">&lt;/</span><span style="COLOR: #800000" twffan="done">shortname</span><span style="COLOR: #0000ff" twffan="done">&gt;</span></font></font><span style="COLOR: #000000" twffan="done"><br /><font face="Courier New" size="2"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" twffan="done" />  <br /><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" twffan="done" /></font></span><font face="Courier New"><font size="2"><span style="COLOR: #0000ff" twffan="done">&lt;</span><span style="COLOR: #800000" twffan="done">uri</span><span style="COLOR: #0000ff" twffan="done">&gt;</span><span style="COLOR: #000000" twffan="done">http://jakarta.apache.org/struts/tags-bean</span><span style="COLOR: #0000ff" twffan="done">&lt;/</span><span style="COLOR: #800000" twffan="done">uri</span><span style="COLOR: #0000ff" twffan="done">&gt;</span></font></font></p><p><span style="COLOR: #0000ff" twffan="done"><font color="#000000">任何需要使用这个标签库的页面都可以通过下面的页面级指令来引用它。标签库不需要再在web.xml文件中引用：</font><br /><span style="COLOR: #0000ff" twffan="done"><font face="Courier New" size="2">&lt;</font></span><font face="Courier New"><font size="2"><span style="COLOR: #800000" twffan="done">%@ taglib<br /><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" twffan="done" />        </span><span style="COLOR: #ff0000" twffan="done">uri</span><span style="COLOR: #0000ff" twffan="done">="http://jakarta.apache.org/struts/tags-bean"</span></font></font><span style="COLOR: #ff0000" twffan="done"><br /><font face="Courier New" size="2"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" twffan="done" />        prefix</font></span><font face="Courier New"><font size="2"><span style="COLOR: #0000ff" twffan="done">="bean"</span><span style="COLOR: #ff0000" twffan="done"> %</span><span style="COLOR: #0000ff" twffan="done">&gt;</span></font></font></span></p><p><span style="COLOR: #0000ff" twffan="done"><span style="COLOR: #0000ff" twffan="done">下面一个表是struts标签的uri：</span></span></p><span style="COLOR: #0000ff" twffan="done"><span style="COLOR: #0000ff" twffan="done"><p></p><table cellspacing="0" cellpadding="0" border="1"><tbody><tr><td width="100%" colspan="3"><h5><font face="Courier New">Table 2-1. Struts 标签库URI</font></h5></td></tr><tr><td width="17%"><p align="center"><strong><font face="Courier New" size="2">Tag library</font></strong></p></td><td width="45%"><p align="center"><strong><font face="Courier New" size="2">Struts 1.1 URI</font></strong></p></td><td width="36%"><p align="center"><strong><font face="Courier New" size="2">Struts 1.2 URI</font></strong></p></td></tr><tr><td width="17%"><p><font face="Courier New" size="2">struts-bean</font></p></td><td width="45%"><p><a href="http://jakarta.apache.org/struts/tags-bean"><font face="Courier New" size="2">http://jakarta.apache.org/struts/tags-bean</font></a></p></td><td width="36%"><p><a href="http://struts.apache.org/tags-bean"><font face="Courier New" size="2">http://struts.apache.org/tags-bean</font></a></p></td></tr><tr><td width="17%"><p><font face="Courier New" size="2">struts-html</font></p></td><td width="45%"><p><a href="http://jakarta.apache.org/struts/tags-html"><font face="Courier New" size="2">http://jakarta.apache.org/struts/tags-html</font></a></p></td><td width="36%"><p><a href="http://struts.apache.org/tags-html"><font face="Courier New" size="2">http://struts.apache.org/tags-html</font></a></p></td></tr><tr><td width="17%"><p><font face="Courier New" size="2">struts-logic</font></p></td><td width="45%"><p><a href="http://jakarta.apache.org/struts/tags-logic"><font face="Courier New" size="2">http://jakarta.apache.org/struts/tags-logic</font></a></p></td><td width="36%"><p><a href="http://struts.apache.org/tags-logic"><font face="Courier New" size="2">http://struts.apache.org/tags-logic</font></a></p></td></tr><tr><td width="17%"><p><font face="Courier New" size="2">struts-nested</font></p></td><td width="45%"><p><a href="http://jakarta.apache.org/struts/tags-nested"><font face="Courier New" size="2">http://jakarta.apache.org/struts/tags-nested</font></a></p></td><td width="36%"><p><a href="http://struts.apache.org/tags-nested"><font face="Courier New" size="2">http://struts.apache.org/tags-nested</font></a></p></td></tr><tr><td width="17%"><p><font face="Courier New" size="2">struts-template</font></p></td><td width="45%"><p><a href="http://jakarta.apache.org/struts/tags-template"><font face="Courier New" size="2">http://jakarta.apache.org/struts/tags-template</font></a></p></td><td width="36%"><p><font face="Courier New" size="2">不再包括，被Tiles代替</font></p></td></tr><tr><td width="17%"><p><font face="Courier New" size="2">struts-tiles</font></p></td><td width="45%"><p><a href="http://jakarta.apache.org/struts/tags-tiles"><font face="Courier New" size="2">http://jakarta.apache.org/struts/tags-tiles</font></a></p></td><td width="36%"><p><a href="http://struts.apache.org/tags-tiles"><font face="Courier New" size="2">http://struts.apache.org/tags-tiles</font></a></p></td></tr><tr><td width="17%"><p><font face="Courier New" size="2">struts-bean-el</font></p></td><td width="45%"><p><a href="http://jakarta.apache.org/struts/tags-bean-el"><font face="Courier New" size="2">http://jakarta.apache.org/struts/tags-bean-el</font></a></p></td><td width="36%"><p><a href="http://struts.apache.org/tags-bean-el"><font face="Courier New" size="2">http://struts.apache.org/tags-bean-el</font></a></p></td></tr><tr><td width="17%"><p><font face="Courier New" size="2">struts-html-el</font></p></td><td width="45%"><p><a href="http://jakarta.apache.org/struts/tags-html-el"><font face="Courier New" size="2">http://jakarta.apache.org/struts/tags-html-el</font></a></p></td><td width="36%"><p><a href="http://struts.apache.org/tags-html-el"><font face="Courier New" size="2">http://struts.apache.org/tags-html-el</font></a></p></td></tr><tr><td width="17%"><p><font face="Courier New" size="2">struts-logic-el</font></p></td><td width="45%"><p><a href="http://jakarta.apache.org/struts/tags-logic-el"><font face="Courier New" size="2">http://jakarta.apache.org/struts/tags-logic-el</font></a></p></td><td width="36%"><p><a href="http://struts.apache.org/tags-logic-el"><font face="Courier New" size="2">http://struts.apache.org/tags-logic-el</font></a></p></td></tr></tbody></table><p>        sturts标签的可以直接通过uri引用，也可以通过在web.xml中声明再使用。直接通过uri引用，则不再需要tld文件，如果是web.xml的话，灵活性比较大，uri以后改变的话，只需要在web.xml中改变，不用在其他页面中改变。</p></span></span></span>
<img src ="http://www.cnitblog.com/dickznew/aggbug/19797.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/dickznew/" target="_blank">D主</a> 2006-12-01 10:15 <a href="http://www.cnitblog.com/dickznew/archive/2006/12/01/19797.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Eclipse和JBuilder共存（D主整理）</title><link>http://www.cnitblog.com/dickznew/archive/2006/11/08/18982.html</link><dc:creator>D主</dc:creator><author>D主</author><pubDate>Wed, 08 Nov 2006 15:29:00 GMT</pubDate><guid>http://www.cnitblog.com/dickznew/archive/2006/11/08/18982.html</guid><wfw:comment>http://www.cnitblog.com/dickznew/comments/18982.html</wfw:comment><comments>http://www.cnitblog.com/dickznew/archive/2006/11/08/18982.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/dickznew/comments/commentRss/18982.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/dickznew/services/trackbacks/18982.html</trackback:ping><description><![CDATA[        怎样让JBuilder不要影响Eclipse的正常使用（Error:could not find Java 2 runtime Environment）？这个问题曾经困扰我好久，虽然后来不怎么用JBuilder，而且Eclipse也可以用startup.jar来启动，但是还是有像我这样赌气非用eclipse.exe不可的。网上也是说法各异，有说改CLASSPATH的、还有改注册表的，还有重装JDK的。我尝试的结果是在环境变量里把path变量的java\bin放在最开始的位置就OK了...sign，就是这么简单，只要Eclipse能找到标准的JRE或JDK的bin目录下的javaw.exe而不是JBuilder自带的JDK。<img src ="http://www.cnitblog.com/dickznew/aggbug/18982.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/dickznew/" target="_blank">D主</a> 2006-11-08 23:29 <a href="http://www.cnitblog.com/dickznew/archive/2006/11/08/18982.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>