<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>天空之城</title>
    <description></description>
    <link>http://lionheart.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>ruby正则表达式学习</title>
        <author>lionheart</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lionheart.javaeye.com">lionheart</a>&nbsp;
          链接：<a href="http://lionheart.javaeye.com/blog/233591" style="color:red;">http://lionheart.javaeye.com/blog/233591</a>&nbsp;
          发表时间: 2008年08月27日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><strong>一、Regexp类的一些方法：</strong>
</p>
<p>&nbsp;&nbsp;&nbsp; Regexp.<span style="color: #ff0000;">new/compile</span>

 (string/regexp,[options,[lang]]) : 构造一个正则表达式对象。第一个参数是一个字符串或者正则表达式；第二个参数是 正则表达式修饰符的按位OR。</p>
<p>&nbsp;&nbsp;&nbsp; Regexp.<span style="color: #ff0000;">escape/quote</span>

 (string) : 对正则表达式中的特殊字符进行转义。如：</p>
<pre name="code" class="ruby">Regexp.escape('\\*?{}.')   #=&gt; \\\\\*\?\{\}\.</pre>
<p>&nbsp;rxp.<span style="color: #ff0000;">match</span>

(str) : 返回一个表示匹配结果的<span style="color: #ff0000;">MatchData</span>

对象。如果没有匹配则返回nil</p>
<pre name="code" class="ruby">str = &quot;a123b456c789&quot;
refs = /(a\d+)(b\d+)(c\d+)/.match(str)
puts refs[0]   # &quot;a123b456c789&quot; 
puts refs[1,3]  # [&quot;a123&quot;,&quot;b456&quot;,&quot;c789&quot;]
refs.to_a.each {x| x}   # MatchData对象不是数组，在进行迭代前要调用to_a方法将其转换为一个数组。</pre>
<p>&nbsp;也可以使用全局变量$1,$2等引用匹配结果：</p>
<pre name="code" class="ruby">refs = /(a\d+)(b\d+)(c\d+)/.match(&quot;a123b456c789&quot;)
puts &quot;'#$1','#$2','$3'&quot;  # 'a123','b456','c789'
</pre>
<p>在sub、gsub等方法中， 不能使用$1等来引用结果，因为这些参数在调用方法前就已经计算好。这时，可以采用特殊编码\1,\2等：</p>
<pre name="code" class="ruby">refs = /(a\d+)(b\d+)(c\d+)/.match(&quot;a123b456c789&quot;)
puts &quot;'#$1','#$2','$3'&quot;  # 'a123','b456','c789'
&quot;a123b456c789&quot;.sub(/(a\d+)(b\d+)(c\d+)/, '1st=\1, 2nd=\2, 3rd=\3')   # 1st=a123, 2nd=b456, 3rd=c789
&quot;a123b456c789&quot;.sub(/(a\d+)(b\d+)(c\d+)/, &quot;1st=\\1, 2nd=\\2, 3rd=\\3&quot;)   # 1st=a123, 2nd=b456, 3rd=c789
# 上面两个sub方法中，第一个使用的是单引号；第二个是双引号，需要使用双语义</pre>
<p>MatchData对象还有以下一些有用的方法：</p>
<p style="padding-left: 30px;">1. <span style="color: #ff0000;">begin(n)</span>

: 返回第n个匹配开头的偏移量</p>
<p style="padding-left: 30px;">2. <span style="color: #ff0000;">end(n)</span>

: 返回第n个匹配结束的偏移量（等于第n+1个匹配的开头偏移量）</p>
<p style="padding-left: 30px;">3. <span style="color: #ff0000;">offset(n)</span>

: 返回一个包含第n个匹配开头和结束偏移量的数组</p>
<p style="padding-left: 30px;">4. <span style="color: #ff0000;">pre_match</span>

: 返回匹配子字符串前面的字符串部分</p>
<p style="padding-left: 30px;">5. <span style="color: #ff0000;">post_match</span>

: 返回匹配子字符串后面的字符串部分</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><strong>二、一些常用的标记</strong>
</p>
<p style="padding-left: 30px;">1.&nbsp; <span style="color: #ff0000;">^</span>
 和 <span style="color: #ff0000;">$</span>
&nbsp; : 行或字符串开头/结尾（注意：匹配单行的行头/行尾）。</p>
<pre name="code" class="ruby">src = &quot;abc\ndef\nghi&quot;
/^abc/ =～ src  #0
/^def/ =～ src   #4
/def$/ =～ src   #4
/ghi$/ =～ src  #8</pre>
<p style="padding-left: 30px;">2. <span style="color: #ff0000;">\A</span>
 和 <span style="color: #ff0000;">\Z</span>
 : 整个字符串的开头/末尾或最后的换行符前</p>
<p style="padding-left: 30px;">&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #ff0000;">\z</span>
 : 基本同 \Z，但是不能匹配最后的换行符</p>
<pre name="code" class="ruby">src = &quot;abc\ndef\nghi&quot;
/\Aabc/ =～ src  #0
/\Adef/ =～ src   #nil
/def\Z/ =～ src   #nil
/ghi\Z/ =～ src  #8
/ghi\z/ =～ src  #8
src &lt;&lt; &quot;\n&quot;
/ghi\Z/ =～ src  #8
/ghi\z/ =～ src  #nil</pre>
<p style="padding-left: 30px;">3. <span style="color: #ff0000;">\b</span>
 : 单词边界（在[]外）；<span style="color: #ff0000;"> \B</span>
 : 非单词边界</p>
<pre name="code" class="ruby">src = &quot;this is a test&quot;
src.gsub(/\b/, '|')  # &quot;|this| |is| |a| |test|&quot;
src.gsub(/\B/, '-')  # &quot;t-h-i-s i-s a t-e-s-t&quot;</pre>
<p style="padding-left: 30px;">4. <span style="color: #ff0000;">{?=}</span>
: 正预查 ，当匹配子字符串sub后面接着的字符串与预查中=号后面的字符串匹配时，sub才匹配成功；{?!}: 负预查，当匹配子字符串sub后面接着的字符串与预查中=号后面的字符串不匹配时，sub才匹配成功。</p>
<pre name="code" class="ruby">/(a\d+)(?=b)(b\d+)(c\d+)/.match(&quot;a123b456c789&quot;)    # ['a123','b456','c789']
 /(a\d+)(?=c)(b\d+)(c\d+)/.match(&quot;a123b456c789&quot;)    # nil
 /(a\d+)(?=b)(\d+)(c\d+)/.match(&quot;a123b456c789&quot;)     # nil

 /(a\d+)(?!c)(b\d+)(c\d+)/.match(&quot;a123b456c789&quot;)    # ['a123','b456','c789'</pre>
<p style="padding-left: 30px;">5. <span style="color: #ff0000;">()</span>
 : 子表达式编组； <span style="color: #ff0000;">(?:)</span>
 : 非捕获组</p>
<pre name="code" class="ruby">refs = /(a\d+)(b\d+)(c\d+)/.match(&quot;a123b456c789&quot;)
puts &quot;'#$1','#$2','$3'&quot;  # 'a123','b456','c789'

refs = /(a\d+)(?:b\d+)(c\d+)/.match(&quot;a123b456c789&quot;)
puts &quot;'#$1','#$2','$3'&quot;  # 'a123','c789','nil'</pre>
<p style="padding-left: 30px;">6. 字符类：包括在方括号[]中的一组字符，其中每一个子匹配是任意一个字符。</p>
<p style="padding-left: 30px;">&nbsp;&nbsp;&nbsp; (1) ^用于字符类的开头时有特殊意义，它对字符列表取反。</p>
<p style="padding-left: 30px;">&nbsp;&nbsp;&nbsp; (2) 像.和?之类的元字符在字符类中没有特殊含义，表示自身代表的字符。而\n这样的转义序列仍然有效。</p>
<p style="padding-left: 30px;">&nbsp;&nbsp;&nbsp; (3) 连字符-用于字符类的开头或结尾，脱字符^用于字符类的中间时，没有特殊含义，只表示自身；左括号[和右括号]用于字符类中时，也是如此，而且还必须显示进行转义。</p>
<pre name="code" class="ruby">/[abc]/ =~ &quot;abcd&quot;   #0
/[^abc]/ =~ &quot;abcd&quot;   #3

/[.?abc]/ =~ &quot;.?&quot;   #0

/[-^\[\]]/ =~ &quot;^&quot; #0</pre>
<p>
&nbsp;
&nbsp; &nbsp;&nbsp; 7. 几个修饰符的介绍</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (1) <span style="color: #ff0000;">i</span>
&nbsp;&nbsp; :&nbsp; 正则表达式不区分大小写</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (2) <span style="color: #ff0000;">o&nbsp;</span>
 :&nbsp; 只执行一次表达式替换</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (3) <span style="color: #ff0000;">m</span>
&nbsp; :&nbsp; 多行模式（句点匹配换行）</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (4) <span style="color: #ff0000;">x</span>
&nbsp;&nbsp; :&nbsp; 扩展正则表达式（允许空白、注释）</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><strong>三、一些常用正则表达式实例</strong>
</p>
<p style="padding-left: 30px;">1. 匹配IP地址</p>
<pre name="code" class="ruby">num = /\d|[01]?\d\d|2[0-4]\d|25[0-5]/
ip = /^(#{num}\.){3}#{num}$/

ip =~ '192.168.0.50'  # 0
ip =~ '192.168.0.500'  # nil</pre>
<p style="padding-left: 30px;">2. 匹配email地址</p>
<pre name="code" class="ruby">before_at = /([a-zA-Z0-9]+(_?[a-zA-Z0-9])+)/
after_at = /[a-zA-Z]+(-?[a-zA-Z])+(\.[a-zA-Z]+)+/
email = /^(#{before_at}@#{after_at})$/

email =~ 'abc_123@xyz.com.cn' #0
email =~ 'abc_123@xyz.com' #0
email =~ 'abc_@xyz.com.cn' #nil
email =~ 'abc_123@xy-z.com.cn' #0
email =~ 'abc_123@xyz-.com.cn' #nil</pre>
<p style="padding-left: 30px;">3. 匹配时间/日期类型（yyyy.mm.dd hh:mm:ss）</p>
<pre name="code" class="ruby">yyyy = /[1-9]\d\d\d/
mm = /0?[1-9]|1[12]/
dd = /0?[1-9]|[12]\d|3[01]/
hh = /[01]?[1-9]|2[0-4]/
MM = /[0-5]\d/
ss = /[0-5]\d/
date_time = /^(#{yyyy}\.#{mm}\.#{dd}) (#{hh}:#{MM}:#{ss})$/

date_time =~ '2008.8.27 22:12:10'  # 0
date_time =~ '2008.8.27 22:12:60'  # nil</pre>
<p style="padding-left: 30px;">&nbsp;</p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://lionheart.javaeye.com/blog/233591#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;">北京: 千橡集团暨校内网诚聘软件研发工程师</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>Wed, 27 Aug 2008 22:09:00 +0800</pubDate>
        <link>http://lionheart.javaeye.com/blog/233591</link>
        <guid>http://lionheart.javaeye.com/blog/233591</guid>
      </item>
      <item>
        <title>javascript中==和===操作符的比较</title>
        <author>lionheart</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lionheart.javaeye.com">lionheart</a>&nbsp;
          链接：<a href="http://lionheart.javaeye.com/blog/232871" style="color:red;">http://lionheart.javaeye.com/blog/232871</a>&nbsp;
          发表时间: 2008年08月26日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>摘引至&quot;<strong>JavaScript: The Definitive Guide, 5th Edition</strong>
&quot; chapter 5 section 4</p>
<p>&nbsp;</p>
<p>In JavaScript,<span style="color: #ff0000;"> numbers, strings, and boolean values are compared <span class="docEmphasis">by value</span>
.</span>
 In this case, two separate values are 
involved, and the <tt>==</tt>
 and <tt>===</tt>
 operators check that these two 
values are identical.</p>
<p>On the other hand, <span style="color: #ff0000;">objects, arrays, and functions are compared <span class="docEmphasis">by reference</span>
. </span>
This means that two variables are equal 
only if they <span class="docEmphasis">refer to</span>
 the same object. </p>
<p>&nbsp;</p>
<p class="docText">The following rules determine whether two values are identical 
according to the <tt>===</tt>
 operator:</p>
<ul>
<li>
<p class="docList"><span style="color: #ff0000;">If the two values have different types, they are not 
identical.</span>
</p>
</li>
<li>
<p class="docList">If both values are numbers and have the same value, they are 
identical, unless either or both values are <tt>NaN</tt>
, in which case they are 
not identical. The <tt>NaN</tt>
 value is never identical to any other value, 
including itself! To check whether a value is <tt>NaN</tt>
, use the global 
<tt>isNaN( )</tt>
 function.</p>
</li>
<li>
<p class="docList">If both values are strings and contain exactly the same 
characters in the same positions, they are identical. If the strings differ in 
length or content, they are not identical. Note that in some cases, the Unicode 
standard allows more than one way to encode the same string. For efficiency, 
however, JavaScript's string comparison compares strictly on a 
character-by-character basis, and it assumes that all strings have been 
converted to a &quot;normalized form&quot; before they are compared.&nbsp;</p>
</li>
<li>
<p class="docList">If both values are the boolean value <tt>true</tt>
 or both are 
the boolean value <tt>false</tt>
, they are identical.</p>
</li>
<li>
<p class="docList">If both values refer to the same object, array, or function, 
they are identical. If they refer to different objects (or arrays or functions) 
they are not identical, even if both objects have identical properties or both 
arrays have identical elements.</p>
</li>
<li>
<p class="docList"><span style="color: #ff0000;">If both values are <tt>null</tt>
 or both values are 
<tt>undefined</tt>
, they are identical.</span>
</p>
</li>
</ul>
<p class="docText">The following rules determine whether two values are equal 
according to the <tt>==</tt>
 operator:</p>
<ul>
<li>
<p class="docList">If the two values have the same type, test them for identity. 
If the values are identical, they are equal; if they are not identical, they are 
not equal.</p>
</li>
<li>
<p class="docList">If the two values do not have the same type, they may still be 
equal. Use the following rules and type conversions to check for equality:</p>
<ul>
<li>
<p class="docList"><span style="color: #ff0000;">If one value is <tt>null</tt>
 and the other is 
<tt>undefined</tt>
, they are equal.</span>
</p>
</li>
<li>
<p class="docList">If one value is a number and the other is a string, convert the 
string to a number and try the comparison again, using the converted value.</p>
</li>
<li>
<p class="docList">If either value is <tt>TRue</tt>
, convert it to 1 and try the 
comparison again. If either value is <tt>false</tt>
, convert it to 0 and try the 
comparison again.</p>
</li>
<li>
<p class="docList">If one value is an object and the other is a number or string, 
convert the object to a primitive and try the comparison again. An object is 
converted to a primitive value by either its <tt>toString( )</tt>
 method or its 
<tt>valueOf( )</tt>
 method. The built-in classes of core JavaScript attempt 
<tt>valueOf( )</tt>
 conversion before <tt>toString( )</tt>
 conversion, except 
for the Date class, which performs <tt>toString( )</tt>
 conversion. Objects that 
are not part of core JavaScript may convert themselves to primitive values in an 
implementation-defined way.</p>
</li>
<li>
<p class="docList">Any other combinations of values are not 
equal.</p>
</li>
</ul>
</li>
</ul>
<p>&nbsp;</p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://lionheart.javaeye.com/blog/232871#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;">北京: 千橡集团暨校内网诚聘软件研发工程师</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, 26 Aug 2008 15:30:32 +0800</pubDate>
        <link>http://lionheart.javaeye.com/blog/232871</link>
        <guid>http://lionheart.javaeye.com/blog/232871</guid>
      </item>
      <item>
        <title>mootools Class 继承机制</title>
        <author>lionheart</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lionheart.javaeye.com">lionheart</a>&nbsp;
          链接：<a href="http://lionheart.javaeye.com/blog/232856" style="color:red;">http://lionheart.javaeye.com/blog/232856</a>&nbsp;
          发表时间: 2008年08月26日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <pre name="code" class="js">var Class=function(B)
{
  var A=function()
  {
    // 存在initialize函数的话就执行此函数，否则直接返回
    // arguments[0] 在什么情况下会 === null ?
    return(arguments[0]!==null&amp;&amp;this.initialize&amp;&amp;$type(this.initialize)==&quot;function&quot;)?this.initialize.apply(this,arguments):this;
  };
  $extend(A,this);
  A.prototype=B;
  A.constructor=Class;
  return A;
};

Class.prototype=
{
  extend:function(B)
  {
    var C=new this(null);
    // 属性copy，如果原Class中存在此属性时，根据属性的type
    // 对属性值进行合并或者包装；否则直接设置此属性值
    for(var D in B)
    {
      var A=C[D];
      C[D]=Class.Merge(A,B[D]);
    }
    // 构造新的Class
    return new Class(C);
  }
}

Class.Merge=function(C,D)
{
  // 如果父Class中存在此属性，且不是同一个对象
  if(C&amp;&amp;C!=D)
  {
    var B=$type(D);
    if(B!=$type(C))
    {
      return D;
    }
    switch(B)
    {
      // 如果此属性值是函数类型的话，创建新的函数对象A，将其parent属性
      // 设置为父Class中的同名函数对象，并返回A
      case&quot;function&quot;:var A=function()
      {
        // 执行此函数时，会先对当前执行对象（子对象）的parent属性设置为该函数对象的
        // parent属性（函数对象C），也即父Class中的同名函数对象，然后再用
        // 子对象的上下文来执行扩展时定义的该函数对象D。
        // 这样设置以后，在D中要想访问父类中的同名函数对象时（相当于java中在子类中通过super访问父类中的方法），
        // 使用this.parent.call(this)即可。
        this.parent=arguments.callee.parent;
        return D.apply(this,arguments);
      };
      A.parent=C;
      return A;
      # 如果是一般对象的话，进行属性合并后直接返回
      case&quot;object&quot;:return $merge(C,D);
    }
  }
  return D;
};</pre>
&nbsp;
          <br/><br/>
          <span style="color:red;">
            <a href="http://lionheart.javaeye.com/blog/232856#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;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 26 Aug 2008 14:59:39 +0800</pubDate>
        <link>http://lionheart.javaeye.com/blog/232856</link>
        <guid>http://lionheart.javaeye.com/blog/232856</guid>
      </item>
      <item>
        <title>javascript prototype 继承</title>
        <author>lionheart</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lionheart.javaeye.com">lionheart</a>&nbsp;
          链接：<a href="http://lionheart.javaeye.com/blog/232776" style="color:red;">http://lionheart.javaeye.com/blog/232776</a>&nbsp;
          发表时间: 2008年08月26日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>js中基于prototype实现继承的基本代码如下所示：</p>
<pre name="code" class="js">function(SubClass, SuperClass){
    function F(){}
    // 
    F.prototype = SuperClass.prototype;
    // 实现继承的关键，构造 prototype chain
    SubClass.prototype = new F(); // 1
    // 重置子类prototype对象的constructor属性为子类本身。
    SubClass.prototype.constructor = SubClass;
    // 设置子类的superclass属性值为父类的prototype。
    SubClass.superclass = SuperClass.prototype;  // 2
    // 使得在子类中可以通过baseconstructor来访问父类的构造函数。
    SubClass.baseconstructor = SuperClass;
}</pre>
<p>&nbsp;上述代码中有两个值得关注的地方：</p>
<p>（1）语句1处使用了new F()的方式，这里为什么需要专门new一个F对象出来呢？首先我们来看下面的这段代码的结果：</p>
<pre name="code" class="js">function SP(){this.cls = &quot;super class&quot;;}
SP.prototype.print(alert(this.cls););

function SB(){}
SB.prototype = SP.prototype
SB.prototype.print(alert(&quot;changed by subclass&quot;));

new SP().print();  // output: changed by subclass</pre>
<p>&nbsp;从结果可知SB prototype对象的改变同时影响到了SP，也即此时SB和SP是共享同一个prototype对象。这是不符合继承的本意的。这里如果将</p>
<pre name="code" class="js">SB.prototype = SP.prototype</pre>
<p>
更改为：</p>
<pre name="code" class="js">SB.prototype = new SP()</pre>
<p>则可以避免此问题。这也是代码1处使用了new F() 而不是F.prototype的原因。</p>
<p>这里还有一个疑问就是F在这里具体作用是什么？为什么需要添加F，而不是直接使用<span style="color: #ff0000;">new SuperClass()</span>
？</p>
<p>先看下面这段代码：</p>
<pre name="code" class="js">function SP(){this.cls = &quot;super class&quot;;}
SP.prototype.print(alert(this.cls););

function SB(){}
SB.prototype = new SP();

new SB().print();  // super class

function F(){}
F.prototype = SP.prototype;
SB.prototype = new F();

new SB().print();  // undefined</pre>
<p>&nbsp;代码中两次执行print函数打印出的结果分别是&ldquo;super class&rdquo; 和 undefined。也即第二次执行此函数时SB对象中不存在cls属性，这正是添加一个空的F函数的作用。它可以避免在子类SB中获得得到在父类SP函数体中定义的属性(this.xxx)。</p>
<p>（2）语句2处SubClass.superclass为SuperClass.prototype，而不是SuperClass本身。关于这一点的说明，引用 <a href="http://bbs.51js.com/viewthread.php?tid=72688&amp;page=1&amp;extra=#pid556697">http://bbs.51js.com/viewthread.php?tid=72688&amp;page=1&amp;extra=#pid556697</a>
 上某位网友的观点：</p>
<p>&nbsp;</p>
<div class="quote_div">原型链继承 subclass就是通过prototype的技巧性处理来继承superclass的 这本身是一个逐级向上的递归过程 所以指定superclass指定到superclass的prototype比较合理，而且以后调用也方便 只需要subclass.superclass.method.call 如果像你那样指定的话就需要subclass.superclass.prototype.method.call  反而更复杂了 。<br />
subclass.superclass.call(this) 的方式没有subclass.superclass.constructor.call(this)的方式直观<br />
而且构造函数constructor我感觉也是显示调用比较好，风格比较一致，而且少点潜规则也更容易看懂吧，没必要学java的那种方式，而且如果superclass没有构造函数的话 按照ext的方式会逐级向更上层的父类调用，直到最顶端。</div>
<p>&nbsp;Ext中的继承也是基于prototype chain的方式来实现的，在 <a href="http://www.javaeye.com/topic/195409" title="http://www.javaeye.com/topic/195409">http://www.javaeye.com/topic/195409</a>
 有对其继承方法实现的详细解析。但是，其中有一处代码一直未弄懂其作用：</p>
<pre name="code" class="js"> if(spp.constructor == Object.prototype.constructor){
                     spp.constructor=sp;
   } </pre>
<p>&nbsp;这一代码中，if条件成立时有两种可能：（1）sp本身就是Object；（2）函数对象在创建时，其prototype对象的constructor属性值总是指向函数对象本身。因此另一种可能就是sp显示改变了其prototype对象，而新对象的constructor属性值指向的是Object。第1种情况处理没有任何意义，因为此时spp.constructor一定等于sp；那么只可能是第二种情况。一个令人费解的问题是&quot;为什么要到有子类继承时才重置父类protoype对象constructor的值，而不是在显示改变其prototype对象时就设置&quot;。为什么这里需要重置constructor的值呢？结合前后代码来看：</p>
<pre name="code" class="js">spp = sp.prototype;
sb.superclass=spp;

 if(spp.constructor == Object.prototype.constructor){
                     spp.constructor=sp;
  }  </pre>
<p>&nbsp;同上文中关于语句2处设置子类superclass一样，此处sb的superclass属性设置为了spp，其父类sp的prototype对象。此时，若想访问到父类本身，就只能通过spp的constructor属性。因此，才需要对constructor属性进行判断，将其重置为父类sp。也即，加入此语句的原因是为了能够<span style="color: #ff0000;">保证在子类中正确调用到父类的构造函数</span>
，而不是Object。</p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://lionheart.javaeye.com/blog/232776#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;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 26 Aug 2008 12:34:28 +0800</pubDate>
        <link>http://lionheart.javaeye.com/blog/232776</link>
        <guid>http://lionheart.javaeye.com/blog/232776</guid>
      </item>
      <item>
        <title>javascript 执行模型的一些测试</title>
        <author>lionheart</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lionheart.javaeye.com">lionheart</a>&nbsp;
          链接：<a href="http://lionheart.javaeye.com/blog/231260" style="color:red;">http://lionheart.javaeye.com/blog/231260</a>&nbsp;
          发表时间: 2008年08月21日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>一 <strong>js的扫描过程</strong>
</p>
<p>&nbsp;&nbsp;&nbsp; js在执行代码之前，会有一个扫描（相当于预编译）的过程，这一过程用于获取定义的变量名和函数对象。主要包括如下几个处理步骤：</p>
<ol>
<li>碰到了&ldquo;var instance=xxx;&rdquo; 这样的语句时，则在当前variable object上添加此属性，赋初值为undefined</li>
<li>碰到了函数的定义&quot;function func(){}&quot;时，则使用此函数定义创建相应的函数对象，然后在varable object对象上添加此属性func，其值为返回的函数对象。<br />
</li>
</ol>
<p>&nbsp;&nbsp;&nbsp; 下面来举例分析这一过程。</p>
<pre name="code" class="js">// a
var local_v = &quot;local v&quot;;
global_v = &quot;global v&quot;;

alert(local_v);    // 1
alert(global_v); // 2     
  

// b
function func1(){
      alert(local_v);
}

var func2 = function(){
      alert(local_v);
}

func1();  //3
func2();  //4

</pre>
<p>上面这些代码的执行过程如下：</p>
<ol>
<li>初始化Global Object即window对象，Variable Object为window对象本身。</li>
<li>扫描源代码，在window对象上添加了 local_v 和 func2 属性，值都为undefined。添加了func1属性，值为该定义返回的函数对象。</li>
<li>执行源代码，将local_v属性赋值为 &ldquo;local v&rdquo;，在global object 对象上加上属性&nbsp; global_v 并赋值为&ldquo;global v&rdquo;。</li>
<li>正确打印出 local_v&nbsp; 和 global_v 的值<br />
</li>
<li>创建匿名函数对象，并将其值赋给&ldquo;func2&rdquo;属性。</li>
<li>执行func1()函数，打印出local_v属性的值。</li>
<li>执行func2()函数，打印出local_v属性的值。</li>
</ol>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 在这一分析的基础上，我们将上述代码中的1，2移到a上面；将3，4移到b上面，然后再一次执行。此时，第1条语句打印出的结果是&quot;undefined&quot;，而执行第2条语句时浏览器报错&quot;global_v is not defined&quot;。这是因为window对象上已经有local_v属性了，只是没有显示赋值；而global_v属性此时还不存在；同理，第3条语句正确输出了结果；而第4条语句则报错&quot;func2 is not a function&quot;。因为此时func1已经赋值为函数对象；而func2却没有。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 理解了js的这一执行模型，则能够正确回答出一些容易混淆的问题，比如如下的代码：</p>
<pre name="code" class="js">var x='global';
document.writeln(x);   // 1
func();

function func(){
    var x='func';
    function inner(){
       document.writeln(x);   // 2
       var x='inner';
       document.writeln(x);  // 3
    }
    inner();
    document.writeln(x);  // 4
} </pre>
&nbsp;
<p>如上所示，如果对执行模型不是很清楚的话，很可能会以为第2条语句会输出&quot;func&quot;或者&quot;inner&quot;。</p>
<p>正确的输出结果应该是：&nbsp; <span style="color: #0000ff;">global&nbsp;&nbsp;&nbsp; undefined&nbsp;&nbsp;&nbsp; inner&nbsp;&nbsp; func</span>
。 第2条语句在执行之前，inner函数内的 variable object上用新的x属性值替代了scope chain上在func函数内的属性值，新值因为在此语句处还未赋值，故打印出的结果是&quot;undefined&quot;</p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://lionheart.javaeye.com/blog/231260#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;">北京: 千橡集团暨校内网诚聘软件研发工程师</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>Thu, 21 Aug 2008 17:15:46 +0800</pubDate>
        <link>http://lionheart.javaeye.com/blog/231260</link>
        <guid>http://lionheart.javaeye.com/blog/231260</guid>
      </item>
      <item>
        <title>mysql query cache</title>
        <author>lionheart</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lionheart.javaeye.com">lionheart</a>&nbsp;
          链接：<a href="http://lionheart.javaeye.com/blog/200705" style="color:red;">http://lionheart.javaeye.com/blog/200705</a>&nbsp;
          发表时间: 2008年06月05日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>1. <span style="color: #0000ff;"><strong>works with Transactions</strong>

</span>

</p>
<div class="quote_title">http://www.mysqlperformanceblog.com/2008/01/29/how-mysql-query-cache-works-with-transactions/ 写道</div>
<div class="quote_div">The result set can be retrieved from query cache (for statements both inside and outside of transactions) until there is a statement inside transactions which modifies the table.<span style="color: #ff6600;"> <span style="background-color: #00ffff; color: #000000;">As soon as table is modified in transaction it becomes uncachable by query cache until that transaction is committed.</span>

</span>

<span style="background-color: #00ffff;"> </span>

Not only query cache can&rsquo;t be used inside the same transaction which modified data but also in other concurrent transactions which do not even see the changes done yet. </div>
<div class="quote_div">With current approach Innodb can probably do something as simple as
marking table &ldquo;<span style="color: #0000ff;">uncachable</span>

&rdquo; if it has any uncommitted changed which
would take care about all complicated aspects of change visibility in
different transaction modes.</div>
<p>&nbsp;</p>
<pre name="code" class="sql">transaction 1 :
start transaction;
select count(*) from parent;  //  result: 1   QCache_hits : 0
select count(*) from parent;  //  result: 1   QCache_hits : 1

transaction 2 :
start transaction;
select count(*) from parent;  //  result: 1   QCache_hits : 2
insert into parent(name) values('new');
select count(*) from parent;  //  result: 2   QCache_hits : 2

transaction 1 :
select count(*) from parent;  // <span style="background-color: #ffff00;"> result: 1   QCache_hits : 2</span>




transaction 2 :
commit;

transaction 1 :
select count(*) from parent;  //  <span style="background-color: #ffff00;">result: 1   QCache_hits : 2</span>

commit;
select count(*) from parent;  //  <span style="background-color: #ffff00;">result: 2   QCache_hits : 2</span>



select count(*) from parent;  //  result: 2   QCache_hits : 3

transaction 2 :
select count(*) from parent;  //  result: 2   QCache_hits : 4</pre>
&nbsp;
<p>&nbsp;the experiment result perfectly explains&nbsp; the mechanism of mysql cache query with transactions.</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>2. <strong><span style="color: #0000ff;">WhiteSpace and comments</span>
</strong>
</p>
<div class="quote_title">http://www.mysqlperformanceblog.com/2008/03/20/mysql-query-cache-whitespace-and-comments/ 写道</div>
<div class="quote_div">You can have whitespace in the start and you can have leading comment and it all works. However the comment which is inside the query works interesting way - <span style="background-color: #00ffff;">the queries with different comments are both treated as same query if only comment is different.</span>
 However if you <span style="background-color: #00ffff;">change whitespace a bit </span>
(see the last query has space after comment deleted) it causes query cache miss.<strong></strong>
</div>
<div class="quote_div"><strong>Whitespace at the start of query does not block query from being cached</strong>
. Moreover query with 2 spaces in front is considered same as query with 3 spaces in front<strong></strong>
</div>
<div class="quote_div"><strong>Comment at the start of the query does not block query from being cached.</strong>
However queries with different comments are considered different
queries (it is not stripped before hashing) - so you should not put
things like current time in such a comment.<strong></strong>
</div>
<div class="quote_div"><strong>Comments inside the query also matter.</strong>
 Meaning if you place comments inside the query or in the end.  Though this was always the case </div>
&nbsp;
<pre name="code" class="sql">select count(*) from parent;  //  QCache_hits : 0
select count(*) from parent;  //  QCache_hits : 1
/*comment*/ select count(*) from parent;  //  QCache_hits : 2             //  whitespace and comment at the start of query 
/*newcomment*/ select count(*) from parent;  //  QCache_hits : 3      //   does not block query from
/*comment*/select count(*) from parent;  //  QCache_hits : 4              //   being cached.

select /*comment*/ count(*) from parent;  //  QCache_hits : 4             // comments inside
select /*new comment*/ count(*) from parent;  //  QCache_hits : 5

select /*comment*/count(*) from parent;  //  QCache_hits : 5         // no whitespace between count(*) and comments.
select /*newcomment*/count(*) from parent;  //  QCache_hits : 6

select /*comment*/   count(*) from parent;  //  QCache_hits : 6      // one more whitespace before count(*)</pre>
&nbsp;
<p>&nbsp;</p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://lionheart.javaeye.com/blog/200705#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;">北京: 千橡集团暨校内网诚聘软件研发工程师</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>Thu, 05 Jun 2008 22:09:03 +0800</pubDate>
        <link>http://lionheart.javaeye.com/blog/200705</link>
        <guid>http://lionheart.javaeye.com/blog/200705</guid>
      </item>
      <item>
        <title>javascript object model</title>
        <author>lionheart</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lionheart.javaeye.com">lionheart</a>&nbsp;
          链接：<a href="http://lionheart.javaeye.com/blog/197149" style="color:red;">http://lionheart.javaeye.com/blog/197149</a>&nbsp;
          发表时间: 2008年05月26日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><strong>the difference between <span style="color: #0000ff;">prototype property</span>
 and <span style="color: #0000ff;">[[prototype]] which</span>
 <span style="color: #0000ff;">constructs</span>
 <span style="color: #0000ff;">the chain of prorotype</span>
</strong>
</p>
<ol>
<li>each object has a inner property called '<span style="color: #0000ff;">[[prototype]]</span>
', whose value is null or point to some object. This property is visible only for JS engine.(in firefox, this property can visited by name '<span style="background-color: #00ffff; color: #000000;">__proto__</span>
' in js code)<br />
</li>
<li>each <span style="color: #ff6600;">Function object</span>
 has a explicit property called '<span style="color: #0000ff;">prototype</span>
'</li>
<li>the steps of finding a property <em>property_name</em>
 in an object <em>obj</em>
 : <br />
<div class="quote_title"> </div>
<div class="quote_div">1. return the value of <em>obj.property_name</em>
 if <em>obj</em>
 has the property.<br />
2. return undefined if <em>obj</em>
.__proto__ is null<br />
3. return the value of <em>obj</em>
.__proto__.<em>property_name</em>
</div>
</li>
<li>let's take an example to view the values of the two properties&nbsp; in&nbsp; some&nbsp; objects with different types.
<pre name="code" class="js">function func(){}

var func_instance = new func();
var obj_instance = new Object();
</pre>
&nbsp;we created three objects: a Function object func, an object func_instance created by func and an object obj_instace created by Object. By default, the prototype property of func is point to an object whose&nbsp; constructor property is point to func itself (it means <span style="background-color: #ffff00;">func.prototype.constructor == func</span>
),&nbsp; so the chain of [[prototype]] of the object created by func is point to <span style="color: #0000ff;">Object.prototype</span>
; the [[prototype]] property is assigned to <span style="color: #0000ff;">Function.prototype</span>
.&nbsp; The proptotype property of func_instance is undefined, and the [[prototype]] property is the value of <span style="color: #0000ff;">func.prototype</span>
. The obj_instance is mostly the same as func_instance, but the value of [[prototype]] is depended on the type of obj_instance. For example, if the expression is <br />
<pre name="code" class="js">var str = new Object('str');</pre>
&nbsp;then the value is the <span style="color: #ff6600;">built-in String constructor</span>
; if the expression is <br />
<pre name="code" class="js">var num = new Object(123);</pre>
&nbsp;then the value is the <span style="color: #ff6600;">built-in Number constructor</span>
. if&nbsp; <span style="background-color: #c0c0c0;">new Object()</span>
 is used , then the value is the <span style="color: #ff6600;">built-in Object  constructor.&nbsp;</span>
 </li>
</ol>
<p><span style="font-size: small;"><strong>the process of creating an object.</strong>
</span>
(<span style="background-color: #c0c0c0;">var f = new func();</span>
 as example)</p>
<ol>
<li>create an object obj of built-in Object constructor and initialize it.</li>
<li>if the type of func.prototype is Object, then set the [[prototype]] property of f to it. otherwise set the value to initialization, namely, <span style="color: #ff6600;"><span style="color: #0000ff;">Object.prototype</span>
. <br />
</span>
</li>
<li><span style="color: #ff6600;"><span style="color: #000000;">regard obj as this, and call the inner [[call]] method of func with the arguments.</span>
</span>
<ol>
<li><span style="color: #ff6600;"><span style="color: #000000;">the [[call]] method creates the execution context.</span>
</span>
</li>
<li><span style="color: #ff6600;"><span style="color: #000000;">invoke the body of func.</span>
</span>
</li>
<li><span style="color: #ff6600;"><span style="color: #000000;">destroy the execution context.</span>
</span>
</li>
<li style="background-color: #00ffff;"><span style="color: #ff6600;"><span style="color: #000000;">return the value of func if exists, otherwise return undefined.</span>
</span>
</li>
</ol>
</li>
<li><span style="color: #ff6600;"><span style="color: #000000;"><span style="background-color: #00ffff;">return the return value of [[call]] method if the type of value is Object, otherwise return obj.</span>
</span>
</span>
</li>
</ol>
<p><span style="color: #ff6600;"><span style="color: #000000;"><span style="background-color: #00ffff;"><span style="background-color: #ffffff;">from the fourth step, we kown that f maybe is not&nbsp; the instance of func but of Object, and the result depends on the return value of func. an example shows the two situation:</span>
</span>
</span>
</span>
</p>
<pre name="code" class="js">function  func1(){}
function func2(){return {var1:'var1'};}

var instance1 = new func1();
var instance2 = new func2();

alert(instance1.constructor); // function func1(){}
alert(instance2.constructor); // function Object(){...}

alert(instance1 instanceof func1); // true
alert(instance2 instanceof func2); // false</pre>
<p>&nbsp;
one point should notice here is that all objects created by the same function share the same [[prototype]] chain. So each object can only read the property in the [[prototype]] chain, the operation of write&nbsp; will&nbsp; result in the creation of a new local prototype with the same name. let's look the following example:</p>
<pre name="code" class="js">function  func1(){}
function func2(){return {var1:'var1'};}


function func1(){}

function func2(){this.prop = &quot;prop in func2&quot;}

func1.prototype = new func2();

var ins1 = new func1();  
var ins2 = new func2();  

alert(ins1.prop);  // prop in func2
alert(ins2.prop);  // prop in func2

ins1.prop = &quot;prop changed by ins1&quot;;

alert(ins1.prop);  // prop changed by ins1
alert(ins2.prop);  // prop in func2

</pre>
&nbsp;
<p><span style="font-size: small;"><strong>the process of creating an Function object.</strong>
</span>
(take <span style="background-color: #c0c0c0;">var fn = funcion(args){...};</span>
 as example)</p>
<ol>
<li>create an object fn of the built-in Object constructor.</li>
<li>assign the value of [[prototype]] property of fn to <span style="color: #ff6600;">Function.prototype</span>
.</li>
<li>set the inner [[call]] property, which is an inner implemented method.</li>
<li>set the inner [[construct]] property, which is also an inner impelmented method.</li>
<li>set fn.length to args.length, or set to 0 if doesnt specify arguments</li>
<li>create an object fnProto using the same logic as <span style="background-color: #c0c0c0;">new Object();</span>
</li>
<li><span style="background-color: #00ffff;">set fnProto.constructor to fn</span>
.</li>
<li><span style="background-color: #00ffff;">set fn.prototype to fnproto</span>
.</li>
<li>return fn. <br />
</li>
</ol>
<p>By default, from the seventh and eighth steps, the prototype of fn(any <span style="color: #ff6600;">user defined function</span>
) is set to an instance of Object, so the object created by fn has a chain of [[prototype]] which points to Object.prototype. But the behavior can be changed by explicit setting the prototype of fn. here is an example:</p>
<pre name="code" class="js">function func1(){}
function func2(){}

func2.prototype = new func1();

var ins2 = new func2();
alert(ins2.constructor); // function func1(){}
alert(func2.prototype.constructor); // function func1(){}</pre>
&nbsp;
<p><span style="font-size: small;"><strong><span style="background-color: #ffffff;">the picture of javascript object model</span>
</strong>
<span style="background-color: #ffffff;">(<span style="font-size: small;">quote from <a href="http://www.cnblogs.com/RicCC">http://www.cnblogs.com/RicCC</a>
</span>
)</span>
</span>
</p>
<p><img src="http://www.cnblogs.com/images/cnblogs_com/riccc/js/js_object_model.jpg" height="451" alt="" style="vertical-align: middle;" width="641" />
</p>
<p>the picture tell us that :</p>
<p>1. <span style="background-color: #00ffff;">Object.prototype is the end of the chain of [[prototype]]</span>
, and <span style="background-color: #00ffff;">the [[prototype]] of Object.prototype is null</span>
.</p>
<p>2. the chain of [[prototype]] of all function is point to Function.prototype</p>
<p>3. <span style="background-color: #00ffff;">the chain of [[prototype]] of Function point to Function.prototype</span>
.</p>
<p>4. <span style="background-color: #00ffff;">the chain of [[prototype]] of Function.prototype is point to Object.prototype</span>
.</p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://lionheart.javaeye.com/blog/197149#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;">北京: 千橡集团暨校内网诚聘软件研发工程师</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, 26 May 2008 17:39:00 +0800</pubDate>
        <link>http://lionheart.javaeye.com/blog/197149</link>
        <guid>http://lionheart.javaeye.com/blog/197149</guid>
      </item>
      <item>
        <title>some thoughts of composite &amp; visitor pattern</title>
        <author>lionheart</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lionheart.javaeye.com">lionheart</a>&nbsp;
          链接：<a href="http://lionheart.javaeye.com/blog/196187" style="color:red;">http://lionheart.javaeye.com/blog/196187</a>&nbsp;
          发表时间: 2008年05月23日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>At first, let's look the typical class structure diagram of composite pattern:</p>
<p>&nbsp;</p>
<p><span style="color: #ff0000;">Composite pattern</span>
 is very suitable for Tree structure. The picture showed above defines a Interface Node and two sub concrete tree types&nbsp; : Leaf&nbsp; and Branch.&nbsp;  Branch may contains sub branch and leaf. The sample codes for the example are listed below:</p>
<pre name="code" class="java">public Interface Node{
       public void print();
}

public class leaf implements Node{
      public void print(){ 
             System.out.println(&quot;visit leaf...&quot;);
      }
}

public class branch implements Node{
       private List&lt;Node&gt; subNodes;

       public void addSubNode(Node subNode){}

       public void removeSubNode(Node subNode){}

       public void print(){
          for(Node node : subNodes){
               node.print();
          }
       }
}
</pre>
<p>&nbsp;The code is so unpractical that the print method just show its node type. In a general way,&nbsp; the requirement might&nbsp; extended in two directions respectively:&nbsp;</p>
<ul>
<li>add new method for each node</li>
<li>add new node type in tree hierarchy.</li>
</ul>
<p>under the first situation,&nbsp; if we need print the number of&nbsp; sub nodes&nbsp; for each node, the easiest way, also the only way, is to&nbsp; change the print method and plus new logic. That is to say, we need to modify the existed system to satisfy new requirement, which violate the <span style="color: #0000ff;">open-closed principle</span>
 of OOD. So, how can we do it with a&nbsp; better way? May be a available method is to seperate the hebavior from the node class, namely introduce new class to response for behavior, and node class only contains state data.&nbsp; So now, it is time that <span style="color: #ff0000;">visitor pattern</span>
 show its power.</p>
<p>the class diagram of visitor pattern as follows:</p>
<p>Compare to the diagram of composite pattern.&nbsp; it has several extra classes : an integerface Visitor and class PrintVisitor. these classes provide the operation to visit nodes. The sample codes listed below:</p>
<pre name="code" class="java">public Interface Node{
       public void print();
       public void accept(Visitor v);
}

public class leaf implements Node{
      public void print(){ 
             System.out.println(&quot;visit leaf...&quot;);
      }
      public void accept(Visitor v){
             v.visit(this); 
      }
}

public class branch implements Node{
       private List&lt;Node&gt; subNodes;

       public void addSubNode(Node subNode){}

       public void removeSubNode(Node subNode){}

       public void print(){
          for(Node node : subNodes){
               node.print();
          }
       }
       public void accept(Visitor v){
             v.visit(this); 
      }
}

public interface Visitor{
      public void visit(Leaf leaf);
      public void visit(Branch branch);
}

public class PrintVisitor implements Visitor{
     public void visit(Leaf leaf){
            leaf.print();
     }
     public void visit(Branch branch){
            branch.print();
     }
} </pre>
<p>&nbsp;Now, we can simply add a new 'visitor' class to extent node behavior, and need not any modification of existed system.&nbsp; Visitor pattern works wonderfully here, but it also has some limitation.</p>
<ol>
<li>it only suitable for extending node behavior, not&nbsp; for adding new node type in tree hierarchy. This is the fatal defect of visitor pattern. Just as we see from the simple codes,&nbsp; a Visitor encapsulate the behavior of all nodes. So if one more node type is added, the vistor interface and all concrete classes need be modified to add corresponding behavior. Luckily, A variant of visitor pattern called <span style="color: #ff0000;">'acyclic visitor' pattern(avp for short)</span>
 may solve the problem. The main idea of avp is make the Vistor Interface to be a <span style="color: #0000ff;">Marker Interface<span style="color: #000000;">, and create an corresponding visitor interface for each node type</span>
<span style="color: #000000;">.</span>
<span style="color: #000000;"> So the codes using avp may looks like that:</span>
</span>
<pre name="code" class="java">public Interface Node{
       public void print();
       public void accept(Visitor v);
}

public class leaf implements Node{
      public void print(){ 
             System.out.println(&quot;visit leaf...&quot;);
      }
      public void accept(Visitor v){
             LeafVisitor lv = (LeafVisitor)v;
             lv.visit(this); 
      }
}

public class branch implements Node{
       private List&lt;Node&gt; subNodes;

       public void addSubNode(Node subNode){}

       public void removeSubNode(Node subNode){}

       public void print(){
          for(Node node : subNodes){
               node.print();
          }
       }
       public void accept(Visitor v){
             BranchVisitor lv = (BranchVisitor)v;
             bv.visit(this); 
      }
}

public interface Visitor{}

public interface LeafVisitor{
     public void visit(Leaf leaf);
}

public interface BranchVisitor{
    public void visit(Branch branch);
}

public class PrintVisitor implements Visitor,LeafVisitor,BranchVisitor{
     public void visit(Leaf leaf){
            leaf.print();
     }
     public void visit(Branch branch){
            branch.print();
     }
} 
</pre>
&nbsp;In the 'accpet' method of class node class,&nbsp; firstly, using up-casting, changes the argument to the visitor interface correspond with the node type. if success, then invokes the 'visit' method of the visitor.<br />
</li>
</ol>
          <br/><br/>
          <span style="color:red;">
            <a href="http://lionheart.javaeye.com/blog/196187#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;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 23 May 2008 17:03:21 +0800</pubDate>
        <link>http://lionheart.javaeye.com/blog/196187</link>
        <guid>http://lionheart.javaeye.com/blog/196187</guid>
      </item>
      <item>
        <title>best practices for web form design</title>
        <author>lionheart</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lionheart.javaeye.com">lionheart</a>&nbsp;
          链接：<a href="http://lionheart.javaeye.com/blog/195713" style="color:red;">http://lionheart.javaeye.com/blog/195713</a>&nbsp;
          发表时间: 2008年05月22日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>These contents are refered from a pdf file named '<span style="color: #0000ff;">best practices for web form design</span>

'.</p>
<p><span style="color: #ff0000; font-size: small;"><strong>information</strong>
</span></p>
<p><span style="color: #ff9900; font-size: x-small;"><strong>Layout</strong>

</span>

</p>
<ul>
<li>top aligned : for reduced completion times &amp; familiar data input.</li>
<li>right aligned : when vertical screen space is a constraint.</li>
<li>left aligned : for unfamiliar, or advanced data entry.</li>
</ul>
<p><strong><span style="color: #ff9900;">Required Form Fields</span>
</strong>
</p>
<ul>
<li>try to avoid optional fileds.</li>
<li>indicate optional fields: if mosts fields are required.</li>
<li>indicate required fields: if mosts fields are optional.</li>
<li>Text is best, but * often&nbsp; works for required fields.</li>
<li>Associate indicators with labels.</li>
</ul>
<p><strong><span style="color: #ff9900;">Field Lengths</span>
</strong>
</p>
<ul>
<li>when possible, use field length as an affordance.</li>
<li>otherwise consider a consistent length that provides enough room for inputs.</li>
</ul>
<p><strong><span style="color: #ff9900;">Content Grouping</span>
</strong>
</p>
<ul>
<li>use relevant content groupings to organize forms.</li>
<li>use the minimum amount of visual elements necessary to communicate useful relationships.</li>
</ul>
<p><strong><span style="color: #ff9900;">Action</span>
</strong>
</p>
<ul>
<li>avoid secondary actions if possible</li>
<li>otherwise, ensure a clear visual distinction between primary &amp; secondary actions.</li>
</ul>
<p><strong><span style="color: #ff9900;">Help &amp; Tips</span>
</strong>
</p>
<ul>
<li>minimize the amount of help &amp; tips required to fill out a form</li>
<li>help visible and adjacent to a data request is most useful</li>
<li>when lots of unfamiliar data is being requested, consider using a dynamic help system.</li>
</ul>
<p><strong><span style="color: #ff0000; font-size: small;">interaction</span>
</strong></p>
<p><strong><span style="color: #ff9900;">path to completion</span>
</strong>
</p>
<ul>
<li>remove all unnecessary data requests</li>
<li>enable smart defaults</li>
<li>employ flexible data entry</li>
<li>illuminate a clear path to completion</li>
<li>for long forms, show progress &amp; save.</li>
</ul>
<p><strong><span style="color: #ff9900;">tabbing</span>
</strong>
</p>
<ul>
<li>remember to account for tabbing behavior</li>
<li>use the tabindex attribute to control tabbing order</li>
<li>consider tabbing expectations when laying out forms.</li>
</ul>
<p><strong><span style="color: #ff9900;">progressive disclosure</span>
</strong>
</p>
<ul>
<li>map progressive disclosure to prioritized user needs.</li>
<li>most effective when user-initiated.</li>
<li>maintain a consistent approach.</li>
</ul>
<p><strong><span style="color: #ff9900;">exposing dependent inputs</span>
</strong>
</p>
<ul>
<li>maintain clear relationship between initial selection options</li>
<li>clearly associate additional inputs with their trigger</li>
<li>avoid 'jumping' that disassociates initial selection options.</li>
</ul>
<p><span style="color: #ff0000; font-size: small;"><strong>feedback</strong>
</span>
</p>
<p><strong><span style="color: #ff9900;">inline validation</span>
</strong>
</p>
<ul>
<li>use inline validation for inputs have potentially high error rates.</li>
<li>use suggested inputs to disambiguate</li>
<li>communicate limits.</li>
</ul>
<p><span style="color: #ff9900;"><strong>Errors</strong>
</span>
</p>
<ul>
<li>clearly communicate an error has occurred: top placement, visual contrast</li>
<li>provide actionable remedies to correct errors.</li>
<li>associate responsible fields with primary error message</li>
<li>'Double' the visual language where errors have occurred.</li>
</ul>
<p><span style="color: #ff9900;"><strong>progress</strong>
</span>
</p>
<ul>
<li>provide indication of tasks in progress</li>
<li>disable 'submit' button after user clicks it to avoid duplicate submissions.</li>
</ul>
<p><span style="color: #ff9900;"><strong>success</strong>
</span>
 </p>
<ul>
<li>clearly communicate a data submission has been successful</li>
<li>provide feedback in context of data submitted.</li>
</ul>
<p>&nbsp;</p>
<p><span style="font-size: small;"><strong>Three web form creation tools</strong>
</span>
</p>
<ul>
<li>wufoo http://www.wufoo.com</li>
<li>form assembly http://www.formassembly.com</li>
<li>icebrrg http://www.icebrrg.com<br />
</li>
</ul>
          <br/><br/>
          <span style="color:red;">
            <a href="http://lionheart.javaeye.com/blog/195713#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;">北京: 千橡集团暨校内网诚聘软件研发工程师</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>Thu, 22 May 2008 16:29:39 +0800</pubDate>
        <link>http://lionheart.javaeye.com/blog/195713</link>
        <guid>http://lionheart.javaeye.com/blog/195713</guid>
      </item>
      <item>
        <title>InnoDB transaction model</title>
        <author>lionheart</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lionheart.javaeye.com">lionheart</a>&nbsp;
          链接：<a href="http://lionheart.javaeye.com/blog/195406" style="color:red;">http://lionheart.javaeye.com/blog/195406</a>&nbsp;
          发表时间: 2008年05月21日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>At first, lst's understand some technologies used in mysql transaction model:</p>
<p>1. <span style="color: #ff0000;"><strong>Next-Key Locking</strong>
</span>
</p>
<div class="quote_title">http://dev.mysql.com/doc/refman/5.0/en/innodb-next-key-locking.html 写道</div>
<div class="quote_div">InnoDB performs the row-level locking in such a way that when it searches or scans an index of a table, it sets shared or exclusive locks on the index records it encounters. <br />
<br />
The next-key locks that InnoDB sets on index records also affect the &ldquo;gap&rdquo; before that index record. If a user has a shared or exclusive lock on record R in an index, another user cannot insert a new index record immediately before R in the index order. </div>
<p>&nbsp;from the introduction, we kown that the next-key locking is the composite of normal lock and 'gap' lock. Besides locks the selected records, it also locks the 'gap'&nbsp; the range index scan iterated in the index order.&nbsp; The explaination may obscure. So i am going to take an example to illustrate it.</p>
<p>There are my testing environment:</p>
<div class="quote_div">window xp sp2<br />
Mysql 5.0.20<br />
<br />
create table parent<br />
(<br />
  `id` int(11) NOT NULL auto_increment,<br />
  `name` varchar(50) default NULL,<br />
  PRIMARY KEY  (`id`)<br />
) ENGINE=InnoDB DEFAULT CHARSET=utf8;</div>
<div class="quote_div">INSERT INTO `parent` VALUES (3,'p3'),(5,'p5');</div>
<p>(1) in the transaction one(T1 for short) execute the following SQL:</p>
<div class="quote_div">select * from parent where id &gt; 2 for update;</div>
<p>&nbsp;the records 3 and 5 will be displayed. </p>
<p>Then, in the transaction two(T2 for short) execute an update sql :</p>
<div class="quote_div">update parent set name = 'newp3' where id=3;</div>
<p>&nbsp;If allthings goes well,&nbsp; an error message will displayed after several seconds :</p>
<div class="quote_div">ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction</div>
<p>&nbsp;Than , execute three insert sql:</p>
<div class="quote_div">insert into parent values(1,'p1');</div>
<div class="quote_div">insert into parent values(2,'p2');<br />
insert into parent values(4,'p4');</div>
<p>&nbsp;the first one execute successfully and the others are fail with the same error message as listed above.</p>
<p>(2) restore the records,&nbsp; and change the sql executed in T1 to :</p>
<div class="quote_div">select * from parent where id &lt; 3 for update;</div>
<p>&nbsp;then the same three sql in T2 executed again. the result reverse : the first two fail and the last success.</p>
<p>(3) restore the records, then in T1 execute:</p>
<div class="quote_div">select * from parent where id = 3 for update;</div>
<p>&nbsp;after that, execute the following in T2:</p>
<div class="quote_div">insert into parent values(2,'p2');<br />
update parent set name='new' where id=3;<br />
insert into parent values(4,'p4');</div>
<p>&nbsp;The result is the two insert sql success and the rest fail.</p>
<p>From the results of&nbsp; three different&nbsp; condition,&nbsp; I think we can clearly realize the meaning of 'gap' lock and&nbsp; rows actually be locked.</p>
<p>2. <strong><span style="color: #ff0000;">Consistent Read</span>
</strong>
</p>
<div class="quote_title">http://dev.mysql.com/doc/refman/5.0/en/innodb-consistent-read.html 写道</div>
<div class="quote_div">A consistent read means that InnoDB uses multi-versioning to present to a query a snapshot of the database at a point in time. <span style="background-color: #ff6600;">The query sees the changes made by those transactions that committed before that point of time,</span>
 and no changes made by later or uncommitted transactions. <br />
<br />
If you are running with the default REPEATABLE READ isolation level, all consistent reads within the same transaction read the <span style="color: #0000ff;">snapshot </span>
established by the first such read in that transaction. <br />
<br />
Consistent read is the <span style="background-color: #ff6600;">default mode</span>
 in which InnoDB <span style="background-color: #ff6600;">processes SELECT  statements</span>
 in <span style="color: #0000ff;">READ COMMITTED</span>
 and <span style="color: #0000ff;">REPEATABLE READ</span>
 isolation levels. A consistent read does not set any locks on the tables it accesses</div>
<div class="quote_div"><code class="literal">InnoDB</code>
 uses a consistent read <span style="background-color: #ff6600;">for select in
        clauses</span>
 like <code class="literal">INSERT INTO ... SELECT</code>
 and
        <code class="literal">UPDATE ... (SELECT)</code>
 that do not specify
        <code class="literal">FOR UPDATE</code>
 or <code class="literal">IN SHARE
        MODE</code>
 if the
        <code class="literal">innodb_locks_unsafe_for_binlog</code>
 option is set
        and the isolation level of the transaction is not set to
        serializable.</div>
<p>&nbsp;</p>
<p><span style="color: #000000; font-size: small;"><strong>Four transaction levels supported by mysql</strong>
</span>
 </p>
<p>1. <span style="color: #ff0000;"><code class="literal">READ UNCOMMITTED</code>
</span>
</p>
<div class="quote_div">SELECT statements are performed in a non-locking fashion, <br />
may occur the problem of <span style="color: #0000ff;">'dirty read'</span>
.</div>
<p>2. <span style="color: #ff0000;"><code class="literal">READ COMMITTED</code>
</span>
</p>
<div class="quote_div">All SELECT ... FOR UPDATE and SELECT ... LOCK IN SHARE MODE statements lock only the index records, not the gaps before them<br />
<br />
UPDATE and DELETE  statements using a unique index with a unique search condition lock only the index record found<br />
<br />
In range-type UPDATE and DELETE statements, InnoDB must set next-key or gap locks <br />
</div>
<p>&nbsp;3. <span style="color: #ff0000;"><code class="literal">REPEATABLE READ</code>
</span>
</p>
<div class="quote_div">SELECT ... FOR UPDATE, SELECT ... LOCK IN SHARE MODE, UPDATE, and DELETE statements that use a unique index with a unique search condition lock only the index record found<br />
<br />
With other search conditions, these operations employ next-key locking</div>
<p>&nbsp;4. <span style="color: #ff0000;"><code class="literal">SERIALIZABLE</code>
</span>
</p>
<div class="quote_div">This level is like REPEATABLE READ, but InnoDB implicitly converts all plain SELECT statements to SELECT ... LOCK IN SHARE MODE.</div>
<p>&nbsp;In the rest of the article, i will concentrate on the two widely used isolation levels : <span style="color: #ff0000;"><code class="literal">READ COMMITTED(RC for short) <span style="color: #000000;">and </span>
</code>
</span>
<span style="color: #ff0000;"><code class="literal">REPEATABLE READ(rr for short). <span style="color: #000000; font-size: small;">introduce their characteristic compare their difference.</span>
</code>
</span>
</p>
<p>(1) &nbsp;&nbsp;&nbsp; from the introducation of consistent read above, we kown that&nbsp;  it is the default mode of the two isolation levels to process SELECT statment. But there is an important different&nbsp; between them :&nbsp; the consistent read , in RR, with the same transaction always read the same snapshot&nbsp; established by the first of read; in contrast, each consistent read <span style="background-color: #00ffff;">set and reads its own fresh snapshot.<span style="background-color: #ffffff;"> in RC. Let's make an experiment.</span>
</span>
</p>
<div class="quote_title"> </div>
<div class="quote_div">In RR:<br />
<br />
T1 : <br />
start transaction;<br />
select * from parent;  // list  1,3,5<br />
T2: <br />
start transaction;<br />
select * from parent;  // list 1,3,5<br />
delete from parent where id=5;&nbsp; commit; <br />
select * from parent;  // list 1,3<br />
T1:<br />
select * from parent;  //also list  1,3,5</div>
<div class="quote_div">In RR:<br />
<br />
T1 :<br />
start transaction;<br />
T2:<br />
start transaction;<br />
select * from parent; // list 1,3,5<br />
delete from parent where id=5;  <br />
select * from parent; // list 1,3<br />
commit;<br />
T1:<br />
select * from parent; // list 1,3</div>
<p>&nbsp;The different results of the two situation make it clear that every consistent read always read the snapshot established <span style="background-color: #00ffff;">in the time point the first read executed.</span>
 So only the operation result of&nbsp; transaction&nbsp; committed&nbsp; before it can be seen.</p>
<div class="quote_div">In RC:<br />
<br />
T1 :<br />
start transaction;<br />
select * from parent; // list 1,3,5<br />
T2:<br />
start transaction;<br />
select * from parent; // list 1,3,5<br />
delete from parent where id=5;<br />
select * from parent; // list 1,3<br />
commit;<br />
T1:<br />
select * from parent; // list 1,3<br />
T2:<br />
start transaction;<br />
select * from parent; // list 1,3<br />
delete from parent where id=3;<br />
select * from parent; // list 1<br />
commit;<br />
T1:<br />
select * from parent; // list 1</div>
<p>&nbsp;Obviously, each consistent read fresh its snapshot and see the lastest committed result.</p>
<p>(2)&nbsp;&nbsp; &nbsp;&nbsp; different lock mechanism is used for SELECT ... FOR UPDATE and SELECT ... LOCK IN SHARE MODE statements in RC.</p>
<div class="quote_div">In RC:<br />
<br />
T1:<br />
select * from parent;  // list 1,3,5<br />
select * from parent where id &gt; 2 for update;  // list 3,5<br />
T2:<br />
select * from parent;  // list 1,3,5<br />
update parent set name='xxx' where id=3; // error<br />
insert into parent values(4,'p4'); //success<br />
select * from parent;  // list 1,3,4,5</div>
<p>&nbsp;Comparing the result with the example one in the first chapter,&nbsp; the insert operation here work successfully even though the record id 4 is in the scope of index 'gap' scanned by the select... for update statment. That is to say, in RC,&nbsp; the select...for update statment does not put&nbsp; 'gap' lock on table.</p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://lionheart.javaeye.com/blog/195406#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;">北京: 千橡集团暨校内网诚聘软件研发工程师</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>Wed, 21 May 2008 19:19:13 +0800</pubDate>
        <link>http://lionheart.javaeye.com/blog/195406</link>
        <guid>http://lionheart.javaeye.com/blog/195406</guid>
      </item>
      <item>
        <title>JSP directives &amp; standard actions</title>
        <author>lionheart</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lionheart.javaeye.com">lionheart</a>&nbsp;
          链接：<a href="http://lionheart.javaeye.com/blog/195004" style="color:red;">http://lionheart.javaeye.com/blog/195004</a>&nbsp;
          发表时间: 2008年05月20日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><span style="font-size: small;"><span style="color: #0000ff;"><strong>Three jsp directives</strong>
</span>
</span>
</p>
<p>1. the <span style="color: #ff0000;">page</span>
 directive</p>
<p style="padding-left: 30px;">first, refere the explaination of it in jsp specificiation:</p>
<div class="quote_div">the page directive defines a number of page dependent properties and communicates these to the JSP container.</div>
<p style="padding-left: 30px;">&nbsp;this directive is so common that always can&nbsp; be see in the top of JSP pages, and used just like this: </p>
<p>&nbsp;</p>
<div class="quote_div">&lt;%@ page contentType=&quot;text/html;charset=utf-8&quot; language=&quot;java&quot; %&gt;</div>
<p style="padding-left: 30px;">&nbsp; the directive above indiciates that the scripting language is based on java, and the MIME type is 'text/html' and the character encoding of output is 'utf-8'.</p>
<p style="padding-left: 30px;">Now that the directive involved the concept of encoding. i will simply explain the difference between <span style="color: #ff0000;">charset</span>
 and <span style="color: #ff0000;">pagEcoding</span>
.</p>
<p style="padding-left: 30px;">&nbsp;In jsp specificiation, the two conceptions are&nbsp; described as follows:</p>
<div class="quote_title"> </div>
<div class="quote_div"><strong>contentType </strong>
<br />
<br />
<span style="background-color: #ff6600; color: #000000;">Defines the MIME type and the character encoding for the response of the JSP page, and is also used in determining the&nbsp; character encoding of the JSP page. </span>
<br />
Values are either of the form &ldquo;TYPE&rdquo; or &ldquo;TYPE;charset= CHARSET&rdquo;with an optional white space after the &ldquo;;&rdquo;. &ldquo;TYPE&rdquo; is a MIME type, see the IANA registry at http://www.iana.org/assignments/media-types/index.html <br />
for useful values. &ldquo;CHARSET&rdquo;, if present, must be the IANA name for a character encoding. The default value for &ldquo;TYPE&rdquo; is &ldquo;text/html&rdquo; for JSP pages in standard syntax, or &ldquo;text/xml&rdquo; for JSP documents in XML syntax. If &ldquo;CHARSET&rdquo; is not specified, the response character encoding is determined as described in <br />
Section JSP.4.2, &ldquo;Response Character Encoding&rdquo;. See Chapter JSP.4 for complete details on character <br />
encodings. <br />
<br />
<br />
<strong>pageEncoding </strong>
<br />
<br />
<span style="background-color: #ff6600;">Describes the character encoding for the JSP page. </span>
The value is of the form &ldquo;CHARSET&rdquo;, which must be the IANA name for a character encoding. For JSP pages in standard syntax, the character encoding for the JSP page is the charset given by the pageEncoding attriute if it is present, otherwise the charset given by the contentType attribute if it is present, otherwise &ldquo;ISO-8859-1&rdquo;. For JSP documents in XML syntax, the character encoding for the JSP page is determined as described in section 4.3.3 and appendix F.1 of the XML specification. The pageEncoding attribute is not needed for such documents. It is a translation-time error if a document names different encodings in its XML prolog / text declaration and in the pageEncoding attribute. The corresponding JSP configuration element is page-encoding (see Section JSP.3.3.4, &ldquo;Declaring Page Encodings&rdquo;). See Chapter JSP.4 for complete details on character encodings. </div>
<p>&nbsp;as we kown,&nbsp; JSP page be compiled to servlet in the server side. the value of pageEncoding specifies the encoding would be used to compile the jsp page, otherwise, the web container will make use of the value of <span style="color: #0000ff;">file.encoding.&nbsp; <span style="color: #000000;">So 'pageEncoding' is the key factor of avoid chinese problem. if we didnt specify it,&nbsp; the application work correctly when deployed on windows would&nbsp; occur chinese character problem if was deployed on linux.&nbsp; On the other side,&nbsp; '</span>
</span>
charset<span style="color: #0000ff;"><span style="color: #000000;">' specifies the encoding of the response of the jsp page. That is to say, the server encoded the data using the encoding specified by 'charset' before sending it to client.</span>
</span>
</p>
<p>2. the <span style="color: #ff6600;">taglib</span>
 directive</p>
<p style="padding-left: 30px;">the jsp specificiation defines it as follow:</p>
<div class="quote_title"> </div>
<div class="quote_div">the taglib directive in a jsp page declares that the page uses a tag library, uniquely identifies the tag library using a URI and associates a tag prefix that will distinguish usage of the actions in the library.</div>
<p>&nbsp;typically, this directive is necessary if we wanna use JSTL and struts defined tag library in jsp page.</p>
<p>3. the <span style="color: #ff6600;">include</span>
 directive</p>
<div class="quote_title"> </div>
<div class="quote_div">the include directive is used to substitute text and/or code at JSP page<span style="background-color: #ff6600;"> translation-time</span>
.  It inserts the text of the specified resource into the page or tag file. </div>
<p>&nbsp;beside the include directive, there is also another way to do the same thing-- using the <span style="color: #ff6600;"><span style="background-color: #ffffff;">&lt;jsp:include&gt;</span>
</span>
 action.</p>
<div class="quote_title"> </div>
<div class="quote_div">A &lt;jsp:include.../&gt; action provides for the inclusion of static and dynamic resources in the same context as the current page.</div>
<p>&nbsp;So, ws the difference of the two ways ?&nbsp; Speak in breaf, the include directive would inserts the text of the included resource to the generated servlet when compiling, in contrast, the other would interpret the response of the included file, and plus it to the itself when visiting the page. In another word, the former is suitable for static resource, and the latter&nbsp; is suitable for both static and dynamic object.&nbsp; An example usage listed as follows:</p>
<div class="quote_title"> </div>
<div class="quote_div">&lt;%@ include file=&rdquo;relativeURI&rdquo;%&gt;<br />
</div>
<div class="quote_div">//the value of flush set to 'true'&nbsp;  indiciates that the buffer is flushed now.<br />
&lt;jsp:include page=&rdquo;relativeURI&rdquo; flush=&rdquo;true&rdquo; /&gt;<br />
</div>
<p>&nbsp;One important point is that the URI of file/page is relatice to the current jsp file/page. If the uri is started with symbol '/' , it means that the uri is relative to the context of web application.</p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://lionheart.javaeye.com/blog/195004#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;">北京: 千橡集团暨校内网诚聘软件研发工程师</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, 20 May 2008 20:13:45 +0800</pubDate>
        <link>http://lionheart.javaeye.com/blog/195004</link>
        <guid>http://lionheart.javaeye.com/blog/195004</guid>
      </item>
      <item>
        <title>implement url-rewrite in j2ee application</title>
        <author>lionheart</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lionheart.javaeye.com">lionheart</a>&nbsp;
          链接：<a href="http://lionheart.javaeye.com/blog/194578" style="color:red;">http://lionheart.javaeye.com/blog/194578</a>&nbsp;
          发表时间: 2008年05月19日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>in many j2ee applications, especially which developed by light-weight framework,such as struts, we can easily see the url pattern as&nbsp; follows :</p>
<div class="quote_title">写道</div>
<div class="quote_div">http://localhost:8080/app/module/action.do?id=x&amp;</div>
<p>&nbsp;In contrast, the url pattern used by ruby on rails applications are totally different:</p>
<div class="quote_title"> 写道</div>
<div class="quote_div">http://localhost:3000/app/module/action/id</div>
<p>&nbsp;Compare the two url patterns, I think most people may choose the latter, for its simplicity and beauty. Apparently, the second one reduce the usage of symbol ? and &amp;. beside that , the second one also is&nbsp; <span style="color: #0000ff;"><span style="background-color: #ffffff;">'search engine friendly'</span>
</span>
 -- it has a higher chance&nbsp; to be searched by searching engine like google. So , hao can we get way from the ugly url pattern&nbsp; in j2ee applications. the answer is : <span style="background-color: #ff9900;">url-rewrite.</span>
</p>
<p>url-rewrite is a technology that&nbsp; substitute dynamic pages for static pages. for example,&nbsp; the page /user/list.do?id=123 can be visited by url /url/list/123 if we have configured related url-rewrite rule.</p>
<p>there are two ways to implement url-rewrite in j2ee application:</p>
<ul>
<li>using proxy http server. Apache HTTP Server 2.x and mod_proxy provide the url-rewrite function.</li>
<li>except that, using the third side lib is also a good choice. such as <span style="color: #ff0000;"><big>UrlRewriteFilter.</big>
</span>
</li>
</ul>
<p><span style="color: #ff0000;"><big><span style="color: #000000;">in this topic, i will introduce the second way.(the other would be introduced serval days latter.)</span>
</big>
</span>
</p>
<p>the stepes to use <span style="color: #ff0000;"><big>UrlRewriteFilter <span style="color: #000000;">in ur app as follows:</span>
</big>
</span>
</p>
<ol>
<li>visit web site <a href="http://tuckey.org/urlrewrite/" target="_blank">http://tuckey.org/urlrewrite/</a>
&nbsp; , and downoad the latest version.</li>
<li>add the lib urlrewrite-xxx.jar to ur app web-inf/lib folder.</li>
<li>add the following to ur web-inf/web.xml: <br />
</li>
<li>
<div class="quote_div">&lt;filter&gt;<br />
       &lt;filter-name&gt;UrlRewriteFilter&lt;/filter-name&gt;<br />
       &lt;filter-class&gt;org.tuckey.web.filters.urlrewrite.UrlRewriteFilter&lt;/filter-class&gt;<br />
    &lt;/filter&gt;<br />
    &lt;filter-mapping&gt;<br />
       &lt;filter-name&gt;UrlRewriteFilter&lt;/filter-name&gt;<br />
       &lt;url-pattern&gt;/*&lt;/url-pattern&gt;<br />
    &lt;/filter-mapping&gt;</div>
</li>
<li>create the file <span style="color: #ff0000;">urlrewrite.xml</span>
 in ur app web-inf/ folder. default, urlRewriteFilter will use the file to apply rewriter rule. add the following content to urlrewrite.xml : <br />
</li>
<li>
<div class="quote_div">&lt;urlrewrite&gt;<br />
<br />
    &lt;rule&gt;<br />
    	&lt;from&gt;/([a-zA-Z]+)/([a-zA-Z]+)/([0-9]+)&lt;/from&gt;<br />
        &lt;to&gt;/$1/$2.do?id=$3&lt;/to&gt;<br />
    &lt;/rule&gt;<br />
<br />
&lt;/urlrewrite&gt;</div>
&nbsp;the rule displayed above means that any url like /user/list/123 will be rewrited to /user/list.do?id=123. <br />
</li>
<li>after all things above were done rightly. now, we can input the  /user/list/123 in browser and the url will be correctly rewrited and display related content. <br />
</li>
</ol>
<p><span style="font-size: small;"><strong><span style="color: #ff0000;">urlrewrite.xml <span style="color: #000000;">introduction</span>
</span>
</strong>
</span>
</p>
<p>urlrewrite.xml must have a root element called <span style="background-color: #ff9900;">&lt;urlrewrite&gt;&lt;/urlrewrite&gt;</span>
, and at least contains one <span style="background-color: #ff9900;">&quot;rule&quot;</span>
 element.</p>
<p><span style="background-color: #ff9900;">'rule'</span>
 element is the core of xml. a 'rule' element stand for a&nbsp; url-rewrite rule. 'rule' element must contains a<span style="background-color: #ff9900;"> 'to' </span>
and <span style="background-color: #ff9900;">'from'</span>
 element, and for some advanced application,&nbsp; also could contains the optional elements like <span style="background-color: #ff9900;">'condition' and 'set'. <span style="background-color: #ffffff;">the official site describe the process flow as follows: </span>
</span>
</p>
<div class="quote_div">When a &quot;rule&quot; is processed against an incoming request, all the &quot;condition&quot; elements must be met, then the &quot;from&quot; will be applied to the request URL and the final URL generated by applying the &quot;to&quot; to the &quot;from&quot; pattern. So long as the rule has matched then the &quot;set&quot; will be run.</div>
<p>&nbsp;the value specified in 'to' and 'from' elements must be relative to the request context, and&nbsp; can be a regular expression in the perl5 style.</p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://lionheart.javaeye.com/blog/194578#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;">北京: 千橡集团暨校内网诚聘软件研发工程师</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, 19 May 2008 21:12:54 +0800</pubDate>
        <link>http://lionheart.javaeye.com/blog/194578</link>
        <guid>http://lionheart.javaeye.com/blog/194578</guid>
      </item>
      <item>
        <title>用criteria进行关联查询</title>
        <author>lionheart</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lionheart.javaeye.com">lionheart</a>&nbsp;
          链接：<a href="http://lionheart.javaeye.com/blog/170148" style="color:red;">http://lionheart.javaeye.com/blog/170148</a>&nbsp;
          发表时间: 2008年03月11日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          问题描述如下：<br /><div class="quote_title">引用</div><div class="quote_div">两个实体 Parent(P) 和 Child(C)之间是1：N的关系，现要求符合指定条件的P及所包 含的C</div><br />采用hibernate中的Criteria来实现此功能的代码如下：<br /><pre name="code" class="java">
Criteria criteria = this.getCriteria(Parent.class);
 //连接关联子对象child，且指定了连接方式为左外连接
criteria.createAlias("children", "c", CriteriaSpecification.LEFT_JOIN));
//下面三行代码是用于获取总的记录数
criteria.setProjection(Projections.rowCount());
int size = (Integer) criteria.uniqueResult();
criteria.setProjection(null);

List results = criteria.list();
</pre><br />上面的results返回的是一个对象数组的list，数组的长度为2，依次是一个Child对象和一个Parent对象，这种返回结果的方式是所需要的；但是，倘若将中间三条获取总记录数的代码去掉，则返回是Parent对象的list，且其相关的Child子对象也没有加载进来。造成这种差别的便是 <span style="color: red">ResultTransformer</span><br />API中对 ResultTransformer 的说明如下：<br /><div class="quote_title">引用</div><div class="quote_div">Implementors define a strategy for transforming criteria query results into the actual application-visible query result list.</div><br />从上可知，criteria会使用此接口的某一实现来将查询结果转化为返回的list中实际存储的结果。criteria中的方法 <span style="color: blue">setResultTrans</span> 可用于设置所使用的转化策略。其可设置的值如下：<br /><ul><li><span style="color: red">CriteriaSpecification.ROOT_ENTITY</span>：就是一个<span style="color: red">RootEntityResultTransformer</span> 对象，其实现如下：</li><pre name="code" class="java">
public Object transformTuple(Object[] tuple, String[] aliases) {
	return tuple[ tuple.length-1 ];
}
</pre><br />由代码可知，它返回值取的是数组中的最后一个对象，也即根实体对象，在上例中就相当于返回Parent对象。<li><span style="color: red">CriteriaSpecification.DISTINCT_ROOT_ENTITY</span>：就是一个 <span style="color: red">DistinctRootEntityResultTransformer</span> 对象，它的实现与RootEntityResultTransformer相似，只是在其的基础对根实体对象进行了比较，过滤掉了其中相同的对象。</li><li><span style="color: red">CriteriaSpecification.ALIAS_TO_ENTITY_MAP</span>：就是一个<span style="color: red">AliasToEntityMapResultTransformer</span> 对象，其实现如下：</li><pre name="code" class="java">
public Object transformTuple(Object[] tuple, String[] aliases) {
	Map result = new HashMap(tuple.length);
	for ( int i=0; i&lt;tuple.length; i++ ) {
		String alias = aliases[i];
		if ( alias!=null ) {
			result.put( alias, tuple[i] );
		}
	}
	return result;
}
</pre><br />它是对数组中的每一个对象，以其别名为key，对象本身为value，构成了一个map作为返回值。<li><span style="color: red">CriteriaSpecification.PROJECTION</span>：就是一个 <span style="color: red">PassThroughResultTransformer</span> 对象，它就是简单地返回数组本身，即上例中第一种情况。</li></ul><br />Criteria中默认使用的 ResultTransformer 实现策略是 ROOT_ENTITY；但是当调用了方法 <span style="color: blue">setProjection</span>后，会隐式地将策略设置为 PROJECTION。所以，才会出现上例中的两种不同结果。如果希望返回的结果是数组形式的，则可以多加上如下这条语句：<br /><pre name="code" class="java">criteria.setProjection(null);</pre>
          <br/><br/>
          <span style="color:red;">
            <a href="http://lionheart.javaeye.com/blog/170148#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;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 11 Mar 2008 13:28:28 +0800</pubDate>
        <link>http://lionheart.javaeye.com/blog/170148</link>
        <guid>http://lionheart.javaeye.com/blog/170148</guid>
      </item>
      <item>
        <title>java序列化机制学习</title>
        <author>lionheart</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lionheart.javaeye.com">lionheart</a>&nbsp;
          链接：<a href="http://lionheart.javaeye.com/blog/139540" style="color:red;">http://lionheart.javaeye.com/blog/139540</a>&nbsp;
          发表时间: 2007年11月09日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <strong>什么是序列化</strong><br />java中的序列化(serialization)机制能够将一个实例对象的状态信息写入到一个字节流中，使其可以通过socket进行传输、或者持久化存储到数据库或文件系统中；然后在需要的时候，可以根据字节流中的信息来重构一个相同的对象。序列化机制在java中有着广泛的应用，EJB、RMI等技术都是以此为基础的。<br /><br /><strong>正确使用序列化机制</strong><br />一般而言，要使得一个类可以序列化，只需简单实现<span style="color: red">java.io.Serializable</span>接口即可。该接口是一个标记式接口，它本身不包含任何内容，实现了该接口则表示这个类准备支持序列化的功能。如下例定义了类Person，并声明其可以序列化。<br /><br /><pre name="code" class="java">
public class Person implements java.io.Serializable {}
</pre><br /><br />序列化机制是通过<span style="color: red">java.io.ObjectOutputStream</span>类和<span style="color: red">java.io.ObjectInputStream</span>类来实现的。在序列化(serialize)一个对象的时候，会先实例化一个ObjectOutputStream对象，然后调用其writeObject()方法；在反序列化(deserialize)的时候，则会实例化一个ObjectInputStream对象，然后调用其readObject()方法。下例说明了这一过程。<br /><pre name="code" class="java">
public void serializeObject(){
     String fileName = "ser.out";
     FileOutputStream fos = new FileOutputStream(fileName);
     ObjectOutputStream oos = new ObjectOutputStream(fos);
     oos.writeObject(new Person());
     oos.flush();
}

public void deserializeObject(){
     String fileName = "ser.out";
     FileInputStream fos = new FileInputStream(fileName);
     ObjectInputStream oos = new ObjectInputStream(fos);
     Person p = oos.readObject();
}
</pre><br />上例中我们对一个Person对象定义了序列化和反序列化的操作。但如果Person类是不能序列化的话，即对不能序列化的类进行序列化操作，则会抛出 <span style="color: red">java.io.NotSerializableException</span>异常。<br />JVM中有一个预定义的序列化实现机制，即默认调用 <span style="color: red">ObjectOutputStream.defaultWriteObject()</span> 和 <span style="color: red">ObjectInputStream.defaultReadObject()</span> 来执行序列化操作。如果想自定义序列化的实现，则必须在声明了可序列化的类中实现 <span style="color: red">writeObject()</span>和<span style="color: red">readObject()</span>方法。<br /><br /><strong>几种使用情况</strong><br />一般在序列化一个类A的时候，有以下三种情况：<br />[list=3]<li> 类A没有父类，自己实现了Serializable接口</li><li> 类A有父类B，且父类实现了Serializable接口</li><li> 类A有父类B，但父类没有实现Serializable接口</li>[/list]<br />对于第一种情况，直接实现Serializable接口即可。<br />对于第二种情况，因为父类B已经实现了Serializable接口，故类A无需实现此接口；如果父类实现了writeObject()和readObject()，则使用此方法，否则直接使用默认的机制。<br />对于第三种情况，则必须在类A中显示实现writeObject()和readObject()方法来处理父类B的状态信息；还有一点要特别注意，在父类B中一定要有一个无参的构造函数，这是因为在反序列化的过程中并不会使用声明为可序列化的类A的任何构造函数，而是会调用其没有申明为可序列化的父类B的无参构造函数。<br /><br /><strong>序列化机制的一些问题</strong><br /><ul><li> 性能问题</li>为了序列化类A一个实例对象，所需保存的全部信息如下：<br />1. 与此实例对象相关的全部类的元数据(metadata)信息；因为继承关系，类A的实例对象也是其任一父类的对象。因而，需要将整个继承链上的每一个类的元数据信息，按照从父到子的顺序依次保存起来。<br />2. 类A的描述信息。此描述信息中可能包含有如下这些信息：类的版本ID(version ID)、表示是否自定义了序列化实现机制的标志、可序列化的属性的数目、每个属性的名字和值、及其可序列化的父类的描述信息。<br />3. 将实例对象作为其每一个超类的实例对象，并将这些数据信息都保存起来。<br />在RMI等远程调用的应用中，每调用一个方法，都需要传递如此多的信息量；久而久之，会对系统的性能照成很大的影响。<li> 版本信息</li>当用readObject()方法读取一个序列化对象的byte流信息时，会从中得到所有相关类的描述信息以及示例对象的状态数据；然后将此描述信息与其本地要构造的类的描述信息进行比较，如果相同则会创建一个新的实例并恢复其状态，否则会抛出异常。这就是序列化对象的版本检测。JVM中默认的描述信息是使用一个长整型的哈希码(hashcode)值来表示，这个值与类的各个方面的信息有关，如类名、类修饰符、所实现的接口名、方法和构造函数的信息、属性的信息等。因而，一个类作一些微小的变动都有可能导致不同的哈希码值。例如开始对一个实例对象进行了序列化，接着对类增加了一个方法，或者更改了某个属性的名称，当再想根据序列化信息来重构以前那个对象的时候，此时两个类的版本信息已经不匹配，不可能再恢复此对象的状态了。要解决这个问题，可能在类中显示定义一个值，如下所示：<br /><pre name="code" class="java">
private static final long serialVersionUID = ALongValue;
</pre><br />这样，序列化机制会使用这个值来作为类的版本标识符，从而可以解决不兼容的问题。但是它却引入了一个新的问题，即使一个类作了实质性的改变，如增加或删除了一些可序列化的属性，在这种机制下仍然会认为这两个类是相等的。<br /></ul><br /><strong>一种更好的选择</strong><br />作为实现Serializable接口的一种替代方案，实现<span style="color: red">java.io.Externalizable</span>接口同样可以标识一个类为可序列化。<br />Externalizable接口中定义了以下两个方法：<br /><pre name="code" class="java">
public void readExternal(ObjectInput in);
public void writeExternal(ObjectOutput out);
</pre><br />这两个方法的功能与 readObject()和writeObject()方法相同，任何实现了Externalizable接口的类都需要这实现两个函数来定义其序列化机制。<br />使用Externalizable比使用Serializable有着性能上的提高。前者序列化一个对象，所需保存的信息比后者要小，对于后者所需保存的第3个方面的信息，前者不需要访问每一个父类并使其保存相关的状态信息，而只需简单地调用类中实现的writeExternal()方法即可。
          <br/><br/>
          <span style="color:red;">
            <a href="http://lionheart.javaeye.com/blog/139540#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;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 09 Nov 2007 21:48:00 +0800</pubDate>
        <link>http://lionheart.javaeye.com/blog/139540</link>
        <guid>http://lionheart.javaeye.com/blog/139540</guid>
      </item>
      <item>
        <title>oracle中的索引及其使用</title>
        <author>lionheart</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lionheart.javaeye.com">lionheart</a>&nbsp;
          链接：<a href="http://lionheart.javaeye.com/blog/136817" style="color:red;">http://lionheart.javaeye.com/blog/136817</a>&nbsp;
          发表时间: 2007年10月30日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          Oracle 中有两种主要的索引机制：B-树索引(B-tree indexes) 和 位图索引(bitmap indexes)，其它的一些索引，如位图连接索引(bitmap join index)、基于函数的索引(function-based indexes)、反转键索引(reverse key indexes)等，都是基于这两种索引的变体。本文主要介绍这两种主要的索引机制。<br />
<h3>一 基础知识</h3>
1. <strong>数据块</strong>(data bolck)<br />
&nbsp;&nbsp;&nbsp; 数据块是Oracle中管理数据文件中存储空间的单位，是数据库使用的I/O的最小单位。Oracle中所有的逻辑数据库结构，如表、索引等的数据都物理地存储在数据块中。数据块的大小是可以配置的，一般使用的值为4KB、8KB、16KB或32KB。<br />
2. <strong>ROWID</strong><br />
&nbsp;&nbsp;&nbsp; ROWID是Oracle中的一个伪列(pseudocolumn)，它提供了访问一个表中指定行的最快的方法。通过ROWID可以直接定位到相应的数据块上。在创建索引时，不仅存储了该索引列的值，同时也存储了该索引列所对应行的ROWID。这样通过索引快速找到相应行的ROWID后，可以通过该ROWID迅速将数据查询出来。这也就是使用索引查询速度比较快的原因。在Oracle 8 以后的版本中，ROWID由以下四部分组成：数据对象编号(OBJECT NUMBER)、数据文件编号(FILE NUMBER)、块编号(BLOCK NUMBER)和行编号(ROW NUMBER)。<br />
<br />
<h3>二 B-树索引</h3>
          <br/><br/>
          <span style="color:red;">
            <a href="http://lionheart.javaeye.com/blog/136817#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;">北京: 千橡集团暨校内网诚聘软件研发工程师</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, 30 Oct 2007 19:11:05 +0800</pubDate>
        <link>http://lionheart.javaeye.com/blog/136817</link>
        <guid>http://lionheart.javaeye.com/blog/136817</guid>
      </item>
      <item>
        <title>[转载]Understanding Indexes</title>
        <author>lionheart</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lionheart.javaeye.com">lionheart</a>&nbsp;
          链接：<a href="http://lionheart.javaeye.com/blog/135464" style="color:red;">http://lionheart.javaeye.com/blog/135464</a>&nbsp;
          发表时间: 2007年10月25日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><a name="What_is_an_Index">
<h3><font color="#ff6600">原文地址：<font color="#000000"><a href="http://www.orafaq.com/node/1403">http://www.orafaq.com/node/1403</a></font></font></h3>
<h3>What is an Index?</h3>
</a></p>
<p>This is covered in the Oracle Concepts manual, of course, but here's the Cliff Notes version.</p>
<p><a name="Blocks">
<h4>Blocks</h4>
</a></p>
<p>First you need to understand a <span style="font-weight: bold;">block</span>. A block - or <span style="font-weight: bold;">page</span> for Microsoft boffins - is the smallest unit of disk that Oracle will read or write. All data in Oracle - tables, indexes, clusters - is stored in blocks. The block size is configurable for any given database but is usually one of 4Kb, 8Kb, 16Kb, or 32Kb. Rows in a table are usually much smaller than this, so many rows will generally fit into a single block. So you never read &quot;just one row&quot;; you will always read the entire block and ignore the rows you don't need. Minimising this wastage is one of the fundamentals of Oracle Performance Tuning.</p>
<p>Oracle uses two different index architectures: b-Tree indexes and bitmap indexes. Cluster indexes, bitmap join indexes, function-based indexes, reverse key indexes and text indexes are all just variations on the two main types. b-Tree is the &quot;normal&quot; index, so we will come back to Bitmap indexes another time.</p>
<p><a name="_The_quotTreequot_in_bTree">
<h4> The &quot;-Tree&quot; in b-Tree</h4>
</a></p>
<p>A b-Tree index is a data structure in the form of a tree - no surprises there - but it is a tree of database <span style="font-style: italic;">blocks</span>, not rows. Imagine the leaf blocks of the index as the pages of a phone book.</p>
<ol class="bb-list" style="list-style-type: circle;">
    <li>Each page in the book (leaf block in the index) contains many entries, which consist of a name (indexed column value) and an address (ROWID) that tells you the physical location of the telephone (row in the table).</li>
    <li>The names on each page are sorted, and the pages - when sorted correctly - contain a complete sorted list of every name and address</li>
</ol>
<p>A sorted list in a phone book is fine for humans, beacuse we have mastered &quot;the flick&quot; - the ability to fan through the book looking for the page that will contain our target <span style="font-style: italic;">without reading the entire page</span>. When we flick through the phone book, we are just reading the first name on each page, which is usually in a larger font in the page header. Oracle cannot read a single name (row) and ignore the reset of the page (block); it needs to read the entire block.</p>
<p>If we had no thumbs, we may find it convenient to create a separate ordered list containing the first name on each page of the phone book along with the page number. This is how the branch-blocks of an index work; a reduced list that contains the first row of each block plus the address of that block. In a large phone book, this reduced list containing one entry per page will still cover many pages, so the process is repeated, creating the next level up in the index, and so on until we are left with a single page: the <span style="font-style: italic;">root</span> of the tree.</p>
<p>To find the name <span style="font-style: italic;">Gallileo</span> in this b-Tree phone book, we:<br />
</p>
<ol class="bb-list" style="list-style-type: circle;">
    <li>Read page 1. This tells us that page 6 starts with <span style="font-style: italic;">Fermat</span> and that page 7 starts with <span style="font-style: italic;">Hawking</span>.</li>
    <li>Read page 6. This tells us that page 350 starts with <span style="font-style: italic;">Fyshe</span> and that page 351 starts with <span style="font-style: italic;">Garibaldi</span>.</li>
    <li>Read page 350, which is a leaf block; we find Gallileo's address and phone number.</li>
</ol>
<p>That's it; 3 blocks to find a specific row in a million row table. In reality, index blocks often fit 100 or more rows, so b-Trees are typically quite shallow. I have never seen an index with more than 5 levels. Curious? Try this:</p>
<pre class="bb-code-block">SELECT index_name, blevel+1 FROM user_indexes ORDER BY 2;<br /></pre>
<p><code class="bb-code">user_indexes.blevel</code> is the number of branch levels. Always add 1 to include the leaf level; this tells you the number of blocks a unique index scan must read to reach the leaf-block. If you're really, really, insatiably curious; try this in SQL*Plus:</p>
<pre class="bb-code-block">ACCEPT index_name PROMPT &quot;Index Name: &quot;<br /><br />ALTER SESSION SET TRACEFILE_IDENTIFIER = '&amp;index_name';<br /><br />COLUMN object_id NEW_VALUE object_id<br /><br />SELECT object_id<br />FROM   user_objects<br />WHERE  object_type = 'INDEX'<br />AND    object_name = upper('&amp;index_name');<br /><br />ALTER SESSION SET EVENTS 'IMMEDIATE TRACE NAME TREEDUMP LEVEL &amp;object_id';<br />ALTER SESSION SET TRACEFILE_IDENTIFIER = &quot;&quot;;<br /><br />SHOW PARAMETER user_dump_dest</pre>
<p>Give the name of an index on a smallish table (because this will create a BIG file). Now, on the Oracle server, go to the directory shown by the final <code class="bb-code">SHOW PARAMETER user_dump_dest</code> command and find your trace file - the file name will contain your index name. Here is a sample:</p>
<pre class="bb-code-block">*** 2007-01-31 11:51:26.822<br />----- begin tree dump<br />branch: 0x68066c8 109078216 (0: nrow: 325, level: 1)<br />   leaf: 0x68066c9 109078217 (-1: nrow: 694 rrow: 694)<br />   leaf: 0x68066ca 109078218 (0: nrow: 693 rrow: 693)<br />   leaf: 0x68066cb 109078219 (1: nrow: 693 rrow: 693)<br />   leaf: 0x68066cc 109078220 (2: nrow: 693 rrow: 693)<br />   leaf: 0x68066cd 109078221 (3: nrow: 693 rrow: 693)<br />   ...<br />   ...<br />   leaf: 0x68069cf 109078991 (320: nrow: 763 rrow: 763)<br />   leaf: 0x68069d0 109078992 (321: nrow: 761 rrow: 761)<br />   leaf: 0x68069d1 109078993 (322: nrow: 798 rrow: 798)<br />   leaf: 0x68069d2 109078994 (323: nrow: 807 rrow: 807)<br />----- end tree dump</pre>
<p>This index has only a root branch with 323 leaf nodes. Each leaf node contains a variable number of index entries up to 807! A deeper index would be more interesting, but it would take a while to dump.</p>
<p><a name="quotBquot_is_for">
<h4>&quot;B&quot; is for...</h4>
</a></p>
<p>Contrary to popular belief, <span style="font-style: italic;">b</span> is not for <span style="font-style: italic;">binary</span>; it's <span style="font-style: italic;">balanced</span>.</p>
<p>As you insert new rows into the table, new rows are inserted into index leaf blocks. When a leaf block is full, another insert will cause the block to be split into two blocks, which means an entry for the new block must be added to the parent branch-block. If the branch-block is also full, it too is split. The process propagates back up the tree until the parent of split has space for one more entry, or the root is reached. A new root is created if the root node splits. Staggeringly, this process ensures that every branch will be the same length. Try it on paper for yourself!</p>
<p><a name="How_are_Indexes_used">
<h3>How are Indexes used?</h3>
</a></p>
<p>Indexes have three main uses: </p>
<ol class="bb-list" style="list-style-type: circle;">
    <li>To quickly find specific rows by avoiding a Full Table Scan
    <p>We've already seen above how a Unique Scan works. Using the phone book metaphor, it's not hard to understand how a Range Scan works in much the same way to find all people named &quot;Gallileo&quot;, or all of the names alphabetically between &quot;Smith&quot; and &quot;Smythe&quot;. Range Scans can occur when we use &gt;, &lt;, <code class="bb-code">LIKE</code>, or <code class="bb-code">BETWEEN</code> in a <code class="bb-code">WHERE</code> clause. A range scan will find the first row in the range using the same technique as the Unique Scan, but will then keep reading the index up to the end of the range. It is OK if the range covers many blocks.</p>
    </li>
    <li>To avoid a table access altogether
    <p>If all we wanted to do when looking up Gallileo in the phone book was to find his address or phone number, the job would be done. However if we wanted to know his date of birth, we'd have to phone and ask. This takes time. If it was something that we needed all the time, like an email address, we could save time by adding it to the phone book.</p>
    <p>Oracle does the same thing. If the information is in the index, then it doesn't bother to read the table. It is a reasonably common technique to add columns to an index, not because they will be used as part of the index scan, but because they save a table access. In fact, Oracle may even perform a Fast Full Scan of an index that it cannot use in a Range or Unique scan just to avoid a table access.<br />
    </p>
    </li>
    <li>To avoid a sort
    <p>This one is not so well known, largely because it is so poorly documented (and in many cases, unpredicatably implemented by the Optimizer as well). Oracle performs a sort for many reasons: <code class="bb-code">ORDER BY</code>, <code class="bb-code">GROUP BY</code>, <code class="bb-code">DISTINCT</code>, Set operations (eg. <code class="bb-code">UNION</code>), Sort-Merge Joins, uncorrelated IN-subqueries, Analytic Functions). If a sort operation requires rows in the same order as the index, then Oracle may read the table rows via the index. A sort operation is not necessary since the rows are returned in sorted order.</p>
    <p>Despite all of the instances listed above where a sort is performed, I have only seen three cases where a sort is actually avoided.</p>
    <ol class="bb-list" style="list-style-type: decimal;">
        <li><code class="bb-code"><span style="font-weight: bold;">GROUP BY</span></code>
        <pre class="bb-code-block">  1  select src_sys, sum(actl_expns_amt), count(*)<br />  2  from ef_actl_expns<br />  3  where src_sys = 'CDW'<br />  4  and actl_expns_amt &gt; 0<br />  5* group by src_sys<br /><br />-------------------------------------------------------------<br />| Id  | Operation                           | Name          |<br />-------------------------------------------------------------<br />|   0 | SELECT STATEMENT                    |               |<br />|   1 |  SORT GROUP BY NOSORT               |               |<br />|*  2 |   TABLE ACCESS BY GLOBAL INDEX ROWID| EF_ACTL_EXPNS |<br />|*  3 |    INDEX RANGE SCAN                 | EF_AEXP_PK    |<br />-------------------------------------------------------------<br /><br />Predicate Information (identified by operation id):<br />---------------------------------------------------<br /><br />   2 - filter(&quot;ACTL_EXPNS_AMT&quot;&gt;0)<br />   3 - access(&quot;SRC_SYS&quot;='CDW')</pre>
        <p>Note the <code class="bb-code">NOSORT</code> qualifier in Step 1.</p>
        </li>
        <li><code class="bb-code"><span style="font-weight: bold;">ORDER BY</span></code>
        <pre class="bb-code-block">  1  select *<br />  2  from ef_actl_expns<br />  3  where src_sys = 'CDW'<br />  4  and actl_expns_amt &gt; 0<br />  5* order by src_sys<br /><br />------------------------------------------------------------<br />| Id  | Operation                          | Name          |<br />------------------------------------------------------------<br />|   0 | SELECT STATEMENT                   |               |<br />|*  1 |  TABLE ACCESS BY GLOBAL INDEX ROWID| EF_ACTL_EXPNS |<br />|*  2 |   INDEX RANGE SCAN                 | EF_AEXP_PK    |<br />------------------------------------------------------------<br /><br />Predicate Information (identified by operation id):<br />---------------------------------------------------<br /><br />   1 - filter(&quot;ACTL_EXPNS_AMT&quot;&gt;0)<br />   2 - access(&quot;SRC_SYS&quot;='CDW')<br /></pre>
        <p>Note that there is no SORT operation, despite the <code class="bb-code">ORDER BY</code> clause. Compare this to the following:</p>
        <pre class="bb-code-block">  1  select *<br />  2  from ef_actl_expns<br />  3  where src_sys = 'CDW'<br />  4  and actl_expns_amt &gt; 0<br />  5* order by actl_expns_amt<br /><br />-------------------------------------------------------------<br />| Id  | Operation                           | Name          |<br />-------------------------------------------------------------<br />|   0 | SELECT STATEMENT                    |               |<br />|   1 |  SORT ORDER BY                      |               |<br />|*  2 |   TABLE ACCESS BY GLOBAL INDEX ROWID| EF_ACTL_EXPNS |<br />|*  3 |    INDEX RANGE SCAN                 | EF_AEXP_PK    |<br />-------------------------------------------------------------<br /><br />Predicate Information (identified by operation id):<br />---------------------------------------------------<br /><br />   2 - filter(&quot;ACTL_EXPNS_AMT&quot;&gt;0)<br />   3 - access(&quot;SRC_SYS&quot;='CDW')</pre>
        </li>
        <li><code class="bb-code"><span style="font-weight: bold;">DISTINCT</span></code>
        <pre class="bb-code-block">  1  select distinct src_sys<br />  2  from ef_actl_expns<br />  3  where src_sys = 'CDW'<br />  4* and actl_expns_amt &gt; 0<br /><br />-------------------------------------------------------------<br />| Id  | Operation                           | Name          |<br />-------------------------------------------------------------<br />|   0 | SELECT STATEMENT                    |               |<br />|   1 |  SORT UNIQUE NOSORT                 |               |<br />|*  2 |   TABLE ACCESS BY GLOBAL INDEX ROWID| EF_ACTL_EXPNS |<br />|*  3 |    INDEX RANGE SCAN                 | EF_AEXP_PK    |<br />-------------------------------------------------------------<br /><br />Predicate Information (identified by operation id):<br />---------------------------------------------------<br /><br />   2 - filter(&quot;ACTL_EXPNS_AMT&quot;&gt;0)<br />   3 - access(&quot;SRC_SYS&quot;='CDW')</pre>
        <p>Again, note the <code class="bb-code">NOSORT</code> qualifier.</p>
        </li>
    </ol>
    <p>This is an extraordinary tuning technique in OLTP systems like SQL*Forms that return one page of detail at a time to the screen. A SQL with a DISTINCT, GROUP BY, or ORDER BY that uses an index to sort can return just the first page of matching rows <span style="font-style: italic;">without having to fetch the entire result set</span> for a sort. This can be the difference between sub-second response time and several minutes or hours.</p>
    <p><a name="Everybody_repeat_after_me_quotFull_table_Scans_are_not_badquot">
    <h3>Everybody repeat after me: &quot;Full table Scans are not bad&quot;</h3>
    </a></p>
    <p>Up to now, we've seen how indexes can be good. It's not always the case; sometimes indexes are no help at all, or worse: they make a query <span style="font-style: italic;">slower</span>.</p>
    <p>A b-Tree index will be no help at all in a reduced scan unless the <code class="bb-code">WHERE</code> clause compares indexed columns using &gt;, &lt;, <code class="bb-code">LIKE</code>, <code class="bb-code">IN</code>, or <code class="bb-code">BETWEEN</code> operators. A b-Tree index cannot be used to scan for any <code class="bb-code">NOT</code> style operators: eg. <code class="bb-code">!=</code>, <code class="bb-code">NOT IN</code>, <code class="bb-code">NOT LIKE</code>. There are lots of conditions, caveats, and complexities regarding joins, sub-queries, <code class="bb-code">OR</code> predicates, functions (inc. arithmetic and concatenation), and casting that are outside the scope of this article. Consult a good SQL tuning manual.</p>
    <p>Much more interesting - and important - are the cases where an index makes a SQL <span style="font-style: italic;">slower</span>. These are particularly common in batch systems that process large quantities of data.</p>
    <p>To explain the problem, we need a new metaphor. Imagine a large deciduous tree in your front yard. It's Autumn, and it's your job to pick up all of the leaves on the lawn. Clearly, the fastest way to do this (without a rake, or a leaf-vac...) would be get down on hands and knees with a bag and work your way back and forth over the lawn, stuffing leaves in the bag as you go. This is a Full Table Scan, selecting rows in no particular order, except that they are nearest to hand. This metaphor works on a couple of levels: you would grab leaves in handfuls, not one by one. A Full Table Scan does the same thing: when a bock is read from disk, Oracle caches the next few blocks with the expectation that it will be asked for them very soon. Type this in SQL*Plus:<br />
    </p>
    <pre class="bb-code-block"><span style="background-color: rgb(255, 255, 0);">SHOW PARAMETER db_file_multiblock_read_count</span><br /></pre>
    <p>Just to shake things up a bit (and to feed an undiagnosed obsessive compulsive disorder), you decide to pick up the leaves in order of size. In support of this endeavour, you take a digital photograph of the lawn, write an image analysis program to identify and measure every leaf, then load the results into a Virtual Reality headset that will highlight the smallest leaf left on the lawn. Ingenious, yes; but this is clearly going to take a lot longer than a full table scan because you cover much more distance walking from leaf to leaf.</p>
    <p>So obviously Full Table Scan is the faster way to pick up <span style="font-style: italic;">every</span> leaf. But just as obvious is that the index (virtual reality headset) is the faster way to pick up <span style="font-style: italic;">just the smallest leaf</span>, or even the 100 smallest leaves. As the number rises, we approach a break-even point; a number beyond which it is faster to just full table scan. This number varies depending on the table, the index, the database settings, the hardware, and the load on the server; generally it is somewhere between 1% and 10% of the table.</p>
    <p>The main reasons for this are:<br />
    </p>
    <ol class="bb-list" style="list-style-type: circle;">
        <li>As implied above, reading a table in indexed order means more movement for the disk head.</li>
        <li>Oracle cannot read single rows. To read a row via an index, the entire block must be read with all but one row discarded. So an index scan of 100 rows would read 100 blocks, but a FTS might read 100 rows in a single block.</li>
        <li>The <code class="bb-code">db_file_multiblock_read_count</code> setting described earlier means FTS requires fewer visits to the physical disk.</li>
        <li>Even if none of these things was true, accessing the entire index <span style="font-style: italic;">and</span> the entire table is still more IO than just accessing the table.</li>
    </ol>
    <p>So what's the lesson here? Know your data! <span style="background-color: rgb(0, 255, 255);">If your query needs 50% of the rows in the table to resolve your query, an index scan just won't help.</span> Not only should you not bother creating or investigating the existence of an index, you should <span style="font-style: italic;">check to make sure</span> Oracle is not already using an index. There are a number of ways to influence index usage; once again, consult a tuning manual. T<span style="background-color: rgb(0, 255, 255);">he exception to this rule - there's always one - is when all of the columns referenced in the SQL are contained in the index. </span>If Oracle does not have to access the table then there is no break-even point; it is generally quicker to scan the index even for 100% of the rows.</p>
    <p><a name="Summary">
    <h3>Summary</h3>
    </a></p>
    <p>Indexes are not a dark-art; they work in an entirely predictable and even intuitive way. Understanding how they work moves Performance Tuning from the realm of guesswork to that of science; so embrace the technology and read the manual.</p>
    </li>
</ol>
<a href="http://www.orafaq.com/node/1403"></a>
          <br/><br/>
          <span style="color:red;">
            <a href="http://lionheart.javaeye.com/blog/135464#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;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 25 Oct 2007 16:00:17 +0800</pubDate>
        <link>http://lionheart.javaeye.com/blog/135464</link>
        <guid>http://lionheart.javaeye.com/blog/135464</guid>
      </item>
      <item>
        <title>对java中equals和hashCode函数的一些理解</title>
        <author>lionheart</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lionheart.javaeye.com">lionheart</a>&nbsp;
          链接：<a href="http://lionheart.javaeye.com/blog/135077" style="color:red;">http://lionheart.javaeye.com/blog/135077</a>&nbsp;
          发表时间: 2007年10月24日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          JDK的java.lang.Object类中实现了equals函数，其定义说明如下：<br /><div class="quote_title">引用</div><div class="quote_div"><br />    public boolean equals(Object obj)<br />         Indicates whether some other object is "equal to" this one. <br />         The equals method implements an equivalence relation on non-null object references: <br />          [list=5]<br />          <li> It  is reflexive: for any non-null reference value x, x.equals(x) should return true.              </li>          <li> It  is symmetric: for any non-null reference values x and y, x.equals(y) should return true if and only if y.equals(x) returns true. </li>          <li> It  is transitive: for any non-null reference values x, y, and z, if x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) should return true. </li>          <li> It  is consistent: for any non-null reference values x and y, multiple invocations of x.equals(y) consistently return true or consistently return false, provided no information used in equals comparisons on the objects is modified. </li>          <li> For  any non-null reference value x, x.equals(null) should return false. </li>          [/list]<br />         The equals method for class Object implements the most discriminating possible equivalence relation on objects; that is, for any non-null reference values x and y, this method returns true if and only if x and y refer to the same object (x == y has the value true). <br />         Note that it is generally necessary to override the hashCode method whenever this method is overridden, so as to maintain the general contract for the hashCode method, which states that equal objects must have equal hash codes. <br /></div><br /><br />其具体的实现代码如下所示：<br /><pre name="code" class="java">
    public boolean equals(Object obj) {
        return (this == obj);
    }  
</pre><br />     从上面的代码中可以看出，Object类的equals实现只是简单地调用了“==”运算符，也即定义中说明的，对于两个非空对象X和Y，有且仅当X和Y指向同一个对象时该函数才返回true。由于Object类是java中所有类的超类，因而其它任何类都默认继承了此函数。在大多数情况下，此默认的实现方式是合适的，因为任一个类本质上都是唯一的；但是对于那些表示“值”的类(如Integer、St