﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-爱女孩的小火柴-文章分类-java</title><link>http://www.blogjava.net/mayu/category/14209.html</link><description>生活的理想就是为了理想的生活:)</description><language>zh-cn</language><lastBuildDate>Thu, 21 Jun 2007 05:27:02 GMT</lastBuildDate><pubDate>Thu, 21 Jun 2007 05:27:02 GMT</pubDate><ttl>60</ttl><item><title>Java程序异常处理的特殊情况ZT</title><link>http://www.blogjava.net/mayu/articles/125142.html</link><dc:creator>my</dc:creator><author>my</author><pubDate>Tue, 19 Jun 2007 08:25:00 GMT</pubDate><guid>http://www.blogjava.net/mayu/articles/125142.html</guid><wfw:comment>http://www.blogjava.net/mayu/comments/125142.html</wfw:comment><comments>http://www.blogjava.net/mayu/articles/125142.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mayu/comments/commentRss/125142.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mayu/services/trackbacks/125142.html</trackback:ping><description><![CDATA[<strong>1、不能在finally块中执行return,continue等语句，否则会把异常&#8220;吃掉&#8221;;</strong>
<p>　　<strong>2、在try，catch中如果有return语句，则在执行return之前先执行finally块</strong></p>
<p>　　请大家仔细看下面的例子：<br>
<table style="BORDER-RIGHT: #cccccc 1px dotted; TABLE-LAYOUT: fixed; BORDER-TOP: #cccccc 1px dotted; BORDER-LEFT: #cccccc 1px dotted; BORDER-BOTTOM: #cccccc 1px dotted" cellSpacing=0 cellPadding=6 width="95%" align=center border=0>
    <tbody>
        <tr>
            <td style="WORD-WRAP: break-word" bgColor=#f3f3f3><font style="FONT-WEIGHT: bold; COLOR: #990000">以下是引用片段：</font><br>public&nbsp;class&nbsp;TryTest&nbsp;{&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args)&nbsp;{&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try&nbsp;{&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(TryTest.test());//&nbsp;返回结果为true其没有任何异常&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;catch&nbsp;(Exception&nbsp;e)&nbsp;{&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("Exception&nbsp;from&nbsp;main");&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;doThings(0);&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp; <br>&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;boolean&nbsp;test()&nbsp;throws&nbsp;Exception&nbsp;{&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try&nbsp;{&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;new&nbsp;Exception("Something&nbsp;error");//&nbsp;第1步.抛出异常&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;catch&nbsp;(Exception&nbsp;e)&nbsp;{//&nbsp;第2步.捕获的异常匹配(声明类或其父类），进入控制块&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("Exception&nbsp;from&nbsp;e");//&nbsp;第3步.打印&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;false;//&nbsp;第5步.&nbsp;return前控制转移到finally块,执行完后再返回（这一步被吃掉了，不执行）&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;finally&nbsp;{&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;true;&nbsp;//&nbsp;第4步.&nbsp;控制转移，直接返回，吃掉了异常&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;doThings(int&nbsp;i)&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(i==0)&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//在执行return之前会先执行finally&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;t=100/i;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(t);&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}catch(Exception&nbsp;ex)&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ex.printStackTrace();&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;finally&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("finally");&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp; <br>}&nbsp;</td>
        </tr>
    </tbody>
</table>
</p>
<img src ="http://www.blogjava.net/mayu/aggbug/125142.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mayu/" target="_blank">my</a> 2007-06-19 16:25 <a href="http://www.blogjava.net/mayu/articles/125142.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>对synchronized(this)的一些理解 ZT</title><link>http://www.blogjava.net/mayu/articles/122890.html</link><dc:creator>my</dc:creator><author>my</author><pubDate>Fri, 08 Jun 2007 09:12:00 GMT</pubDate><guid>http://www.blogjava.net/mayu/articles/122890.html</guid><wfw:comment>http://www.blogjava.net/mayu/comments/122890.html</wfw:comment><comments>http://www.blogjava.net/mayu/articles/122890.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mayu/comments/commentRss/122890.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mayu/services/trackbacks/122890.html</trackback:ping><description><![CDATA[<strong>synchronized&nbsp;<br>　　Java语言的关键字，当它用来修饰一个方法或者一个代码块的时候，能够保证在同一时刻最多只有一个线程执行该段代码。</strong>&nbsp;<br><br><br><br>一、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时，一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。<br><br><br><br>二、然而，当一个线程访问object的一个synchronized(this)同步代码块时，另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。<br><br><br><br>三、尤其关键的是，当一个线程访问object的一个synchronized(this)同步代码块时，其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。<br><br><br><br>四、第三个例子同样适用其它同步代码块。也就是说，当一个线程访问object的一个synchronized(this)同步代码块时，它就获得了这个object的对象锁。结果，其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。<br><br><br><br>五、以上规则对其它对象锁同样适用.<br><br><br><br>举例说明：<br><br><br><br>一、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时，一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。<br><br><br><br>package&nbsp;ths;<br><br>public&nbsp;class&nbsp;Thread1&nbsp;implements&nbsp;Runnable&nbsp;{<br>public&nbsp;void&nbsp;run()&nbsp;{<br>synchronized(this)&nbsp;{<br>for&nbsp;(int&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;5;&nbsp;i++)&nbsp;{<br>System.out.println(Thread.currentThread().getName()&nbsp;+&nbsp;"&nbsp;synchronized&nbsp;loop&nbsp;"&nbsp;+&nbsp;i);<br>}<br>}<br>}<br>public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args)&nbsp;{<br>Thread1&nbsp;t1&nbsp;=&nbsp;new&nbsp;Thread1();<br>Thread&nbsp;ta&nbsp;=&nbsp;new&nbsp;Thread(t1,&nbsp;"A");<br>Thread&nbsp;tb&nbsp;=&nbsp;new&nbsp;Thread(t1,&nbsp;"B");<br>ta.start();<br>tb.start();<br>}<br>}<br><br><br><br>结果：<br><br><br><br>A&nbsp;synchronized&nbsp;loop&nbsp;0<br>A&nbsp;synchronized&nbsp;loop&nbsp;1<br>A&nbsp;synchronized&nbsp;loop&nbsp;2<br>A&nbsp;synchronized&nbsp;loop&nbsp;3<br>A&nbsp;synchronized&nbsp;loop&nbsp;4<br>B&nbsp;synchronized&nbsp;loop&nbsp;0<br>B&nbsp;synchronized&nbsp;loop&nbsp;1<br>B&nbsp;synchronized&nbsp;loop&nbsp;2<br>B&nbsp;synchronized&nbsp;loop&nbsp;3<br>B&nbsp;synchronized&nbsp;loop&nbsp;4<br><br><br><br>二、然而，当一个线程访问object的一个synchronized(this)同步代码块时，另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。<br><br><br><br>package&nbsp;ths;<br><br>public&nbsp;class&nbsp;Thread2&nbsp;{<br>public&nbsp;void&nbsp;m4t1()&nbsp;{<br>synchronized(this)&nbsp;{<br>int&nbsp;i&nbsp;=&nbsp;5;<br>while(&nbsp;i--&nbsp;&gt;&nbsp;0)&nbsp;{<br>System.out.println(Thread.currentThread().getName()&nbsp;+&nbsp;"&nbsp;:&nbsp;"&nbsp;+&nbsp;i);<br>try&nbsp;{<br>Thread.sleep(500);<br>}&nbsp;catch&nbsp;(InterruptedException&nbsp;ie)&nbsp;{<br>}<br>}<br>}<br>}<br>public&nbsp;void&nbsp;m4t2()&nbsp;{<br>int&nbsp;i&nbsp;=&nbsp;5;<br>while(&nbsp;i--&nbsp;&gt;&nbsp;0)&nbsp;{<br>System.out.println(Thread.currentThread().getName()&nbsp;+&nbsp;"&nbsp;:&nbsp;"&nbsp;+&nbsp;i);<br>try&nbsp;{<br>Thread.sleep(500);<br>}&nbsp;catch&nbsp;(InterruptedException&nbsp;ie)&nbsp;{<br>}<br>}<br>}<br>public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args)&nbsp;{<br>final&nbsp;Thread2&nbsp;myt2&nbsp;=&nbsp;new&nbsp;Thread2();<br>Thread&nbsp;t1&nbsp;=&nbsp;new&nbsp;Thread(<br>new&nbsp;Runnable()&nbsp;{<br>public&nbsp;void&nbsp;run()&nbsp;{<br>myt2.m4t1();<br>}<br>},&nbsp;"t1"<br>);<br>Thread&nbsp;t2&nbsp;=&nbsp;new&nbsp;Thread(<br>new&nbsp;Runnable()&nbsp;{<br>public&nbsp;void&nbsp;run()&nbsp;{<br>myt2.m4t2();<br>}<br>},&nbsp;"t2"<br>);<br>t1.start();<br>t2.start();<br>}<br>}<br><br><br><br>结果：<br><br><br><br>t1&nbsp;:&nbsp;4<br>t2&nbsp;:&nbsp;4<br>t1&nbsp;:&nbsp;3<br>t2&nbsp;:&nbsp;3<br>t1&nbsp;:&nbsp;2<br>t2&nbsp;:&nbsp;2<br>t1&nbsp;:&nbsp;1<br>t2&nbsp;:&nbsp;1<br>t1&nbsp;:&nbsp;0<br>t2&nbsp;:&nbsp;0<br><br><br><br>三、尤其关键的是，当一个线程访问object的一个synchronized(this)同步代码块时，其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。<br><br><br><br>//修改Thread2.m4t2()方法：<br><br>public&nbsp;void&nbsp;m4t2()&nbsp;{<br>synchronized(this)&nbsp;{<br>int&nbsp;i&nbsp;=&nbsp;5;<br>while(&nbsp;i--&nbsp;&gt;&nbsp;0)&nbsp;{<br>System.out.println(Thread.currentThread().getName()&nbsp;+&nbsp;"&nbsp;:&nbsp;"&nbsp;+&nbsp;i);<br>try&nbsp;{<br>Thread.sleep(500);<br>}&nbsp;catch&nbsp;(InterruptedException&nbsp;ie)&nbsp;{<br>}<br>}<br>}<br><br>}<br><br><br><br>结果：<br><br><br><br>t1&nbsp;:&nbsp;4<br>t1&nbsp;:&nbsp;3<br>t1&nbsp;:&nbsp;2<br>t1&nbsp;:&nbsp;1<br>t1&nbsp;:&nbsp;0<br>t2&nbsp;:&nbsp;4<br>t2&nbsp;:&nbsp;3<br>t2&nbsp;:&nbsp;2<br>t2&nbsp;:&nbsp;1<br>t2&nbsp;:&nbsp;0<br><br><br><br>四、第三个例子同样适用其它同步代码块。也就是说，当一个线程访问object的一个synchronized(this)同步代码块时，它就获得了这个object的对象锁。结果，其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。<br><br><br><br>//修改Thread2.m4t2()方法如下：<br><br>public&nbsp;synchronized&nbsp;void&nbsp;m4t2()&nbsp;{<br>int&nbsp;i&nbsp;=&nbsp;5;<br>while(&nbsp;i--&nbsp;&gt;&nbsp;0)&nbsp;{<br>System.out.println(Thread.currentThread().getName()&nbsp;+&nbsp;"&nbsp;:&nbsp;"&nbsp;+&nbsp;i);<br>try&nbsp;{<br>Thread.sleep(500);<br>}&nbsp;catch&nbsp;(InterruptedException&nbsp;ie)&nbsp;{<br>}<br>}<br>}<br><br><br><br>结果：<br><br><br><br>t1&nbsp;:&nbsp;4<br>t1&nbsp;:&nbsp;3<br>t1&nbsp;:&nbsp;2<br>t1&nbsp;:&nbsp;1<br>t1&nbsp;:&nbsp;0<br>t2&nbsp;:&nbsp;4<br>t2&nbsp;:&nbsp;3<br>t2&nbsp;:&nbsp;2<br>t2&nbsp;:&nbsp;1<br>t2&nbsp;:&nbsp;0<br><br><br><br>五、以上规则对其它对象锁同样适用:<br><br><br><br>package&nbsp;ths;<br><br>public&nbsp;class&nbsp;Thread3&nbsp;{<br>class&nbsp;Inner&nbsp;{<br>private&nbsp;void&nbsp;m4t1()&nbsp;{<br>int&nbsp;i&nbsp;=&nbsp;5;<br>while(i--&nbsp;&gt;&nbsp;0)&nbsp;{<br>System.out.println(Thread.currentThread().getName()&nbsp;+&nbsp;"&nbsp;:&nbsp;Inner.m4t1()="&nbsp;+&nbsp;i);<br>try&nbsp;{<br>Thread.sleep(500);<br>}&nbsp;catch(InterruptedException&nbsp;ie)&nbsp;{<br>}<br>}<br>}<br>private&nbsp;void&nbsp;m4t2()&nbsp;{<br>int&nbsp;i&nbsp;=&nbsp;5;<br>while(i--&nbsp;&gt;&nbsp;0)&nbsp;{<br>System.out.println(Thread.currentThread().getName()&nbsp;+&nbsp;"&nbsp;:&nbsp;Inner.m4t2()="&nbsp;+&nbsp;i);<br>try&nbsp;{<br>Thread.sleep(500);<br>}&nbsp;catch(InterruptedException&nbsp;ie)&nbsp;{<br>}<br>}<br>}<br>}<br>private&nbsp;void&nbsp;m4t1(Inner&nbsp;inner)&nbsp;{<br>synchronized(inner)&nbsp;{&nbsp;//使用对象锁<br>inner.m4t1();<br>}<br>}<br>private&nbsp;void&nbsp;m4t2(Inner&nbsp;inner)&nbsp;{<br>inner.m4t2();<br>}<br>public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args)&nbsp;{<br>final&nbsp;Thread3&nbsp;myt3&nbsp;=&nbsp;new&nbsp;Thread3();<br>final&nbsp;Inner&nbsp;inner&nbsp;=&nbsp;myt3.new&nbsp;Inner();<br>Thread&nbsp;t1&nbsp;=&nbsp;new&nbsp;Thread(<br>new&nbsp;Runnable()&nbsp;{<br>public&nbsp;void&nbsp;run()&nbsp;{<br>myt3.m4t1(inner);<br>}<br>},&nbsp;"t1"<br>);<br>Thread&nbsp;t2&nbsp;=&nbsp;new&nbsp;Thread(<br>new&nbsp;Runnable()&nbsp;{<br>public&nbsp;void&nbsp;run()&nbsp;{<br>myt3.m4t2(inner);<br>}<br>},&nbsp;"t2"<br>);<br>t1.start();<br>t2.start();<br>}<br>}<br><br><br><br>结果：<br><br>尽管线程t1获得了对Inner的对象锁，但由于线程t2访问的是同一个Inner中的非同步部分。所以两个线程互不干扰。<br><br><br><br>t1&nbsp;:&nbsp;Inner.m4t1()=4<br>t2&nbsp;:&nbsp;Inner.m4t2()=4<br>t1&nbsp;:&nbsp;Inner.m4t1()=3<br>t2&nbsp;:&nbsp;Inner.m4t2()=3<br>t1&nbsp;:&nbsp;Inner.m4t1()=2<br>t2&nbsp;:&nbsp;Inner.m4t2()=2<br>t1&nbsp;:&nbsp;Inner.m4t1()=1<br>t2&nbsp;:&nbsp;Inner.m4t2()=1<br>t1&nbsp;:&nbsp;Inner.m4t1()=0<br>t2&nbsp;:&nbsp;Inner.m4t2()=0<br><br><br><br>现在在Inner.m4t2()前面加上synchronized：<br><br><br><br>private&nbsp;synchronized&nbsp;void&nbsp;m4t2()&nbsp;{<br>int&nbsp;i&nbsp;=&nbsp;5;<br>while(i--&nbsp;&gt;&nbsp;0)&nbsp;{<br>System.out.println(Thread.currentThread().getName()&nbsp;+&nbsp;"&nbsp;:&nbsp;Inner.m4t2()="&nbsp;+&nbsp;i);<br>try&nbsp;{<br>Thread.sleep(500);<br>}&nbsp;catch(InterruptedException&nbsp;ie)&nbsp;{<br>}<br>}<br>}<br><br><br><br>结果：<br><br>尽管线程t1与t2访问了同一个Inner对象中两个毫不相关的部分,但因为t1先获得了对Inner的对象锁，所以t2对Inner.m4t2()的访问也被阻塞，因为m4t2()是Inner中的一个同步方法。<br><br><br><br>t1&nbsp;:&nbsp;Inner.m4t1()=4<br>t1&nbsp;:&nbsp;Inner.m4t1()=3<br>t1&nbsp;:&nbsp;Inner.m4t1()=2<br>t1&nbsp;:&nbsp;Inner.m4t1()=1<br>t1&nbsp;:&nbsp;Inner.m4t1()=0<br>t2&nbsp;:&nbsp;Inner.m4t2()=4<br>t2&nbsp;:&nbsp;Inner.m4t2()=3<br>t2&nbsp;:&nbsp;Inner.m4t2()=2<br>t2&nbsp;:&nbsp;Inner.m4t2()=1<br>t2&nbsp;:&nbsp;Inner.m4t2()=0 
<img src ="http://www.blogjava.net/mayu/aggbug/122890.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mayu/" target="_blank">my</a> 2007-06-08 17:12 <a href="http://www.blogjava.net/mayu/articles/122890.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java同步机制浅谈――synchronized  ZT</title><link>http://www.blogjava.net/mayu/articles/122887.html</link><dc:creator>my</dc:creator><author>my</author><pubDate>Fri, 08 Jun 2007 09:09:00 GMT</pubDate><guid>http://www.blogjava.net/mayu/articles/122887.html</guid><wfw:comment>http://www.blogjava.net/mayu/comments/122887.html</wfw:comment><comments>http://www.blogjava.net/mayu/articles/122887.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mayu/comments/commentRss/122887.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mayu/services/trackbacks/122887.html</trackback:ping><description><![CDATA[<p><span id=ArticleContent1_ArticleContent1_lblContent></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><font size=3><span lang=EN-US><font face="Times New Roman">Java</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">对多线程的支持与同步机制深受大家的喜爱，似乎看起来使用了</span><span lang=EN-US><font face="Times New Roman">synchronized</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">关键字就可以轻松地解决多线程共享数据同步问题。到底如何？――还得对</span><span lang=EN-US><font face="Times New Roman">synchronized</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">关键字的作用进行深入了解才可定论。</span></font></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><font size=3><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">总的说来，</span><span lang=EN-US><font face="Times New Roman">synchronized</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">关键字可以作为函数的修饰符，也可作为函数内的语句，也就是平时说的同步方法和同步语句块。如果再细的分类，</span><span lang=EN-US><font face="Times New Roman">synchronized</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">可作用于</span><span lang=EN-US><font face="Times New Roman">instance</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">变量、</span><span lang=EN-US><font face="Times New Roman">object reference</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">（对象引用）、</span><span lang=EN-US><font face="Times New Roman">static</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">函数和</span><span lang=EN-US><font face="Times New Roman">class literals(</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">类名称字面常量</span><span lang=EN-US><font face="Times New Roman">)</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">身上。</span></font></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'"><font size=3>在进一步阐述之前，我们需要明确几点：</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><font size=3><span lang=EN-US><font face="Times New Roman">A</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">．无论</span><span lang=EN-US><font face="Times New Roman">synchronized</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">关键字加在方法上还是对象上，它取得的锁都是对象，而不是把一段代码或函数当作锁――而且同步方法很可能还会被其他线程的对象访问。</span></font></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><font size=3><span lang=EN-US><font face="Times New Roman">B</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">．每个对象只有一个锁（</span><span lang=EN-US><font face="Times New Roman">lock</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">）与之相关联。</span></font></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><font size=3><span lang=EN-US><font face="Times New Roman">C</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">．实现同步是要很大的系统开销作为代价的，甚至可能造成死锁，所以尽量避免无谓的同步控制。</span></font></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><font size=3><strong style="mso-bidi-font-weight: normal"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">接着来讨论</span><span lang=EN-US><font face="Times New Roman">synchronized</font></span></strong><strong style="mso-bidi-font-weight: normal"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">用到不同地方对代码产生的影响：</span><span lang=EN-US>
<p>&#160;</p>
</span></strong></font>
<p>&#160;</p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><font size=3><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">假设</span><span lang=EN-US><font face="Times New Roman">P1</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">、</span><span lang=EN-US><font face="Times New Roman">P2</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">是同一个类的不同对象，这个类中定义了以下几种情况的同步块或同步方法，</span><span lang=EN-US><font face="Times New Roman">P1</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">、</span><span lang=EN-US><font face="Times New Roman">P2</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">就都可以调用它们。</span><strong style="mso-bidi-font-weight: normal"><span lang=EN-US>
<p>&#160;</p>
</span></strong></font>
<p>&#160;</p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: -39pt; mso-list: l0 level1 lfo1; tab-stops: list 18.0pt"><span lang=EN-US style="mso-fareast-font-family: 'Times New Roman'"><span style="mso-list: Ignore"><font face="Times New Roman"><font size=3>1．</font><span style="FONT: 7pt 'Times New Roman'">&nbsp; </span></font></span></span><font size=3><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">把</span><span lang=EN-US><font face="Times New Roman">synchronized</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">当作函数修饰符时，示例代码如下：</span></font></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 42pt; mso-para-margin-left: 4.0gd"><span lang=EN-US><font face="Times New Roman" size=3>Public synchronized void methodAAA()</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 42pt; mso-para-margin-left: 4.0gd"><span lang=EN-US><font face="Times New Roman" size=3>{</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 63pt; mso-para-margin-left: 6.0gd"><span lang=EN-US><font face="Times New Roman" size=3>//&#8230;.</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 42pt; mso-para-margin-left: 4.0gd"><span lang=EN-US><font face="Times New Roman" size=3>}</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><font size=3><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">这也就是同步方法，那这时</span><span lang=EN-US><font face="Times New Roman">synchronized</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">锁定的是哪个对象呢？它锁定的是调用这个同步方法对象。也就是说，当一个对象</span><span lang=EN-US><font face="Times New Roman">P1</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">在不同的线程中执行这个同步方法时，它们之间会形成互斥，达到同步的效果。但是这个对象所属的</span><span lang=EN-US><font face="Times New Roman">Class</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">所产生的另一对象</span><span lang=EN-US><font face="Times New Roman">P2</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">却可以任意调用这个被加了</span><span lang=EN-US><font face="Times New Roman">synchronized</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">关键字的方法。</span></font></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'"><font size=3>上边的示例代码等同于如下代码：</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 42pt; mso-para-margin-left: 4.0gd"><span lang=EN-US><font face="Times New Roman" size=3>public void methodAAA()</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 42pt; mso-para-margin-left: 4.0gd"><span lang=EN-US><font face="Times New Roman" size=3>{</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 63pt; mso-para-margin-left: 6.0gd"><span lang=EN-US><font face="Times New Roman" size=3>synchronized (this)<span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>//<span style="mso-spacerun: yes">&nbsp; </span>(1)</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 63pt; mso-para-margin-left: 6.0gd"><span lang=EN-US><font face="Times New Roman" size=3>{</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 63pt; mso-para-margin-left: 6.0gd"><span lang=EN-US><font size=3><font face="Times New Roman"><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>//&#8230;..</font></font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 63pt; mso-para-margin-left: 6.0gd"><span lang=EN-US><font face="Times New Roman" size=3>}</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 42pt; mso-para-margin-left: 4.0gd"><span lang=EN-US><font face="Times New Roman" size=3>}</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><font size=3><span lang=EN-US><font face="Times New Roman"><span style="mso-spacerun: yes">&nbsp;</span>(1)</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">处的</span><span lang=EN-US><font face="Times New Roman">this</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">指的是什么呢？它指的就是调用这个方法的对象，如</span><span lang=EN-US><font face="Times New Roman">P1</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">。可见同步方法实质是将</span><span lang=EN-US><font face="Times New Roman">synchronized</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">作用于</span><span lang=EN-US><font face="Times New Roman">object reference</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">。――那个拿到了</span><span lang=EN-US><font face="Times New Roman">P1</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">对象锁的线程，才可以调用</span><span lang=EN-US><font face="Times New Roman">P1</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的同步方法，而对</span><span lang=EN-US><font face="Times New Roman">P2</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">而言，</span><span lang=EN-US><font face="Times New Roman">P1</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">这个锁与它毫不相干，程序也可能在这种情形下摆脱同步机制的控制，造成数据混乱：（</span></font></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><font size=3><span lang=EN-US><font face="Times New Roman">2</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">．同步块，示例代码如下：</span></font></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US><font size=3><font face="Times New Roman"><span style="mso-spacerun: yes">&nbsp; </span><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </span><span style="mso-spacerun: yes">&nbsp;&nbsp;</span><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </span>public void method3(SomeObject so)</font></font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US><font size=3><font face="Times New Roman"><span style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>{</font></font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US><font size=3><font face="Times New Roman"><span style="mso-tab-count: 3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>synchronized(so)</font></font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 42pt; TEXT-INDENT: 21pt"><span lang=EN-US><font face="Times New Roman" size=3>{</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 42pt; TEXT-INDENT: 21pt"><span lang=EN-US><font size=3><font face="Times New Roman"><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>//&#8230;..</font></font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 42pt; TEXT-INDENT: 21pt"><span lang=EN-US><font face="Times New Roman" size=3>}</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 21pt; TEXT-INDENT: 21pt"><span lang=EN-US><font face="Times New Roman" size=3>}</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.75pt"><font size=3><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">这时，锁就是</span><span lang=EN-US><font face="Times New Roman">so</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">这个对象，谁拿到这个锁谁就可以运行它所控制的那段代码。当有一个明确的对象作为锁时，就可以这样写程序，但当没有明确的对象作为锁，只是想让一段代码同步时，可以创建一个特殊的</span><span lang=EN-US><font face="Times New Roman">instance</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">变量（它得是一个对象）来充当锁：</span></font></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.75pt"><span lang=EN-US><font face="Times New Roman" size=3>class Foo implements Runnable</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.75pt"><span lang=EN-US><font face="Times New Roman" size=3>{</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.75pt"><font size=3><span lang=EN-US><font face="Times New Roman"><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>private byte[] lock = new byte[0];<span style="mso-spacerun: yes">&nbsp; </span>// </font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">特殊的</span><span lang=EN-US><font face="Times New Roman">instance</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">变量</span></font></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.75pt"><span lang=EN-US><font size=3><font face="Times New Roman"><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </span>Public void methodA()</font></font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 20.25pt; TEXT-INDENT: 21.75pt"><span lang=EN-US><font face="Times New Roman" size=3>{</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.75pt"><span lang=EN-US><font size=3><font face="Times New Roman"><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>synchronized(lock) { //&#8230; }</font></font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 20.25pt; TEXT-INDENT: 21.75pt"><span lang=EN-US><font face="Times New Roman" size=3>}</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 20.25pt; TEXT-INDENT: 21.75pt"><span lang=EN-US><font face="Times New Roman" size=3>//&#8230;..</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.75pt"><span lang=EN-US><font face="Times New Roman" size=3>}</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><font size=3><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">注：零长度的</span><span lang=EN-US><font face="Times New Roman">byte</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">数组对象创建起来将比任何对象都经济――查看编译后的字节码：生成零长度的</span><span lang=EN-US><font face="Times New Roman">byte[]</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">对象只需</span><span lang=EN-US><font face="Times New Roman">3</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">条操作码，而</span><span lang=EN-US><font face="Times New Roman">Object lock = new Object()</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">则需要</span><span lang=EN-US><font face="Times New Roman">7</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">行操作码。</span></font></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><font size=3><span lang=EN-US><font face="Times New Roman">3</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">．将</span><span lang=EN-US><font face="Times New Roman">synchronized</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">作用于</span><span lang=EN-US><font face="Times New Roman">static </font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">函数，示例代码如下：</span></font></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US><font size=3><font face="Times New Roman"><span style="mso-spacerun: yes">&nbsp;</span><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp; </span>Class Foo </font></font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><span lang=EN-US><font face="Times New Roman" size=3>{</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 42pt; mso-para-margin-left: 4.0gd"><font size=3><span lang=EN-US><font face="Times New Roman">public synchronized static void methodAAA()<span style="mso-spacerun: yes">&nbsp;&nbsp; </span>// </font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">同步的</span><span lang=EN-US><font face="Times New Roman">static </font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">函数</span></font></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 42pt; mso-para-margin-left: 4.0gd"><span lang=EN-US><font face="Times New Roman" size=3>{</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 63pt; mso-para-margin-left: 6.0gd"><span lang=EN-US><font face="Times New Roman" size=3>//&#8230;.</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 42pt; mso-para-margin-left: 4.0gd"><span lang=EN-US><font face="Times New Roman" size=3>}</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 42pt; mso-para-margin-left: 4.0gd"><span lang=EN-US><font face="Times New Roman" size=3>public void methodBBB()</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 42pt; mso-para-margin-left: 4.0gd"><span lang=EN-US><font face="Times New Roman" size=3>{</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 42pt; mso-para-margin-left: 4.0gd"><font size=3><span lang=EN-US><font face="Times New Roman"><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>synchronized(Foo.class)<span style="mso-spacerun: yes">&nbsp;&nbsp; </span>//<span style="mso-spacerun: yes">&nbsp; </span>class literal(</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">类名称字面常量</span><span lang=EN-US><font face="Times New Roman">)</font></span></font></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 42pt; mso-para-margin-left: 4.0gd"><span lang=EN-US><font face="Times New Roman" size=3>}</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US><font size=3><font face="Times New Roman"><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}</font></font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><font size=3><span lang=EN-US><span style="mso-spacerun: yes"><font face="Times New Roman">&nbsp;&nbsp; </font></span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">代码中的</span><span lang=EN-US><font face="Times New Roman">methodBBB()</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">方法是把</span><span lang=EN-US><font face="Times New Roman">class literal</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">作为锁的情况，它和同步的</span><span lang=EN-US><font face="Times New Roman">static</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">函数产生的效果是一样的，取得的锁很特别，是当前调用这个方法的对象所属的类（</span><span lang=EN-US><font face="Times New Roman">Class</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，而不再是由这个</span><span lang=EN-US><font face="Times New Roman">Class</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">产生的某个具体对象了）。</span></font></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><font size=3><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">记得在《</span><span lang=EN-US><font face="Times New Roman">Effective Java</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">》一书中看到过将</span><span lang=EN-US><font face="Times New Roman"> Foo.class</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">和</span><span lang=EN-US><font face="Times New Roman"> P1.getClass()</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">用于作同步锁还不一样，不能用</span><span lang=EN-US><font face="Times New Roman">P1.getClass()</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">来达到锁这个</span><span lang=EN-US><font face="Times New Roman">Class</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的目的。</span><span lang=EN-US><font face="Times New Roman">P1</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">指的是由</span><span lang=EN-US><font face="Times New Roman">Foo</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">类产生的对象。</span></font></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><font size=3><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">可以推断：如果一个类中定义了一个</span><span lang=EN-US><font face="Times New Roman">synchronized</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的</span><span lang=EN-US><font face="Times New Roman">static</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">函数</span><span lang=EN-US><font face="Times New Roman">A</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，也定义了一个</span><span lang=EN-US><font face="Times New Roman">synchronized </font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的</span><span lang=EN-US><font face="Times New Roman">instance</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">函数</span><span lang=EN-US><font face="Times New Roman">B</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，那么这个类的同一对象</span><span lang=EN-US><font face="Times New Roman">Obj</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">在多线程中分别访问</span><span lang=EN-US><font face="Times New Roman">A</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">和</span><span lang=EN-US><font face="Times New Roman">B</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">两个方法时，不会构成同步，因为它们的锁都不一样。</span><span lang=EN-US><font face="Times New Roman">A</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">方法的锁是</span><span lang=EN-US><font face="Times New Roman">Obj</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">这个对象，而</span><span lang=EN-US><font face="Times New Roman">B</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的锁是</span><span lang=EN-US><font face="Times New Roman">Obj</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">所属的那个</span><span lang=EN-US><font face="Times New Roman">Class</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">。</span><strong style="mso-bidi-font-weight: normal"><span lang=EN-US>
<p>&#160;</p>
</span></strong></font>
<p>&#160;</p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'"><font size=3>小结如下：</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><font size=3><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">搞清楚</span><span lang=EN-US><font face="Times New Roman">synchronized</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">锁定的是哪个对象，就能帮助我们设计更安全的多线程程序。</span></font></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US>
<p><font face="Times New Roman" size=3>&nbsp;</font></p>
</span>
<p>&#160;</p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'"><font size=3>还有一些技巧可以让我们对共享资源的同步访问更加安全：</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 18pt; TEXT-INDENT: -18pt; mso-list: l1 level1 lfo2; tab-stops: list 18.0pt"><span lang=EN-US style="mso-fareast-font-family: 'Times New Roman'"><span style="mso-list: Ignore"><font face="Times New Roman"><font size=3>1．</font><span style="FONT: 7pt 'Times New Roman'">&nbsp; </span></font></span></span><font size=3><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">定义</span><span lang=EN-US><font face="Times New Roman">private </font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的</span><span lang=EN-US><font face="Times New Roman">instance</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">变量</span><span lang=EN-US><font face="Times New Roman">+</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">它的</span><span lang=EN-US><font face="Times New Roman"> get</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">方法，而不要定义</span><span lang=EN-US><font face="Times New Roman">public/protected</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的</span><span lang=EN-US><font face="Times New Roman">instance</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">变量。如果将变量定义为</span><span lang=EN-US><font face="Times New Roman">public</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，对象在外界可以绕过同步方法的控制而直接取得它，并改动它。这也是</span><span lang=EN-US><font face="Times New Roman">JavaBean</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的标准实现方式之一。</span></font></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 18pt; TEXT-INDENT: -18pt; mso-list: l1 level1 lfo2; tab-stops: list 18.0pt"><span lang=EN-US style="mso-fareast-font-family: 'Times New Roman'"><span style="mso-list: Ignore"><font face="Times New Roman"><font size=3>2．</font><span style="FONT: 7pt 'Times New Roman'">&nbsp; </span></font></span></span><font size=3><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">如果</span><span lang=EN-US><font face="Times New Roman">instance</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">变量是一个对象，如数组或</span><span lang=EN-US><font face="Times New Roman">ArrayList</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">什么的，那上述方法仍然不安全，因为当外界对象通过</span><span lang=EN-US><font face="Times New Roman">get</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">方法拿到这个</span><span lang=EN-US><font face="Times New Roman">instance</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">对象的引用后，又将其指向另一个对象，那么这个</span><span lang=EN-US><font face="Times New Roman">private</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">变量也就变了，岂不是很危险。</span><font face="Times New Roman"> </font><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">这个时候就需要将</span><span lang=EN-US><font face="Times New Roman">get</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">方法也加上</span><span lang=EN-US><font face="Times New Roman">synchronized</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">同步，并且，只返回这个</span><span lang=EN-US><font face="Times New Roman">private</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">对象的</span><span lang=EN-US><font face="Times New Roman">clone()</font></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">――这样，调用端得到的就是对象副本的引用了。</span></font></p>
</span>
<img src ="http://www.blogjava.net/mayu/aggbug/122887.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mayu/" target="_blank">my</a> 2007-06-08 17:09 <a href="http://www.blogjava.net/mayu/articles/122887.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转 Java RunTime类</title><link>http://www.blogjava.net/mayu/articles/122814.html</link><dc:creator>my</dc:creator><author>my</author><pubDate>Fri, 08 Jun 2007 04:02:00 GMT</pubDate><guid>http://www.blogjava.net/mayu/articles/122814.html</guid><wfw:comment>http://www.blogjava.net/mayu/comments/122814.html</wfw:comment><comments>http://www.blogjava.net/mayu/articles/122814.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mayu/comments/commentRss/122814.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mayu/services/trackbacks/122814.html</trackback:ping><description><![CDATA[<p align=center><span class=Title>RunTime</span></p>
<p>&nbsp;</p>
<p>Java的类库日益庞大，所包含的类和接口也不计其数。但其中有一些非常重要的类和接口，是Java类库中的核心部分。常见的有String、Object、Class、Collection、ClassLoader、Runtime、Process...，熟悉这些类是学好Java的基础。而这些类一般不容易理解，需要做深入的研究和实践才能掌握。下面是我对这些类理解和使用的一些总结。欢迎你在阅读后将你宝贵的意见和读后感留下！ </p>
<p>leizhimin 51cto技术博客<br>&nbsp; </p>
<p>leizhimin 51cto技术博客<br>一、概述<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Runtime类封装了运行时的环境。每个 Java 应用程序都有一个 Runtime 类实例，使应用程序能够与其运行的环境相连接。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一般不能实例化一个Runtime对象，应用程序也不能创建自己的 Runtime 类实例，但可以通过 getRuntime 方法获取当前Runtime运行时对象的引用。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一旦得到了一个当前的Runtime对象的引用，就可以调用Runtime对象的方法去控制Java虚拟机的状态和行为。 <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当Applet和其他不被信任的代码调用任何Runtime方法时，常常会引起SecurityException异常。 </p>
<p>leizhimin 51cto技术博客<br>&nbsp; </p>
<p>leizhimin 51cto技术博客<br>二、API预览<br>&nbsp;&nbsp;&nbsp; addShutdownHook(Thread hook) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 注册新的虚拟机来关闭挂钩。 <br>&nbsp;&nbsp;&nbsp; availableProcessors() <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 向 Java 虚拟机返回可用处理器的数目。 <br>&nbsp;&nbsp;&nbsp; exec(String command) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在单独的进程中执行指定的字符串命令。 <br>&nbsp;&nbsp;&nbsp; exec(String[] cmdarray) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在单独的进程中执行指定命令和变量。 <br>&nbsp;&nbsp;&nbsp; exec(String[] cmdarray, String[] envp) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在指定环境的独立进程中执行指定命令和变量。 <br>&nbsp;&nbsp;&nbsp; exec(String[] cmdarray, String[] envp, File dir) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在指定环境和工作目录的独立进程中执行指定的命令和变量。 <br>&nbsp;&nbsp;&nbsp; exec(String command, String[] envp) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在指定环境的单独进程中执行指定的字符串命令。 <br>&nbsp;&nbsp;&nbsp; exec(String command, String[] envp, File dir) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在有指定环境和工作目录的独立进程中执行指定的字符串命令。 <br>&nbsp;&nbsp;&nbsp; exit(int status) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 通过启动虚拟机的关闭序列，终止当前正在运行的 Java 虚拟机。 <br>&nbsp;&nbsp;&nbsp; freeMemory() <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 返回 Java 虚拟机中的空闲内存量。 <br>&nbsp;&nbsp;&nbsp; gc() <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 运行垃圾回收器。 <br>&nbsp;&nbsp;&nbsp; InputStream getLocalizedInputStream(InputStream in) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 已过时。 从 JDK 1.1 开始，将本地编码字节流转换为 Unicode 字符流的首选方法是使用 InputStreamReader 和 BufferedReader 类。 <br>&nbsp;&nbsp;&nbsp; OutputStream getLocalizedOutputStream(OutputStream out) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 已过时。 从 JDK 1.1 开始，将 Unicode 字符流转换为本地编码字节流的首选方法是使用 OutputStreamWriter、BufferedWriter 和 PrintWriter 类。 <br>&nbsp;&nbsp;&nbsp; getRuntime() <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 返回与当前 Java 应用程序相关的运行时对象。 <br>&nbsp;&nbsp;&nbsp; halt(int status) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 强行终止目前正在运行的 Java 虚拟机。 <br>&nbsp;&nbsp;&nbsp; load(String filename) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 加载作为动态库的指定文件名。 <br>&nbsp;&nbsp;&nbsp; loadLibrary(String libname) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 加载具有指定库名的动态库。 <br>&nbsp;&nbsp;&nbsp; maxMemory() <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 返回 Java 虚拟机试图使用的最大内存量。 <br>&nbsp;&nbsp;&nbsp; removeShutdownHook(Thread hook) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 取消注册某个先前已注册的虚拟机关闭挂钩。 <br>&nbsp;&nbsp;&nbsp; runFinalization() <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 运行挂起 finalization 的所有对象的终止方法。 <br>&nbsp;&nbsp;&nbsp; runFinalizersOnExit(value) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 已过时。 此方法本身具有不安全性。它可能对正在使用的对象调用终结方法，而其他线程正在操作这些对象，从而导致不正确的行为或死锁。 <br>&nbsp;&nbsp;&nbsp; totalMemory() <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 返回 Java 虚拟机中的内存总量。 <br>&nbsp;&nbsp;&nbsp; traceInstructions(on) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 启用／禁用指令跟踪。 <br>&nbsp;&nbsp;&nbsp; traceMethodCalls(on) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 启用／禁用方法调用跟踪。 </p>
<p>leizhimin 51cto技术博客<br>&nbsp; </p>
<p>leizhimin 51cto技术博客<br>三、常见的应用</p>
<p><br>leizhimin 51cto技术博客<br>1、内存管理：<br>Java提供了无用单元自动收集机制。通过totalMemory()和freeMemory()方法可以知道对象的堆内存有多大，还剩多少。<br>Java会周期性的回收垃圾对象（未使用的对象），以便释放内存空间。但是如果想先于收集器的下一次指定周期来收集废弃的对象，可以通过调用gc()方法来根据需要运行无用单元收集器。一个很好的试验方法是先调用gc()方法，然后调用freeMemory()方法来查看基本的内存使用情况，接着执行代码，然后再次调用freeMemory()方法看看分配了多少内存。下面的程序演示了这个构想。 </p>
<p>leizhimin 51cto技术博客<br>//此实例来自《java核心技术》卷一<br>class MemoryDemo{<br>&nbsp;&nbsp;&nbsp; public static void main(String args[]){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Runtime r = Runtime.getRuntime();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; long mem1,mem2;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Integer someints[] = new Integer[1000];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("Total memory is ：" + r.totalMemory());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mem1 = r.freeMemory();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("Initial free is : " + mem1);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; r.gc();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mem1 = r.freeMemory();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("Free memory after garbage collection : " + mem1);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //allocate integers<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(int i=0; i&lt;1000; i++) someints[i] = new Integer(i); </p>
<p>leizhimin 51cto技术博客<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mem2 = r.freeMemory();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("Free memory after allocation : " + mem2);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("Memory used by allocation : " +(mem1-mem2)); </p>
<p>leizhimin 51cto技术博客<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //discard Intergers<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(int i=0; i&lt;1000; i++) someints[i] = null;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; r.gc(); //request garbage collection<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mem2 = r.freeMemory();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("Free memory after collecting " + "discarded integers : " + mem2);<br>&nbsp;&nbsp;&nbsp; }<br>} </p>
<p>leizhimin 51cto技术博客<br>编译后运行结果如下（不同的机器不同时间运行的结果也不一定一样）：<br>Total memory is ：2031616<br>Initial free is : 1818488<br>Free memory after garbage collection : 1888808<br>Free memory after allocation : 1872224<br>Memory used by allocation : 16584<br>Free memory after collecting discarded integers : 1888808 </p>
<p>leizhimin 51cto技术博客<br>&nbsp; </p>
<p>leizhimin 51cto技术博客<br>2、执行其他程序<br>在安全的环境中，可以在多任务操作系统中使用Java去执行其他特别大的进程（也就是程序）。ecec()方法有几种形式命名想要运行的程序和它的输入参数。ecec()方法返回一个Process对象，可以使用这个对象控制Java程序与新运行的进程进行交互。ecec()方法本质是依赖于环境。<br>下面的例子是使用ecec()方法启动windows的记事本notepad。这个例子必须在Windows操作系统上运行。 </p>
<p>leizhimin 51cto技术博客<br>//此实例来自《Java核心技术》卷一<br>class ExecDemo {<br>&nbsp;&nbsp;&nbsp; public static void main(String args[]){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Runtime r = Runtime.getRuntime();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Process p = null;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; p = r.exec("notepad");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (Exception e) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("Error executing notepad.");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>} </p>
<p>leizhimin 51cto技术博客<br>ecec()还有其他几种形式，例子中演示的是最常用的一种。ecec()方法返回Process对象后，在新程序开始运行后就可以使用Process的方法了。可以用destory()方法杀死子进程，也可以使用waitFor()方法等待程序直到子程序结束，exitValue()方法返回子进程结束时返回的值。如果没有错误，将返回0，否则返回非0。下面是关于ecec()方法的例子的改进版本。例子被修改为等待，直到运行的进程退出： </p>
<p>leizhimin 51cto技术博客<br>//此实例来自《Java核心技术》卷一<br>class ExecDemoFini {<br>&nbsp;&nbsp;&nbsp; public static void main(String args[]){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Runtime r = Runtime.getRuntime();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Process p = null;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; p = r.exec("notepad");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; p.waitFor();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (Exception e) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("Error executing notepad.");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("Notepad returned " + p.exitValue());<br>&nbsp;&nbsp;&nbsp; }<br>}<br>下面是运行的结果（当关闭记事本后，会接着运行程序，打印信息）：<br>Notepad returned 0<br>请按任意键继续. . . </p>
<p><br>当子进程正在运行时，可以对标准输入输出进行读写。getOutputStream()方法和getInPutStream()方法返回对子进程的标准输入和输出。 </p>
<a href="http://blog.csdn.net/baileyfu/archive/2007/05/16/1612067.aspx"><u><font color=#800080></font></u></a>
<img src ="http://www.blogjava.net/mayu/aggbug/122814.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mayu/" target="_blank">my</a> 2007-06-08 12:02 <a href="http://www.blogjava.net/mayu/articles/122814.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java程序员面试三十二问 </title><link>http://www.blogjava.net/mayu/articles/120851.html</link><dc:creator>my</dc:creator><author>my</author><pubDate>Wed, 30 May 2007 03:24:00 GMT</pubDate><guid>http://www.blogjava.net/mayu/articles/120851.html</guid><wfw:comment>http://www.blogjava.net/mayu/comments/120851.html</wfw:comment><comments>http://www.blogjava.net/mayu/articles/120851.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mayu/comments/commentRss/120851.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mayu/services/trackbacks/120851.html</trackback:ping><description><![CDATA[第一，谈谈final，&nbsp;finally，&nbsp;finalize的区别。&nbsp;<br>&nbsp;第二，Anonymous&nbsp;Inner&nbsp;Class&nbsp;（匿名内部类）&nbsp;是否可<br>&nbsp;以extends（继承）其它类，是否可以&nbsp;<br>&nbsp;implements（实现）interface（接口）？&nbsp;<br>&nbsp;第三，Static&nbsp;Nested&nbsp;Class&nbsp;和&nbsp;Inner&nbsp;Class的不同，说得<br>&nbsp;越多越好（面试题有的很笼统）。&nbsp;<br>&nbsp;第四，&amp;和&amp;&amp;的区别。&nbsp;<br>&nbsp;第五，HashMap和Hashtable的区别。&nbsp;<br>&nbsp;第六，Collection&nbsp;和&nbsp;Collections的区别。&nbsp;<br>&nbsp;第七，什么时候用assert.&nbsp;<br>&nbsp;第八，GC是什么？&nbsp;为什么要有GC？&nbsp;<br>&nbsp;第九，String&nbsp;s&nbsp;=&nbsp;new&nbsp;String（"xyz"）；创建了几个String&nbsp;<br>&nbsp;Object？&nbsp;<br>&nbsp;第十，Math.round（11.5）等於多少？&nbsp;<br>&nbsp;Math.round（-11.5）等於多少？&nbsp;<br>&nbsp;第十一，short&nbsp;s1&nbsp;=&nbsp;1；&nbsp;s1&nbsp;=&nbsp;s1&nbsp;+&nbsp;1；有什么错？&nbsp;short&nbsp;<br>&nbsp;s1&nbsp;=&nbsp;1；&nbsp;s1&nbsp;+=&nbsp;1；有什么错？&nbsp;<br>&nbsp;第十二，sleep（）&nbsp;和&nbsp;wait（）&nbsp;有什么区别？&nbsp;<br>&nbsp;第十三，Java有没有goto？&nbsp;<br>&nbsp;第十四，数组有没有length（）这个方法？&nbsp;String有没<br>&nbsp;有length（）这个方法？&nbsp;<br>&nbsp;第十五，Overload和Override的区别。Overloaded的方<br>&nbsp;法是否可以改变返回值的类型？&nbsp;<br>&nbsp;第十六，Set里的元素是不能重复的，那么用什么方法<br>&nbsp;来区分重复与否呢？&nbsp;是用==还是equals（）？&nbsp;<br>&nbsp;它们有何区别？&nbsp;<br>&nbsp;第十七，给我一个你最常见到的runtime&nbsp;exception.&nbsp;<br>&nbsp;第十八，error和exception有什么区别？&nbsp;<br>&nbsp;第十九，List，&nbsp;Set，&nbsp;Map是否继承自Collection接口？&nbsp;<br>&nbsp;第二十，abstract&nbsp;class和interface有什么区别？&nbsp;<br>&nbsp;第二十一，abstract的method是否可同时是static，是否<br>&nbsp;可同时是native，是否可同时是&nbsp;<br>&nbsp;synchronized？&nbsp;<br>&nbsp;第二十二，接口是否可继承接口？&nbsp;抽象类是否可实现（<br>&nbsp;implements）接口？&nbsp;抽象类是否可继承实体&nbsp;<br>&nbsp;类（concrete&nbsp;class）？&nbsp;<br>&nbsp;第二十三，启动一个线程是用run（）还是start（）？&nbsp;<br>&nbsp;第二十四，构造器Constructor是否可被override？&nbsp;<br>&nbsp;第二十五，是否可以继承String类？&nbsp;<br>&nbsp;第二十六，当一个线程进入一个对象的一<br>&nbsp;个synchronized方法后，其它线程是否可进入此对象的其它&nbsp;<br>&nbsp;方法？&nbsp;<br>&nbsp;第二十七，try&nbsp;{}里有一个return语句，那么紧跟在这<br>&nbsp;个try后的finally&nbsp;{}里的code会不会被执行&nbsp;<br>&nbsp;，什么时候被执行，在return前还是后？&nbsp;<br>&nbsp;第二十八，编程题：&nbsp;用最有效率的方法算出2乘以8等於<br>&nbsp;几？&nbsp;<br>&nbsp;第二十九，两个对象值相同（x.equals（y）&nbsp;==&nbsp;true），<br>&nbsp;但却可有不同的hash&nbsp;code，这句话对不对&nbsp;<br>&nbsp;？&nbsp;<br>&nbsp;第三十，当一个对象被当作参数传递到一个方法后，此<br>&nbsp;方法可改变这个对象的属性，并可返回变化后&nbsp;<br>&nbsp;的结果，那么这里到底是值传递还是引用传递？&nbsp;<br>&nbsp;第三十一，swtich是否能作用在byte上，是否能作用<br>&nbsp;在long上，是否能作用在String上？&nbsp;<br>&nbsp;第三十二，编程题：&nbsp;写一个Singleton出来。&nbsp;<br>&nbsp;以下是答案&nbsp;<br>&nbsp;第一，谈谈final，&nbsp;finally，&nbsp;finalize的区别。&nbsp;<br>&nbsp;final？修饰符（关键字）如果一个类被声明为final，意<br>&nbsp;味着它不能再派生出新的子类，不能作为父类被继承。因此<br>&nbsp;一个类不能既被声明为&nbsp;abstract的，又被声明为final的。将<br>&nbsp;变量或方法声明为final，&nbsp;可以保证它们在使用中不被改变。<br>&nbsp;被声明为final的变量必须在声明时给定初值，而在以后的引<br>&nbsp;用中只能&nbsp;读取，不可修改。被声明为final的方法也同样只能<br>&nbsp;使用，不能重载。finally？再异常处理时提供&nbsp;finally&nbsp;块来执行<br>&nbsp;任何清除操作。如果抛出一个异常，那么相匹配的&nbsp;catch&nbsp;子<br>&nbsp;句就会执行，然后控制就会进入&nbsp;finally&nbsp;块（如果有的话）。&nbsp;<br>&nbsp;finalize？方法名。Java&nbsp;技术允许使用&nbsp;finalize（）&nbsp;方法在垃<br>&nbsp;圾收集器将对象从内存中清除出去&nbsp;之前做必要的清理工作。<br>&nbsp;这个方法是由垃圾收集器在确定这个对象没有被引用时对这<br>&nbsp;个对象调用的。它是&nbsp;在&nbsp;Object&nbsp;类中定义的，因此所有的类<br>&nbsp;都继承了它。子类覆盖&nbsp;finalize（）&nbsp;方法以整理系统资源或<br>&nbsp;者执&nbsp;行其他清理工作。finalize（）&nbsp;方法是在垃圾收集器删<br>&nbsp;除对象之前对这个对象调用的。&nbsp;<br>&nbsp;第二，Anonymous&nbsp;Inner&nbsp;Class&nbsp;（匿名内部类）&nbsp;是否可<br>&nbsp;以extends（继承）其它类，是否可以&nbsp;<br>&nbsp;implements（实现）interface（接口）？&nbsp;<br>&nbsp;匿名的内部类是没有名字的内部类。不能extends（继承<br>&nbsp;）&nbsp;其它类，但一个内部类可以作为一个接口&nbsp;<br>&nbsp;，由另一个内部类实现。&nbsp;<br>&nbsp;第三，Static&nbsp;Nested&nbsp;Class&nbsp;和&nbsp;Inner&nbsp;Class的不同，说得<br>&nbsp;越多越好（面试题有的很笼统）。&nbsp;<br>&nbsp;Nested&nbsp;Class&nbsp;（一般是C++的说法），Inner&nbsp;Class&nbsp;（一<br>&nbsp;般是JAVA的说法）。Java内部类与C++嵌套&nbsp;<br>&nbsp;类最大的不同就在于是否有指向外部的引用上。具体可<br>&nbsp;见http：&nbsp;<br>&nbsp;//www.frontfree.net/articles/services/view.asp？id=704&amp;page<br>&nbsp;=1&nbsp;<br>&nbsp;注：&nbsp;静态内部类（Inner&nbsp;Class）意味着1创建一个static<br>&nbsp;内部类的对象，不需要一个外部类对象，2&nbsp;<br>&nbsp;不能从一个static内部类的一个对象访问一个外部类对象&nbsp;<br>&nbsp;第四，&amp;和&amp;&amp;的区别。&nbsp;<br>&nbsp;&amp;是位运算符。&amp;&amp;是布尔逻辑运算符。&nbsp;<br>&nbsp;第五，HashMap和Hashtable的区别。&nbsp;<br>&nbsp;都属于Map接口的类，实现了将惟一键映射到特定的值<br>&nbsp;上。&nbsp;<br>&nbsp;HashMap&nbsp;类没有分类或者排序。它允许一个&nbsp;null&nbsp;键和多<br>&nbsp;个&nbsp;null&nbsp;值。&nbsp;<br>&nbsp;Hashtable&nbsp;类似于&nbsp;HashMap，但是不允许&nbsp;null&nbsp;键和&nbsp;null&nbsp;<br>&nbsp;值。它也比&nbsp;HashMap&nbsp;慢，因为它是同步&nbsp;<br>&nbsp;的。&nbsp;<br>&nbsp;第六，Collection&nbsp;和&nbsp;Collections的区别。&nbsp;<br>&nbsp;Collections是个java.util下的类，它包含有各种有关集合<br>&nbsp;操作的静态方法。&nbsp;<br>&nbsp;Collection是个java.util下的接口，它是各种集合结构的父<br>&nbsp;接口。&nbsp;<br>&nbsp;第七，什么时候用assert。&nbsp;<br>&nbsp;断言是一个包含布尔表达式的语句，在执行这个语句时假定<br>&nbsp;该表达式为&nbsp;true。如果表达式计算为&nbsp;false，那么系统会报告<br>&nbsp;一个&nbsp;AssertionError。它用于调试目的：&nbsp;<br>&nbsp;assert(a&nbsp;&gt;&nbsp;0);&nbsp;//&nbsp;throws&nbsp;an&nbsp;AssertionError&nbsp;if&nbsp;a&nbsp;&lt;=&nbsp;0&nbsp;<br>&nbsp;断言可以有两种形式：&nbsp;<br>&nbsp;assert&nbsp;Expression1&nbsp;;&nbsp;<br>&nbsp;assert&nbsp;Expression1&nbsp;:&nbsp;Expression2&nbsp;;&nbsp;<br>&nbsp;Expression1&nbsp;应该总是产生一个布尔值。&nbsp;<br>&nbsp;Expression2&nbsp;可以是得出一个值的任意表达式。这个值用于<br>&nbsp;生成显示更多调试信息的&nbsp;String&nbsp;消息。&nbsp;<br>&nbsp;断言在默认情况下是禁用的。要在编译时启用断言，需要使<br>&nbsp;用&nbsp;source&nbsp;1.4&nbsp;标记：&nbsp;<br>&nbsp;javac&nbsp;-source&nbsp;1.4&nbsp;Test.java&nbsp;<br>&nbsp;要在运行时启用断言，可使用&nbsp;-enableassertions&nbsp;或者&nbsp;-ea&nbsp;标<br>&nbsp;记。&nbsp;<br>&nbsp;要在运行时选择禁用断言，可使用&nbsp;-da&nbsp;或者&nbsp;<br>&nbsp;-disableassertions&nbsp;标记。&nbsp;<br>&nbsp;要系统类中启用断言，可使用&nbsp;-esa&nbsp;或者&nbsp;-dsa&nbsp;标记。还可以<br>&nbsp;在包的基础上启用或者禁用断言。&nbsp;可以在预计正常情况下不<br>&nbsp;会到达的任何位置上放置断言。断言可以用于验证传递给私<br>&nbsp;有方法的参数。不过，断言不应该用于验证传递给公有方法<br>&nbsp;的参数，因为不管是否启用了断言，公有方法都必须检查其<br>&nbsp;参数。不过，既可以在公有方法中，也可以在非公有方法中<br>&nbsp;利用断言测试后置条件。另外，断言不应该以任何方式改变<br>&nbsp;程序的状态。&nbsp;<br>&nbsp;第八，GC是什么?&nbsp;为什么要有GC?&nbsp;(基础)。&nbsp;<br>&nbsp;GC是垃圾收集器。Java&nbsp;程序员不用担心内存管理，因为垃<br>&nbsp;圾收集器会自动进行管理。要请求垃圾收&nbsp;<br>&nbsp;集，可以调用下面的方法之一：&nbsp;<br>&nbsp;System.gc()&nbsp;<br>&nbsp;Runtime.getRuntime().gc()&nbsp;<br>&nbsp;第九，String&nbsp;s&nbsp;=&nbsp;new&nbsp;String("xyz");创建了几个String&nbsp;Object?&nbsp;<br>&nbsp;两个对象，一个是"xyx",一个是指向"xyx"的引用对象s。&nbsp;<br>&nbsp;第十，Math.round(11.5)等於多少?&nbsp;Math.round(-11.5)等於多<br>&nbsp;少?&nbsp;<br>&nbsp;Math.round(11.5)返回（long）12，Math.round(-11.5)返<br>&nbsp;回（long）-11;&nbsp;<br>&nbsp;第十一，short&nbsp;s1&nbsp;=&nbsp;1;&nbsp;s1&nbsp;=&nbsp;s1&nbsp;+&nbsp;1;有什么错?&nbsp;short&nbsp;s1&nbsp;=&nbsp;1;&nbsp;s1&nbsp;<br>&nbsp;+=&nbsp;1;有什么错?&nbsp;<br>&nbsp;short&nbsp;s1&nbsp;=&nbsp;1;&nbsp;s1&nbsp;=&nbsp;s1&nbsp;+&nbsp;1;有错，s1是short型，s1+1是int型,不<br>&nbsp;能显式转化为short型。可修改为&nbsp;s1&nbsp;=(short)(s1&nbsp;+&nbsp;1)&nbsp;。short&nbsp;<br>&nbsp;s1&nbsp;=&nbsp;1;&nbsp;s1&nbsp;+=&nbsp;1正确。&nbsp;<br>&nbsp;第十二，sleep()&nbsp;和&nbsp;wait()&nbsp;有什么区别?&nbsp;搞线程的最爱&nbsp;<br>&nbsp;sleep()方法是使线程停止一段时间的方法。在sleep&nbsp;时间间<br>&nbsp;隔期满后，线程不一定立即恢复执行。&nbsp;这是因为在那个时刻<br>&nbsp;，其它线程可能正在运行而且没有被调度为放弃执行，除<br>&nbsp;非(a)"醒来"的线程具有更高的优先级，(b)正在运行的线程因<br>&nbsp;为其它原因而阻塞。&nbsp;<br>&nbsp;wait()是线程交互时，如果线程对一个同步对象x&nbsp;发出一<br>&nbsp;个wait()调用，该线程会暂停执行，被调对象进入等待状态，<br>&nbsp;直到被唤醒或等待时间到。&nbsp;<br>&nbsp;第十三，Java有没有goto?&nbsp;<br>&nbsp;Goto?java中的保留字，现在没有在java中使用。&nbsp;<br>&nbsp;第十四，数组有没有length()这个方法?&nbsp;String有没有length()<br>&nbsp;这个方法？&nbsp;<br>&nbsp;数组没有length()这个方法，有length的属性。&nbsp;<br>&nbsp;String有有length()这个方法。<br>&nbsp;&nbsp;<br>&nbsp;第十五，Overload和Override的区别。Overloaded的方法是<br>&nbsp;否可以改变返回值的类型?&nbsp;<br>&nbsp;方法的重写Overriding和重载Overloading是Java多态性的不<br>&nbsp;同表现。重写Overriding是父类与子类&nbsp;之间多态性的一种表<br>&nbsp;现，重载Overloading是一个类中多态性的一种表现。如果在<br>&nbsp;子类中定义某方法与其父类有相同的名称和参数，我们说该<br>&nbsp;方法被重写&nbsp;(Overriding)。子类的对象使用这个方法时，将调<br>&nbsp;用子类中的定义，对它而言，父类中的定义如同被"屏蔽"了<br>&nbsp;。如果在一个类中定义了多个同名的方法，它们或有不同的<br>&nbsp;参数个数或有不同的参数类型，则称为方法的重<br>&nbsp;载(Overloading)。Overloaded的方法是可以改变返回值的类<br>&nbsp;型。&nbsp;<br>&nbsp;第十六，Set里的元素是不能重复的，那么用什么方法来区<br>&nbsp;分重复与否呢?&nbsp;是用==还是equals()?&nbsp;它们有何区别?&nbsp;<br>&nbsp;Set里的元素是不能重复的，那么用iterator()方法来区分重复<br>&nbsp;与否。equals()是判读两个Set是否相&nbsp;等。&nbsp;<br>&nbsp;equals()和==方法决定引用值是否指向同一对象equals()在类<br>&nbsp;中被覆盖，为的是当两个分离的对象的内容和类型相配的话<br>&nbsp;，返回真值。&nbsp;<br>&nbsp;第十七，给我一个你最常见到的runtime&nbsp;exception。&nbsp;<br>&nbsp;ArithmeticException,&nbsp;ArrayStoreException,&nbsp;<br>&nbsp;BufferOverflowException,&nbsp;<br>&nbsp;BufferUnderflowException,&nbsp;CannotRedoException,&nbsp;<br>&nbsp;CannotUndoException,&nbsp;ClassCastException,&nbsp;<br>&nbsp;CMMException,&nbsp;ConcurrentModificationException,&nbsp;<br>&nbsp;DOMException,&nbsp;EmptyStackException,&nbsp;<br>&nbsp;IllegalArgumentException,&nbsp;IllegalMonitorStateException,&nbsp;<br>&nbsp;IllegalPathStateException,&nbsp;<br>&nbsp;IllegalStateException,&nbsp;ImagingOpException,&nbsp;<br>&nbsp;IndexOutOfBoundsException,&nbsp;<br>&nbsp;MissingResourceException,&nbsp;NegativeArraySizeException,&nbsp;<br>&nbsp;NoSuchElementException,&nbsp;<br>&nbsp;NullPointerException,&nbsp;ProfileDataException,&nbsp;<br>&nbsp;ProviderException,&nbsp;RasterFormatException,&nbsp;<br>&nbsp;SecurityException,&nbsp;SystemException,&nbsp;<br>&nbsp;UndeclaredThrowableException,&nbsp;UnmodifiableSetException,&nbsp;<br>&nbsp;UnsupportedOperationException&nbsp;<br>&nbsp;第十八，error和exception有什么区别?&nbsp;<br>&nbsp;error&nbsp;表示恢复不是不可能但很困难的情况下的一种严重问题<br>&nbsp;。比如说内存溢出。不可能指望程序能处理这样的情况。&nbsp;<br>&nbsp;exception&nbsp;表示一种设计或实现问题。也就是说，它表示如果<br>&nbsp;程序运行正常，从不会发生的情况。&nbsp;<br>&nbsp;第十九，List,&nbsp;Set,&nbsp;Map是否继承自Collection接口?&nbsp;<br>&nbsp;List，Set是&nbsp;<br>&nbsp;Map不是&nbsp;<br>&nbsp;第二十，abstract&nbsp;class和interface有什么区别?&nbsp;<br>&nbsp;声明方法的存在而不去实现它的类被叫做抽象类（abstract&nbsp;<br>&nbsp;class），它用于要创建一个体现某些基本行为的类，并为该<br>&nbsp;类声明方法，但不能在该类中实现该类的情况。不能创<br>&nbsp;建abstract&nbsp;类的实例。然而可以创建一个变量，其类型是一<br>&nbsp;个抽象类，并让它指向具体子类的一个实例。不能有抽象构<br>&nbsp;造函数或抽象静态方法。Abstract&nbsp;类的子类为它们父类中的<br>&nbsp;所有抽象方法提供实现，否则它们也是抽象类为。取而代之<br>&nbsp;，在子类中实现该方法。知道其行为的其它类可以在类中实<br>&nbsp;现这些方法。&nbsp;<br>&nbsp;接口（interface）是抽象类的变体。在接口中，所有方法都<br>&nbsp;是抽象的。多继承性可通过实现这样的接口而获得。接口中<br>&nbsp;的所有方法都是抽象的，没有一个有程序体。接口只可以定<br>&nbsp;义static&nbsp;final成员变量。接口的实现与子类相似，除了该实现<br>&nbsp;类不能从接口定义中继承行为。当类实现特殊接口时，它定<br>&nbsp;义（即将程序体给予）所有这种接口的方法。然后，它可以<br>&nbsp;在实现了该接口的类的任何对象上调用接口的方法.由于有抽<br>&nbsp;象类，它允许使用接口名作为引用变量的类型。通常的动态<br>&nbsp;联编将生效。引用可以转换到接口类型或从接口类型转<br>&nbsp;换，instanceof&nbsp;运算符可以用来决定某对象的类是否实现了<br>&nbsp;接口。&nbsp;<br>&nbsp;第二十一，abstract的method是否可同时是static,是否可同时<br>&nbsp;是native，是否可同时是&nbsp;<br>&nbsp;synchronized?&nbsp;<br>&nbsp;都不能&nbsp;<br>&nbsp;第二十二，接口是否可继承接口?&nbsp;抽象类是否可实<br>&nbsp;现(implements)接口?&nbsp;抽象类是否可继承实体类&nbsp;<br>&nbsp;(concrete&nbsp;class)?&nbsp;<br>&nbsp;接口可以继承接口。抽象类可以实现(implements)接口，抽象<br>&nbsp;类是否可继承实体类，但前提是实体类必须有明确的构造函<br>&nbsp;数。&nbsp;<br>&nbsp;第二十三，启动一个线程是用run()还是start()?&nbsp;<br>&nbsp;启动一个线程是调用start()方法，使线程所代表的虚拟处理<br>&nbsp;机处于可运行状态，这意味着它可以由JVM调度并执行。这<br>&nbsp;并不意味着线程就会立即运行。run()方法可以产生必须退出<br>&nbsp;的标志来停止一个线程。&nbsp;<br>&nbsp;&nbsp;<br>&nbsp;第二十四，构造器Constructor是否可被override?&nbsp;<br>&nbsp;构造器Constructor不能被继承，因此不能重写Overriding，但<br>&nbsp;可以被重载Overloading。&nbsp;<br>&nbsp;第二十五，是否可以继承String类?&nbsp;<br>&nbsp;String类是final类故不可以继承。&nbsp;<br>&nbsp;第二十六，当一个线程进入一个对象的一个synchronized方<br>&nbsp;法后，其它线程是否可进入此对象的其它方法?&nbsp;<br>&nbsp;不能，一个对象的一个synchronized方法只能由一个线程访<br>&nbsp;问。&nbsp;<br>&nbsp;第二十七，try&nbsp;{}里有一个return语句，那么紧跟在这个try后<br>&nbsp;的finally&nbsp;{}里的code会不会被执行，什么时候被执<br>&nbsp;行，在return前还是后?&nbsp;<br>&nbsp;会执行，在return前执行。&nbsp;<br>&nbsp;第二十八，编程题:&nbsp;用最有效率的方法算出2乘以8等於几?&nbsp;<br>&nbsp;有C背景的程序员特别喜欢问这种问题。&nbsp;<br>&nbsp;2&nbsp;&lt;&lt;&nbsp;3&nbsp;<br>&nbsp;第二十九，两个对象值相同(x.equals(y)&nbsp;==&nbsp;true)，但却可有<br>&nbsp;不同的hash&nbsp;code，这句话对不对?&nbsp;<br>&nbsp;不对，有相同的hash&nbsp;code。&nbsp;<br>&nbsp;第三十，当一个对象被当作参数传递到一个方法后，此方法<br>&nbsp;可改变这个对象的属性，并可返回变化后的结果，那么这里<br>&nbsp;到底是值传递还是引用传递?&nbsp;<br>&nbsp;是值传递。Java&nbsp;编程语言只由值传递参数。当一个对象实例<br>&nbsp;作为一个参数被传递到方法中时，参数的值就是对该对象的<br>&nbsp;引用。对象的内容可以在被调用的方法中改变，但对象的引<br>&nbsp;用是永远不会改变的。&nbsp;<br>&nbsp;第三十一，swtich是否能作用在byte上，是否能作用在long上<br>&nbsp;，是否能作用在String上?&nbsp;<br>&nbsp;switch（expr1）中，expr1是一个整数表达式。因此传递给&nbsp;<br>&nbsp;switch&nbsp;和&nbsp;case&nbsp;语句的参数应该是&nbsp;int、&nbsp;short、&nbsp;char&nbsp;或者&nbsp;<br>&nbsp;byte。long,string&nbsp;都不能作用于swtich。&nbsp;<br>&nbsp;第三十二，编程题:&nbsp;写一个Singleton出来。&nbsp;<br>&nbsp;Singleton模式主要作用是保证在Java应用程序中，一个<br>&nbsp;类Class只有一个实例存在。&nbsp;<br>&nbsp;一般Singleton模式通常有几种种形式:&nbsp;<br>&nbsp;第一种形式:&nbsp;定义一个类，它的构造函数为private的，<br>&nbsp;它有一个static的private的该类变量，&nbsp;在类初始化时实例话<br>&nbsp;，通过一个public的getInstance方法获取对它的引用,继而调<br>&nbsp;用其中的方法。&nbsp;<br>&nbsp;public&nbsp;class&nbsp;Singleton&nbsp;{&nbsp;<br>&nbsp;private&nbsp;Singleton(){}&nbsp;<br>&nbsp;//在自己内部定义自己一个实例，是不是很奇怪？&nbsp;<br>&nbsp;//注意这是private&nbsp;只供内部调用&nbsp;<br>&nbsp;private&nbsp;static&nbsp;Singleton&nbsp;instance&nbsp;=&nbsp;new&nbsp;Singleton();&nbsp;<br>&nbsp;//这里提供了一个供外部访问本class的静态方法，可以直接<br>&nbsp;访问&nbsp;<br>&nbsp;public&nbsp;static&nbsp;Singleton&nbsp;getInstance()&nbsp;{&nbsp;<br>&nbsp;return&nbsp;instance;&nbsp;<br>&nbsp;}&nbsp;<br>&nbsp;}&nbsp;<br>&nbsp;第二种形式:&nbsp;<br>&nbsp;public&nbsp;class&nbsp;Singleton&nbsp;{&nbsp;<br>&nbsp;private&nbsp;static&nbsp;Singleton&nbsp;instance&nbsp;=&nbsp;null;&nbsp;<br>&nbsp;public&nbsp;static&nbsp;synchronized&nbsp;Singleton&nbsp;getInstance()&nbsp;{&nbsp;<br>&nbsp;//这个方法比上面有所改进，不用每次都进行生成对象，只<br>&nbsp;是第一次&nbsp;<br>&nbsp;//使用时生成实例，提高了效率！&nbsp;<br>&nbsp;if&nbsp;(instance==null)&nbsp;<br>&nbsp;instance＝new&nbsp;Singleton();&nbsp;<br>&nbsp;return&nbsp;instance;&nbsp;}&nbsp;<br>&nbsp;}&nbsp;<br>&nbsp;其他形式:&nbsp;<br>&nbsp;定义一个类，它的构造函数为private的，所有方法为static的<br>&nbsp;。&nbsp;<br>&nbsp;一般认为第一种形式要更加安全些&nbsp;<br>&nbsp;第三十三&nbsp;Hashtable和HashMap&nbsp;<br>&nbsp;Hashtable继承自Dictionary类，而HashMap是Java1.2引进的<br>&nbsp;Map&nbsp;interface的一个实现&nbsp;<br>&nbsp;HashMap允许将null作为一个entry的key或<br>&nbsp;者value，而Hashtable不允许&nbsp;<br>&nbsp;还有就是，HashMap把Hashtable的contains方法去掉了，改<br>&nbsp;成containsvalue和containsKey。因为&nbsp;contains方法容易让人<br>&nbsp;引起误解。&nbsp;<br>&nbsp;最大的不同是，Hashtable的方法<br>&nbsp;是Synchronize的，而HashMap不是，在多个线程访<br>&nbsp;问Hashtable时，不需要自己为它的方法实现同<br>&nbsp;步，而HashMap就必须为之提供外同步。&nbsp;<br>&nbsp;Hashtable和HashMap采用的hash/rehash算法都大概一样，<br>&nbsp;所以性能不会有很大的差异&nbsp;<br>
<img src ="http://www.blogjava.net/mayu/aggbug/120851.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mayu/" target="_blank">my</a> 2007-05-30 11:24 <a href="http://www.blogjava.net/mayu/articles/120851.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>详细解析Java中抽象类和接口的区别 转帖</title><link>http://www.blogjava.net/mayu/articles/120813.html</link><dc:creator>my</dc:creator><author>my</author><pubDate>Wed, 30 May 2007 02:07:00 GMT</pubDate><guid>http://www.blogjava.net/mayu/articles/120813.html</guid><wfw:comment>http://www.blogjava.net/mayu/comments/120813.html</wfw:comment><comments>http://www.blogjava.net/mayu/articles/120813.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mayu/comments/commentRss/120813.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mayu/services/trackbacks/120813.html</trackback:ping><description><![CDATA[在Java语言中，&nbsp;abstract&nbsp;class&nbsp;和interface&nbsp;是支持抽象类定义的两种机制。正是由于这两种机制的存在，才赋予了Java强大的&nbsp;面向对象能力。abstract&nbsp;class和interface之间在对于抽象类定义的支持方面具有很大的相似性，甚至可以相互替换，因此很多开发者在进&nbsp;行抽象类定义时对于abstract&nbsp;class和interface的选择显得比较随意。其实，两者之间还是有很大的区别的，对于它们的选择甚至反映出对&nbsp;于问题领域本质的理解、对于设计意图的理解是否正确、合理。本文将对它们之间的区别进行一番剖析，试图给开发者提供一个在二者之间进行选择的依据。&nbsp;
<p>&#160;</p>
<p>&nbsp;<br>&nbsp;理解抽象类<br>&nbsp;abstract&nbsp;class和interface在Java语言中都是用来进行抽象类（本文&nbsp;中的抽象类并非从abstract&nbsp;class翻译而来，它表示的是一个抽象体，而abstract&nbsp;class为Java语言中用于定义抽象类的一种方法，&nbsp;请读者注意区分）定义的，那么什么是抽象类，使用抽象类能为我们带来什么好处呢？</p>
<p>&nbsp;在&nbsp;面向对象的概念中，我们知道所有的对象都是通过类来描绘的，但是反过来却不是这样。并不是&nbsp;所有的类都是用来描绘对象的，如果一个类中没有包含足够的信息来描绘一个具体的对象，这样的类就是抽象类。抽象类往往用来表征我们在对问题领域进行分析、&nbsp;设计中得出的抽象概念，是对一系列看上去不同，但是本质上相同的具体概念的抽象。比如：如果我们进行一个图形编辑软件的开发，就会发现问题领域存在着圆、&nbsp;三角形这样一些具体概念，它们是不同的，但是它们又都属于形状这样一个概念，形状这个概念在问题领域是不存在的，它就是一个抽象概念。正是因为抽象的概念&nbsp;在问题领域没有对应的具体概念，所以用以表征抽象概念的抽象类是不能够实例化的。</p>
<p>&nbsp;在面向对象领域，抽象类主要用来进行类型隐藏。&nbsp;我们可以构造出一个固定的一组行为的抽象描&nbsp;述，但是这组行为却能够有任意个可能的具体实现方式。这个抽象描述就是抽象类，而这一组任意个可能的具体实现则表现为所有可能的派生类。模块可以操作一个&nbsp;抽象体。由于模块依赖于一个固定的抽象体，因此它可以是不允许修改的；同时，通过从这个抽象体派生，也可扩展此模块的行为功能。熟悉OCP的读者一定知&nbsp;道，为了能够实现面向对象设计的一个最核心的原则OCP(Open-Closed&nbsp;Principle)，抽象类是其中的关键所在。</p>
<p>&nbsp;从语法定义层面看abstract&nbsp;class&nbsp;和&nbsp;interface<br>&nbsp;在语法层面，Java语言对于abstract&nbsp;class和interface给出了不同的定义方式，下面以定义一个名为Demo的抽象类为例来说明这种不同。</p>
<p>&nbsp;使用abstract&nbsp;class的方式定义Demo抽象类的方式如下：</p>
<p>&nbsp;abstract&nbsp;class&nbsp;Demo｛<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;abstract&nbsp;void&nbsp;method1();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;abstract&nbsp;void&nbsp;method2();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#8230;<br>&nbsp;｝</p>
<p>&nbsp;使用interface的方式定义Demo抽象类的方式如下：</p>
<p>&nbsp;interface&nbsp;Demo{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;method1();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;method2();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#8230;<br>&nbsp;}</p>
<p>&nbsp;在abstract&nbsp;class方式中，Demo可以有自己的数据成员，也可以有非&nbsp;abstract的成员方法，而在interface方式的实现中，Demo只能够有静态的不能被修改的数据成员（也就是必须是static&nbsp;final&nbsp;的，不过在interface中一般不定义数据成员），所有的成员方法都是abstract的。从某种意义上说，interface是一种特殊形式的&nbsp;abstract&nbsp;class。</p>
<p>&nbsp;从编程的角度来看，abstract&nbsp;class和interface都可以用来实现&nbsp;"design&nbsp;by&nbsp;contract"&nbsp;的思想。但是在具体的使用上面还是有一些区别的。</p>
<p>&nbsp;首先，abstract&nbsp;class&nbsp;在&nbsp;Java&nbsp;语言中表示的是一种继承关系，一个类只能使用一次继承关系(因为Java不支持多继承&nbsp;--&nbsp;转注)。但是，一个类却可以实现多个interface。也许，这是Java语言的设计者在考虑Java对于多重继承的支持方面的一种折中考虑吧。</p>
<p>&nbsp;其次，在abstract&nbsp;class的定义中，我们可以赋予方法的默认行为。但是在interface的定义中，方法却不能拥有默认行为，为了绕过这个限制，必须使用委托，但是这会增加一些复杂性，有时会造成很大的麻烦。</p>
<p>&nbsp;在&nbsp;抽象类中不能定义默认行为还存在另一个比较严重的问题，那就是可能会造成维护上的麻烦。因&nbsp;为如果后来想修改类的界面（一般通过&nbsp;abstract&nbsp;class&nbsp;或者interface来表示）以适应新的情况（比如，添加新的方法或者给已用的方法中添&nbsp;加新的参数）时，就会非常的麻烦，可能要花费很多的时间（对于派生类很多的情况，尤为如此）。但是如果界面是通过abstract&nbsp;class来实现的，那&nbsp;么可能就只需要修改定义在abstract&nbsp;class中的默认行为就可以了。</p>
<p>&nbsp;同样，如果不能在抽象类中定义默认行为，就会导致同样的方法实现出现在该抽象类的每一个派生类中，违反了&nbsp;"one&nbsp;rule，one&nbsp;place"&nbsp;原则，造成代码重复，同样不利于以后的维护。因此，在abstract&nbsp;class和interface间进行选择时要非常的小心。</p>
<p>&nbsp;从设计理念层面看&nbsp;abstract&nbsp;class&nbsp;和&nbsp;interface<br>&nbsp;上&nbsp;面主要从语法定义和编程的角度论述了abstract&nbsp;class和interface的区&nbsp;别，这些层面的区别是比较低层次的、非本质的。本小节将从另一个层面：abstract&nbsp;class和interface所反映出的设计理念，来分析一下二&nbsp;者的区别。作者认为，从这个层面进行分析才能理解二者概念的本质所在。</p>
<p>&nbsp;前&nbsp;面已经提到过，abstract&nbsp;class在Java语言中体现了一种继承关系，要想使得&nbsp;继承关系合理，父类和派生类之间必须存在"is-a"关系，即父类和派生类在概念本质上应该是相同的（参考文献〔3〕中有关于"is-a"关系的大篇幅深&nbsp;入的&nbsp;论述，有兴趣的读者可以参考）。对于interface来说则不然，并不要求interface的实现者和interface定义在概念本质上是一致的，&nbsp;仅仅是实现了interface定义的契约而已。为了使论述便于理解，下面将通过一个简单的实例进行说明。</p>
<p>&nbsp;考虑这样一个例子，假设在我们的问题领域中有一个关于Door的抽象概念，该Door具有执行两个动作open和close，此时我们可以通过abstract&nbsp;class或者interface来定义一个表示该抽象概念的类型，定义方式分别如下所示：</p>
<p>&nbsp;使用abstract&nbsp;class方式定义Door：</p>
<p>&nbsp;abstract&nbsp;class&nbsp;Door{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;abstract&nbsp;void&nbsp;open();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;abstract&nbsp;void&nbsp;close()；<br>&nbsp;}</p>
<p>&nbsp;使用interface方式定义Door：</p>
<p>&nbsp;interface&nbsp;Door{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;open();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;close();<br>&nbsp;}</p>
<p>&nbsp;其他具体的Door类型可以extends使用abstract&nbsp;class方式定义的Door或者implements使用interface方式定义的Door。看起来好像使用abstract&nbsp;class和interface没有大的区别。</p>
<p>&nbsp;&nbsp;</p>
<p>&nbsp;如&nbsp;果现在要求Door还要具有报警的功能。我们该如何设计针对该例子的类结构呢（在本例中，&nbsp;主要是为了展示&nbsp;abstract&nbsp;class&nbsp;和interface&nbsp;反映在设计理念上的区别，其他方面无关的问题都做了简化或者忽略）？下面将罗列出可能的解&nbsp;决方案，并从设计理念层面对这些不同的方案进行分析。</p>
<p>&nbsp;解决方案一：</p>
<p>&nbsp;简单的在Door的定义中增加一个alarm方法，如下：</p>
<p>&nbsp;abstract&nbsp;class&nbsp;Door{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;abstract&nbsp;void&nbsp;open();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;abstract&nbsp;void&nbsp;close()；<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;abstract&nbsp;void&nbsp;alarm();<br>&nbsp;}</p>
<p>&nbsp;或者</p>
<p>&nbsp;interface&nbsp;Door{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;open();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;close();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;alarm();<br>&nbsp;}</p>
<p>&nbsp;那么具有报警功能的AlarmDoor的定义方式如下：</p>
<p>&nbsp;class&nbsp;AlarmDoor&nbsp;extends&nbsp;Door{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;open(){&#8230;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;close(){&#8230;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;alarm(){&#8230;}<br>&nbsp;}</p>
<p>&nbsp;或者</p>
<p>&nbsp;class&nbsp;AlarmDoor&nbsp;implements&nbsp;Door｛<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;open(){&#8230;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;close(){&#8230;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;alarm(){&#8230;}<br>&nbsp;｝</p>
<p>&nbsp;这种方法违反了面向对象设计中的一个核心原则&nbsp;ISP&nbsp;(Interface&nbsp;Segregation&nbsp;Principle)，在Door的定义中把Door概念本身固有的行为方法和另外一个概念"报警器"的行为方&nbsp;法混在了一起。这样引起的一个问题是那些仅仅依赖于Door这个概念的模块会因为"报警器"这个概念的改变（比如：修改alarm方法的参数）而改变，反&nbsp;之依然。</p>
<p>&nbsp;解决方案二：</p>
<p>&nbsp;既&nbsp;然open、close和alarm属于两个不同的概念，根据ISP原则应该把它们分别定&nbsp;义在代表这两个概念的抽象类中。定义方式有：这两个概念都使用&nbsp;abstract&nbsp;class&nbsp;方式定义；两个概念都使用interface方式定义；一个概念&nbsp;使用&nbsp;abstract&nbsp;class&nbsp;方式定义，另一个概念使用interface方式定义。</p>
<p>&nbsp;显然，由于Java语言不支持多重继承，所以两个概念都使用abstract&nbsp;class方式定义是不可行的。后面两种方式都是可行的，但是对于它们的选择却反映出对于问题领域中的概念本质的理解、对于设计意图的反映是否正确、合理。我们一一来分析、说明。</p>
<p>&nbsp;如&nbsp;果两个概念都使用interface方式来定义，那么就反映出两个问题：1、我们可能没有&nbsp;理解清楚问题领域，AlarmDoor在概念本质上到底是Door还是报警器？2、如果我们对于问题领域的理解没有问题，比如：我们通过对于问题领域的分&nbsp;析发现AlarmDoor在概念本质上和Door是一致的，那么我们在实现时就没有能够正确的揭示我们的设计意图，因为在这两个概念的定义上（均使用&nbsp;interface方式定义）反映不出上述含义。</p>
<p>&nbsp;如&nbsp;果我们对于问题领域的理解是：AlarmDoor在概念本质上是Door，同时它有具有报&nbsp;警的功能。我们该如何来设计、实现来明确的反映出我们的意思呢？前面已经说过，abstract&nbsp;class在Java语言中表示一种继承关系，而继承关系&nbsp;在本质上是"is-a"关系。所以对于Door这个概念，我们应该使用abstarct&nbsp;class方式来定义。另外，AlarmDoor又具有报警功能，说&nbsp;明它又能够完成报警概念中定义的行为，所以报警概念可以通过interface方式定义。如下所示：</p>
<p>&nbsp;abstract&nbsp;class&nbsp;Door{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;abstract&nbsp;void&nbsp;open();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;abstract&nbsp;void&nbsp;close()；<br>&nbsp;}<br>&nbsp;interface&nbsp;Alarm{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;alarm();<br>&nbsp;}<br>&nbsp;class&nbsp;Alarm&nbsp;Door&nbsp;extends&nbsp;Door&nbsp;implements&nbsp;Alarm{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;open(){&#8230;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;close(){&#8230;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;alarm(){&#8230;}<br>&nbsp;}</p>
<p>&nbsp;这&nbsp;种实现方式基本上能够明确的反映出我们对于问题领域的理解，正确的揭示我们的设计意图。其&nbsp;实abstract&nbsp;class表示的是"is-a"关系，interface表示的是"like-a"关系，大家在选择时可以作为一个依据，当然这是建立在对&nbsp;问题领域的理解上的，比如：如果我们认为AlarmDoor在概念本质上是报警器，同时又具有Door的功能，那么上述的定义方式就要反过来了。</p>
<p>&nbsp;&nbsp;</p>
<p>&nbsp;小结<br>&nbsp;1.abstract&nbsp;class&nbsp;在&nbsp;Java&nbsp;语言中表示的是一种继承关系，一个类只能使用一次继承关系。但是，一个类却可以实现多个interface。<br>&nbsp;2.在abstract&nbsp;class&nbsp;中可以有自己的数据成员，也可以有非abstarct的成员方法，而在interface中，只能够有静态的不能被修改的数据成员（也就是必须是static&nbsp;final的，不过在&nbsp;interface中一般不定义数据成员），所有的成员方法都是abstract的。<br>&nbsp;3.abstract&nbsp;class和interface所反映出的设计理念不同。其实abstract&nbsp;class表示的是"is-a"关系，interface表示的是"like-a"关系。&nbsp;<br>&nbsp;4.实现抽象类和接口的类必须实现其中的所有方法。抽象类中可以有非抽象方法。接口中则不能有实现方法。<br>&nbsp;5.接口中定义的变量默认是public&nbsp;static&nbsp;final&nbsp;型，且必须给其初值，所以实现类中不能重新定义，也不能改变其值。<br>&nbsp;6.抽象类中的变量默认是&nbsp;friendly&nbsp;型，其值可以在子类中重新定义，也可以重新赋值。&nbsp;<br>&nbsp;7.接口中的方法默认都是&nbsp;public,abstract&nbsp;类型的。<br>&nbsp;结论</p>
<p>&nbsp;abstract&nbsp;class&nbsp;和&nbsp;interface&nbsp;是&nbsp;Java语言中的两种定义抽象类的方式，它们之间有很大的相似性。但是对于它们的选择却又往往反映出对于问题领域中的概&nbsp;念本质的理解、对于设计意图的反映是否正确、合理，因为它们表现了概念间的不同的关系（虽然都能够实现需求的功能）。这其实也是语言的一种的惯用法，希望&nbsp;读者朋友能够细细体会。</p>
<p>&nbsp;参考文献<br>&nbsp;[1]&nbsp;Thinking&nbsp;in&nbsp;Java,&nbsp;Bruce&nbsp;Eckel<br>&nbsp;[2]&nbsp;Design&nbsp;Patterns&nbsp;Explained:&nbsp;A&nbsp;New&nbsp;Perspective&nbsp;on&nbsp;Object-Oriented&nbsp;Design,&nbsp;Alan&nbsp;Shalloway&nbsp;and&nbsp;James&nbsp;R.&nbsp;Trott<br>&nbsp;[3]&nbsp;Effective&nbsp;C++:&nbsp;50&nbsp;Specific&nbsp;Ways&nbsp;to&nbsp;Improve&nbsp;Your&nbsp;Programs&nbsp;and&nbsp;Design,&nbsp;Scott&nbsp;Meyers</p>
<img src ="http://www.blogjava.net/mayu/aggbug/120813.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mayu/" target="_blank">my</a> 2007-05-30 10:07 <a href="http://www.blogjava.net/mayu/articles/120813.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>区分引用类型和原始类型</title><link>http://www.blogjava.net/mayu/articles/120647.html</link><dc:creator>my</dc:creator><author>my</author><pubDate>Tue, 29 May 2007 03:35:00 GMT</pubDate><guid>http://www.blogjava.net/mayu/articles/120647.html</guid><wfw:comment>http://www.blogjava.net/mayu/comments/120647.html</wfw:comment><comments>http://www.blogjava.net/mayu/articles/120647.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mayu/comments/commentRss/120647.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mayu/services/trackbacks/120647.html</trackback:ping><description><![CDATA[<font face=宋体>Java 提供两种不同的类型：引用类型和原始类型（或内置类型）。另外，Java 还为每个原始类型提供了封装类(Wrapper)。如果需要一个整型变量，是使用基本的 int 型呢，还是使用 Integer 类的一个对象呢？如果需要声明一个布尔类型，是使用基本的 boolean，还是使用Boolean 类的一个对象呢？本文可帮助您作出决定。
<p>下面列出了原始类型以及它们的对象封装类。</p>
<p>原始类型封装类<br>booleanBoolean<br>char Character<br>byte Byte<br>shortShort<br>intInteger<br>long Long<br>floatFloat<br>double Double</p>
<p>引用类型和原始类型的行为完全不同，并且它们具有不同的语义。例如，假定一个方法中有两个局部变量，一个变量为 int 原始类型，另一个变量是对一个 Integer 对象的对象引用：</p>
<p>int i = 5;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 原始类型<br>Integer j = new Integer(10);&nbsp;&nbsp;&nbsp;&nbsp; // 对象引用<br>&nbsp;<br>这两个变量都存储在局部变量表中，并且都是在 Java 操作数堆栈中操作的，但对它们的表示却完全不同。（本文中以下部分将用通用术语堆栈代替操作数堆栈或局部变量表。）原始类型 int 和对象引用各占堆栈的 32 位。（要表示一个 int 或一个对象引用，Java 虚拟机实现至少需要使用 32 位存储。）Integer 对象的堆栈项并不是对象本身，而是一个对象引用。</p>
<p>Java 中的所有对象都要通过对象引用访问。对象引用是指向对象存储所在堆中的某个区域的指针。当声明一个原始类型时，就为类型本身声明了存储。前面的两行代码表示如下：</p>
<p>引用类型和原始类型具有不同的特征和用法，它们包括：大小和速度问题，这种类型以哪种类型的数据结构存储，当引用类型和原始类型用作某个类的实例数据时所指定的缺省值。对象引用实例变量的缺省值为 null，而原始类型实例变量的缺省值与它们的类型有关。</p>
<p>许多程序的代码将同时包含原始类型以及它们的对象封装。当检查它们是否相等时，同时使用这两种类型并了解它们如何正确相互作用和共存将成为问题。程序员必须了解这两种类型是如何工作和相互作用的，以避免代码出错。</p>
<p>例如，不能对原始类型调用方法，但可以对对象调用方法：</p>
<p>int j = 5;<br>j.hashCode();&nbsp;&nbsp;&nbsp;&nbsp; // 错误<br>//...<br>Integer i = new Integer(5);<br>i.hashCode();&nbsp;&nbsp;&nbsp;&nbsp; // 正确</p>
<p>使用原始类型无须调用 new，也无须创建对象。这节省了时间和空间。混合使用原始类型和对象也可能导致与赋值有关的意外结果。看起来没有错误的代码可能无法完成您希望做的工作。例如：</p>
<p>import java.awt.Point;<br>class Assign<br>{<br>public static void main(String args)<br>{<br>&nbsp;&nbsp; int a = 1;<br>&nbsp;&nbsp; int b = 2;<br>&nbsp;&nbsp; Point x = new Point(0,0);<br>&nbsp;&nbsp; Point y = new Point(1,1);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 1<br>&nbsp;&nbsp; System.out.println("a is " + a);<br>&nbsp;&nbsp; System.out.println("b is " + b);<br>&nbsp;&nbsp; System.out.println("x is " + x);<br>&nbsp;&nbsp; System.out.println("y is " + y);<br>&nbsp;&nbsp; System.out.println("Performing assignment and " + <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "setLocation..."); <br>&nbsp;&nbsp; a = b;<br>&nbsp;&nbsp; a++;<br>&nbsp;&nbsp; x = y;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 2<br>&nbsp;&nbsp; x.setLocation(5,5);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 3<br>&nbsp;&nbsp; System.out.println("a is "+a); <br>&nbsp;&nbsp; System.out.println("b is "+b); <br>&nbsp;&nbsp; System.out.println("x is "+x); <br>&nbsp;&nbsp; System.out.println("y is "+y);<br>}<br>}</p>
<p>这段代码生成以下输出：</p>
<p>a is 1<br>b is 2<br>x is java.awt.Point<br>y is java.awt.Point<br>Performing assignment and setLocation...<br>a is 3<br>b is 2<br>x is java.awt.Point<br>y is java.awt.Point</p>
<p>修改整数 a 和 b 的结果没什么意外的地方。b 的值被赋予整型变量 a，结果 a 的值增加了 1。这一输出反映了我们希望发生的情况。但是，令人感到意外的，是在赋值并调用 setLocation之后 x 和 y 对象的输出。我们在完成 x = y 赋值之后特意对 x 调用了 setLocation，x 和 y 的值怎么会相同呢？我们毕竟将 y 赋予 x，然后更改了 x，这与我们对整数 a 和 b 进行的操作没什么不同。</p>
<p>这种混淆是由原始类型和对象的使用造成的。赋值对这两种类型所起的作用没什么不同。但它可能看起来所有不同。赋值使等号 (=) 左边的值等于右边的值。这一点对于原始类型（如前面的 int a 和 b）是显而易见的。对于非原始类型（如 Point 对象），赋值修改的是对象引用，而不是对象本身。因此，在语句 x = y; 之后，x 等于 y。换句话说，因为 x 和 y 是对象引用，它们现在引用同一个对象。因此，对 x 所作的任何更改也会更改 y。<br>&nbsp;<br>因为 x 和 y 引用同一个对象，所以对 x 执行的所有方法与对 y 执行的方法都作用于同一个对象。</p>
<p>区分引用类型和原始类型并理解引用的语义是很重要的。若做不到这一点，则会使编写的代码无法完成预定工作。</p>
=========================================================================<br><br><br>Java 提供两种不同的类型：引用类型和原始类型（或内置类型）。Int是java的原始数据类型，Integer是java为int提供的封装类。Java</font>
<p><font face=宋体>为每个原始类型提供了封装类。<br>原始类型封装类,booleanBoolean,charCharacter,byteByte,shortShort,intInteger,longLong,floatFloat,doubleDouble<br>引用类型和原始类型的行为完全不同，并且它们具有不同的语义。引用类型和原始类型具有不同的特征和用法，它们包括：大小和速度问题，</font></p>
<p><font face=宋体>这种类型以哪种类型的数据结构存储，当引用类型和原始类型用作某个类的实例数据时所指定的缺省值。对象引用实例变量的缺省值为 null，</font></p>
<p><font face=宋体>而原始类型实例变量的缺省值与它们的类型有关<br><br></p>
<p>在java中一切都是以类为基础的，并且java对基本的数据类型也进行了封装，如下所示，将介绍几个基本的数据类型及其封装类：</p>
<p>1&nbsp; Boolean VS boolean</p>
<dl>
<dt>
<pre>public final class <strong>Boolean</strong><dt>extends <a title="java.lang 中的类" href="file:///G:/html_zh_CN/html/zh_CN/api/java/lang/Object.html"><font color=#0000ff><u>Object</u></font></a><dt>implements <a title="java.io 中的接口" href="file:///G:/html_zh_CN/html/zh_CN/api/java/io/Serializable.html"><font color=#0000ff><u>Serializable</u></font></a>, <a title="java.lang 中的接口" href="file:///G:/html_zh_CN/html/zh_CN/api/java/lang/Comparable.html"><font color=#0000ff><u>Comparable</u></font></a>&lt;<a title="java.lang 中的类" href="file:///G:/html_zh_CN/html/zh_CN/api/java/lang/Boolean.html"><font color=#0000ff><u>Boolean</u></font></a>&gt;</dt></pre>
</dt></dl>
<pre>&nbsp;</pre>
<p>Boolean 类将基本类型为 <code><font face=新宋体>boolean</font></code> 的值包装在一个对象中。一个 <code><font face=新宋体>Boolean</font></code> 类型的对象只包含一个类型为 <code><font face=新宋体>boolean</font></code> 的字段。 </p>
<p>此外，此类还为 <code><font face=新宋体>boolean</font></code> 和 <code><font face=新宋体>String</font></code> 的相互转换提供了许多方法，并提供了处理 <code><font face=新宋体>boolean</font></code> 时非常有用的其他一些常量和方法。<br>.............<br>Byte&nbsp; ，Character&nbsp; ，Double&nbsp; 等等都是一样<br><br><strong>表A Java原始数据类型<br></strong><br>简单类型 大小 范围/精度 <br><br>float 4 字节 32位IEEE 754单精度 <br><br>double 8 字节 64位IEEE 754双精度 <br><br>byte 1字节 -128到127 <br><br>short 2 字节 -32,768到32,767 <br><br>int 4 字节 -2,147,483,648到2,147,483,647 <br><br>long 8 字节 -9,223,372,036,854,775,808到9,223,372,036, 854,775,807 <br><br>char 2 字节 整个Unicode字符集 <br><br>boolean 1 位 True或者false <br></font></p>
<img src ="http://www.blogjava.net/mayu/aggbug/120647.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mayu/" target="_blank">my</a> 2007-05-29 11:35 <a href="http://www.blogjava.net/mayu/articles/120647.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java.util.Date 构造函数</title><link>http://www.blogjava.net/mayu/articles/119466.html</link><dc:creator>my</dc:creator><author>my</author><pubDate>Wed, 23 May 2007 10:12:00 GMT</pubDate><guid>http://www.blogjava.net/mayu/articles/119466.html</guid><wfw:comment>http://www.blogjava.net/mayu/comments/119466.html</wfw:comment><comments>http://www.blogjava.net/mayu/articles/119466.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mayu/comments/commentRss/119466.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mayu/services/trackbacks/119466.html</trackback:ping><description><![CDATA[1. Date = new Date(); <br>不介绍了<br>2. Date = new Date(107, 0, 1);<br>三个参数是year,month,day,都是int型，<br>107代表2007，是减去1900得到的数，比如要new一个2005年的，就是105，1999年的就是99<br>0代表1月，这里月份是0-11的数字，0代表1月，1代表2月，依此类推<br>1表示天数，数字范围1-31<br>3. Date = new Date(65, 2, 6, 9, 30, 15, 0);<br>public Date([yearOrTimevalue:Number], [month:Number], [date:Number], [hour:Number], [minute:Number], [second:Number], [millisecond:Number])<br>精确到毫秒<br>
<img src ="http://www.blogjava.net/mayu/aggbug/119466.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mayu/" target="_blank">my</a> 2007-05-23 18:12 <a href="http://www.blogjava.net/mayu/articles/119466.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一些基础的精华</title><link>http://www.blogjava.net/mayu/articles/92819.html</link><dc:creator>my</dc:creator><author>my</author><pubDate>Wed, 10 Jan 2007 01:54:00 GMT</pubDate><guid>http://www.blogjava.net/mayu/articles/92819.html</guid><wfw:comment>http://www.blogjava.net/mayu/comments/92819.html</wfw:comment><comments>http://www.blogjava.net/mayu/articles/92819.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mayu/comments/commentRss/92819.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mayu/services/trackbacks/92819.html</trackback:ping><description><![CDATA[1、 对象的初始化 <br />(1) 非静态对象的初始化 <br />在创建对象时，对象所在类的所有数据成员会首先进行初始化。 <br />基本类型：int型，初始化为0。 <br />如果为对象：这些对象会按顺序初始化。 <br />※在所有类成员初始化完成之后，才调用本类的构造方法创建对象。 <br />构造方法的作用就是初始化。 <br />(2) 静态对象的初始化 <br />程序中主类的静态变量会在main方法执行前初始化。 <br />不仅第一次创建对象时，类中的所有静态变量都初始化，并且第一次访问某类（注意此时 <br />未创建此类对象）的静态对象时，所有的静态变量也要按它们在类中的顺序初始化。 <br />2、 继承时，对象的初始化过程 <br />(1) 主类的超类由高到低按顺序初始化静态成员，无论静态成员是否为private。 <br />(2) 主类静态成员的初始化。 <br />(3) 主类的超类由高到低进行默认构造方法的调用。注意，在调用每一个超类的默认构造 <br />方法前，先进行对此超类进行非静态对象的初始化。 <br />(4) 主类非静态成员的初始化。 <br />(5) 调用主类的构造方法。 <br />3、 关于构造方法 <br />(1) 类可以没有构造方法，但如果有多个构造方法，就应该要有默认的构造方法，否则在继承此类时，需要在子类中显式调用父类的某一个非默认的构造方法了。 <br />(2) 在一个构造方法中，只能调用一次其他的构造方法，并且调用构造方法的语句必须是 <br />第一条语句。 <br />4、 有关public、private和protected <br />(1) 无public修饰的类，可以被其他类访问的条件是：a.两个类在同一文件中，b.两个类 <br />在同一文件夹中，c.两个类在同一软件包中。 <br />(2) protected：继承类和同一软件包的类可访问。 <br />(3) 如果构造方法为private，那么在其他类中不能创建该类的对象。 <br />5、 抽象类 <br />(1) 抽象类不能创建对象。 <br />(2) 如果一个类中一个方法为抽象方法，则这个类必须为abstract抽象类。 <br />(3) 继承抽象类的类在类中必须实现抽象类中的抽象方法。 <br />(4) 抽象类中可以有抽象方法，也可有非抽象方法。抽象方法不能为private。 <br />(5) 间接继承抽象类的类可以不给出抽象方法的定义。 <br />6、 final关键字 <br />(1) 一个对象是常量，不代表不能转变对象的成员，仍可以其成员进行操作。 <br />(2) 常量在使用前必须赋值，但除了在声明的同时初始化外，就只能在构造方法中初始化 <br />。 <br />(3) final修饰的方法不能被重置（在子类中不能出现同名方法）。 <br />(4) 如果声明一个类为final，则所有的方法均为final，无论其是否被final修饰，但数据 <br />成员可为final也可不是。 <br />7、 接口interface （用implements来实现接口） <br />(1) 接口中的所有数据均为 static和final即静态常量。尽管可以不用这两个关键字修饰 <br />，但必须给常量赋初值。 <br />(2) 接口中的方法均为public，在实现接口类中，实现方法必须可public关键字。 <br />(3) 如果使用public来修饰接口，则接口必须与文件名相同。 <br />8、 多重继承 <br />(1) 一个类继承了一个类和接口，那么必须将类写在前面，接口写在后面，接口之间用逗 <br />号分隔。 <br />(2) 接口之间可多重继承，注意使用关键字extends。 <br />(3) 一个类虽只实现了一个接口，但不仅要实现这个接口的所有方法，还要实现这个接口 <br />继承的接口的方法，接口中的所有方法均须在类中实现。 <br />9、 接口的嵌入 <br />(1) 接口嵌入类中，可以使用private修饰。此时，接口只能在所在的类中实现，其他类不 <br />能访问。 <br />(2) 嵌入接口中的接口一定要为public。 <br />10、类的嵌入 <br />(1) 类可以嵌入另一个类中，但不能嵌入接口中。 <br />(2) 在静态方法或其他方法中，不能直接创建内部类对象，需通过手段来取得。 <br />手段有两种： <br />class A { <br />class B {} <br />B getB() { <br />B b = new B(); <br />return b; <br />} <br />} <br />static void m() { <br />A a = new A(); <br />A.B ab = a.getB(); // 或者是 A.B ab = a.new B(); <br />} <br />(3) 一个类继承了另一个类的内部类，因为超类是内部类，而内部类的构造方法不能自动 <br />被调用，这样就需要在子类的构造方法中明确的调用超类的构造方法。 <br />接上例： <br />class C extends A.B { <br />C() { <br />new A().super(); // 这一句就实现了对内部类构造方法的调用。 <br />} <br />} <br />构造方法也可这样写： <br />C(A a) { <br />a.super(); <br />} // 使用这个构造方法创建对象，要写成C c = new C(a); a是A的对象。 <br />11、异常类 <br />JAVA中除了RunTimeException 类，其他异常均须捕获或抛出<img src ="http://www.blogjava.net/mayu/aggbug/92819.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mayu/" target="_blank">my</a> 2007-01-10 09:54 <a href="http://www.blogjava.net/mayu/articles/92819.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java中的一些常用词汇</title><link>http://www.blogjava.net/mayu/articles/82551.html</link><dc:creator>my</dc:creator><author>my</author><pubDate>Tue, 21 Nov 2006 07:49:00 GMT</pubDate><guid>http://www.blogjava.net/mayu/articles/82551.html</guid><wfw:comment>http://www.blogjava.net/mayu/comments/82551.html</wfw:comment><comments>http://www.blogjava.net/mayu/articles/82551.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mayu/comments/commentRss/82551.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mayu/services/trackbacks/82551.html</trackback:ping><description><![CDATA[Abstract class 抽象类:抽象类是不允许实例化的类，因此一般它需要被进行扩展继承。   <br /><br />　　Abstract method 抽象方法:抽象方法即不包含任何功能代码的方法。   <br /><br />　　Access modifier 访问控制修饰符:访问控制修饰符用来修饰Java中类、以及类的方法和变量的访问控制属性。   <br /><br />　　Anonymous class 匿名类:当你需要创建和使用一个类，而又不需要给出它的名字或者再次使用的使用，就可以利用匿名类。   <br /><br />　　Anonymous inner classes 匿名内部类:匿名内部类是没有类名的局部内部类。   <br /><br />　　API 应用程序接口:提供特定功能的一组相关的类和方法的集合。   <br /><br />　　Array 数组:存储一个或者多个相同数据类型的数据结构，使用下标来访问。在Java中作为对象处理。   <br /><br />　　Automatic variables 自动变量:也称为方法局部变量method local variables，即声明在方法体中的变量。   <br /><br /><br />　　Base class 基类:即被扩展继承的类。   <br /><br />　　Blocked state 阻塞状态:当一个线程等待资源的时候即处于阻塞状态。阻塞状态不使用处理器资源   <br /><br />　　Call stack 调用堆栈:调用堆栈是一个方法列表，按调用顺序保存所有在运行期被调用的方法。   <br /><br />　　Casting 类型转换 :即一个类型到另一个类型的转换，可以是基本数据类型的转换，也可以是对象类型的转换。   <br /><br />　　char 字符:容纳单字符的一种基本数据类型。   <br /><br />　　Child class 子类:见继承类Derived class   <br /><br />　　Class 类:面向对象中的最基本、最重要的定义类型。   <br /><br />　　Class members 类成员:定义在类一级的变量，包括实例变量和静态变量。   <br /><br />　　Class methods 类方法:类方法通常是指的静态方法，即不需要实例化类就可以直接访问使用的方法。   <br /><br />　　Class variable 类变量:见静态变量Static variable   <br /><br />　　Collection 容器类:容器类可以看作是一种可以储存其他对象的对象，常见的容器类有Hashtables和Vectors。   <br /><br />　　Collection interface 容器类接口:容器类接口定义了一个对所有容器类的公共接口。   <br /><br />　　Collections framework 容器类构架:接口、实现和算法三个元素构成了容器类的架构。   <br /><br />　　Constructor 构造函数:在对象创建或者实例化时候被调用的方法。通常使用该方法来初始化数据成员和所需资源。   <br /><br />　　Containers容器:容器是一种特殊的组件，它可以容纳其他组件。   <br /><br />　　Declaration 声明:声明即是在源文件中描述类、接口、方法、包或者变量的语法。   <br /><br />　　Derived class 继承类:继承类是扩展继承某个类的类。   <br /><br />　　Encapsulation 封装性:封装性体现了面向对象程序设计的一个特性，将方法和数据组织在一起，隐藏其具体实现而对外体现出公共的接口。   <br /><br />　　Event classes 事件类:所有的事件类都定义在java.awt.event包中。   <br /><br />　　Event sources 事件源:产生事件的组件或对象称为事件源。事件源产生事件并把它传递给事件监听器event listener*。   <br /><br />　　Exception 异常:异常在Java中有两方面的意思。首先，异常是一种对象类型。其次，异常还指的是应用中发生的一种非标准流程情况，即异常状态。   <br /><br />　　Extensibility扩展性:扩展性指的是面向对象程序中，不需要重写代码和重新设计，能容易的增强源设计的功能。   <br /><br />　　Finalizer 收尾:每个类都有一个特殊的方法finalizer，它不能被直接调用，而被JVM在适当的时候调用，通常用来处理一些清理资源的工作，因此称为收尾机制。   <br /><br />　　Garbage collection 垃圾回收机制:当需要分配的内存空间不再使用的时候，JVM将调用垃圾回收机制来回收内存空间。   <br /><br />　　Guarded region 监控区域:一段用来监控错误产生的代码。   <br /><br />　　Heap堆:Java中管理内存的结构称作堆。   <br /><br />　　Identifiers 标识符:即指定类、方法、变量的名字。注意Java是大小写敏感的语言。   <br /><br />　　Import statement 引入语法:引入语法允许你可以不使用某个类的全名就可以参考这个类。   <br /><br />　　Inheritance 继承:继承是面向对象程序设计的重要特点，它是一种处理方法，通过这一方法，一个对象可以获得另一个对象的特征。   <br /><br />　　Inner classes 内部类:内部类与一般的类相似，只是它被声明在类的内部，或者甚至某个类方法体中。   <br /><br />　　Instance 实例:类实例化以后成为一个对象。   <br /><br />　　Instance variable 实例变量:实例变量定义在对象一级，它可以被类中的任何方法或者其他类的中方法访问，但是不能被静态方法访问。   <br /><br />　　Interface 接口:接口定义的是一组方法或者一个公共接口，它必须通过类来实现。   <br /><br />　　Java source file Java源文件:Java源程序包含的是Java程序语言计算机指令。   <br /><br />　　Java Virtual Machine (JVM) Java虚拟机:解释和执行Java字节码的程序，其中Java字节码由Java编译器生成。   <br /><br />　　javac Java编译器:Javac是Java编译程序的名称。   <br /><br />　　JVM Java虚拟机:见Java虚拟机   <br /><br />　　Keywords 关键字:即Java中的保留字，不能用作其他的标识符。   <br /><br />　　Layout managers 布局管理器:布局管理器是一些用来负责处理容器中的组件布局排列的类。   <br /><br />　　Local inner classes 局部内部类:在方法体中，或者甚至更小的语句块中定义的内部类。   <br /><br />　　Local variable 局部变量:在方法体中声明的变量   <br /><br />　　Member inner classes 成员内部类:定义在封装类中的没有指定static修饰符的内部类。   <br /><br />　　Members 成员:类中的元素，包括方法和变量。   <br /><br />　　Method 方法:完成特定功能的一段源代码，可以传递参数和返回结果，定义在类中。   <br /><br />　　Method local variables 方法局部变量:见自动变量Automatic variables   <br /><br />　　Modifier 修饰符:用来修饰类、方法或者变量行为的关键字。   <br /><br />　　Native methods 本地方法:本地方法是指使用依赖平台的语言编写的方法，它用来完成Java无法处理的某些依赖于平台的功能。   <br /><br />　　Object 对象:一旦类实例化之后就成为对象。   <br /><br />　　Overloaded methods 名称重载方法:方法的名称重载是指同一个类中具有多个方法，使用相同的名称而只是其参数列表不同。   <br /><br />　　Overridden methods 覆盖重载方法:方法的覆盖重载是指父类和子类使用的方法采用同样的名称、参数列表和返回类型。   <br /><br />　　Package 包:包即是将一些类聚集在一起的一个实体。   <br /><br />　　Parent class 父类:被其他类继承的类。也见基类。   <br /><br />　　Private members 私有成员:私有成员只能在当前类被访问，其他任何类都不可以访问之。   <br /><br />　　Public members 公共成员:公共成员可以被任何类访问，而不管该类属于那个包。   <br /><br />　　Runtime exceptions 运行时间异常:运行时间异常是一种不能被你自己的程序处理的异常。通常用来指示程序BUG。   <br /><br />　　Source file 源文件:源文件是包含你的Java代码的一个纯文本文件。   <br /><br />　　Stack trace 堆栈轨迹:如果你需要打印出某个时间的调用堆栈状态，你将产生一个堆栈轨迹。   <br /><br />　　Static inner classes 静态内部类:静态内部类是内部类最简单的形式，它于一般的类很相似，除了被定义在了某个类的内部。   <br /><br />　　Static methods 静态方法:静态方法声明一个方法属于整个类，即它可以不需要实例化一个类就可以通过类直接访问之。   <br /><br />　　Static variable 静态变量:也可以称作类变量。它类似于静态方法，也是可以不需要实例化类就可以通过类直接访问。   <br /><br />　　Superclass 超类:被一个或多个类继承的类。   <br /><br />　　Synchronized methods 同步方法:同步方法是指明某个方法在某个时刻只能由一个线程访问。   <br /><br />　　Thread 线程:线程是一个程序内部的顺序控制流。   <br /><br />　　Time-slicing 时间片:调度安排线程执行的一种方案。   <br /><br />　　Variable access 变量访问控制:变量访问控制是指某个类读或者改变一个其他类中的变量的能力。   <br /><br />　　Visibility 可见性: 可见性体现了方法和实例变量对其他类和包的访问控制。 <br /><img src ="http://www.blogjava.net/mayu/aggbug/82551.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mayu/" target="_blank">my</a> 2006-11-21 15:49 <a href="http://www.blogjava.net/mayu/articles/82551.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>将JAVA编译为EXE的几种方法 </title><link>http://www.blogjava.net/mayu/articles/77541.html</link><dc:creator>my</dc:creator><author>my</author><pubDate>Fri, 27 Oct 2006 01:51:00 GMT</pubDate><guid>http://www.blogjava.net/mayu/articles/77541.html</guid><wfw:comment>http://www.blogjava.net/mayu/comments/77541.html</wfw:comment><comments>http://www.blogjava.net/mayu/articles/77541.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mayu/comments/commentRss/77541.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mayu/services/trackbacks/77541.html</trackback:ping><description><![CDATA[
		<p>将JAVA编译为EXE的几种方法 <br />--------------------------------------------------------------------------------<br /><br />将Java应用程序本地编译为EXE的几种方法(建议使用JOVE和JET)　 <br /><br />a. 利用微软的SDK-Java 4.0所提供的jexegen.exe创建EXE文件，这个软件可以　 <br />从微软的网站免费下载，地址如下：　 <br /><a href="http://www.microsoft.com/java/download/dl_sdk40.htm">http://www.microsoft.com/java/download/dl_sdk40.htm</a>　 <br />jexegen的语法如下：　 <br />jexegen /OUT:exe_file_name　 <br />/MAIN:main_class_name main_class_file_name.class　 <br />[and other classes]　 <br />b. Visual Cafe提供了一个能够创建EXE文件的本地编译器。你需要安装该光盘　 <br />上提供的EXE组件。　 <br />c. 使用InstallAnywhere创建安装盘。　 <br />d. 使用IBM AlphaWorks提供的一个高性能Java编译器，该编译器可以从下面的　 <br />地址获得：　 <br /><a href="http://www.alphaworks.ibm.com/tech/hpc">http://www.alphaworks.ibm.com/tech/hpc</a>　 <br />e. JET是一个优秀的Java语言本地编译器。该编译器可以从这个网站获得一个　 <br />测试版本：　 <br /><a href="http://www.excelsior-usa.com/jet.html">http://www.excelsior-usa.com/jet.html</a>　 <br />f. Instantiations公司的JOVE　 <br /><a href="http://www.instantiations.com/jove/...ejovesystem.htm">http://www.instantiations.com/jove/...ejovesystem.htm</a>　 <br />JOVE公司合并了以前的SuperCede，一个优秀的本地编译器，现在SuperCede　 <br />已经不复存在了。　 <br />g. JToEXE　 <br />Bravo Zulu Consulting, Inc开发的一款本地编译器，本来可以从该公司的　 <br />网页上免费下载的，不过目前在该公司的主页上找不到了。 <br />h. 从<a href="http://www.towerj.com/">www.towerj.com</a>获得一个TowerJ编译器，该编译器可以将你的CLASS文件　 <br />编译成EXE文件。　</p>
		<p>h......exe4j，，呵呵 不用说了吧。</p>
<img src ="http://www.blogjava.net/mayu/aggbug/77541.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mayu/" target="_blank">my</a> 2006-10-27 09:51 <a href="http://www.blogjava.net/mayu/articles/77541.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> Java中常见的异常</title><link>http://www.blogjava.net/mayu/articles/74724.html</link><dc:creator>my</dc:creator><author>my</author><pubDate>Thu, 12 Oct 2006 02:13:00 GMT</pubDate><guid>http://www.blogjava.net/mayu/articles/74724.html</guid><wfw:comment>http://www.blogjava.net/mayu/comments/74724.html</wfw:comment><comments>http://www.blogjava.net/mayu/articles/74724.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mayu/comments/commentRss/74724.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mayu/services/trackbacks/74724.html</trackback:ping><description><![CDATA[
		<span id="ShowBody" style="FONT-SIZE: 12px; LINE-HEIGHT: 15px">1. java.lang.NullPointerException<br />　　这个异常大家肯定都经常遇到，异常的解释是"程序遇上了空指针"，简单地说就是调用了未经初始化的对象或者是不存在的对象，这个错误经常出现在创建图片，调用数组这些操作中，比如图片未经初始化，或者图片创建时的路径错误等等。对数组操作中出现空指针，很多情况下是一些刚开始学习编程的朋友常犯的错误，即把数组的初始化和数组元素的初始化混淆起来了。数组的初始化是对数组分配需要的空间，而初始化后的数组，其中的元素并没有实例化，依然是空的，所以还需要对每个元素都进行初始化（如果要调用的话）<br /><br />　　2. java.lang.ClassNotFoundException<br />　　这个异常是很多原本在JB等开发环境中开发的程序员，把JB下的程序包放在WTk下编译经常出现的问题，异常的解释是"指定的类不存在"，这里主要考虑一下类的名称和路径是否正确即可，如果是在JB下做的程序包，一般都是默认加上Package的，所以转到WTK下后要注意把Package的路径加上。<br /><br />　　3. java.lang.ArithmeticException<br />　　这个异常的解释是"数学运算异常"，比如程序中出现了除以零这样的运算就会出这样的异常，对这种异常，大家就要好好检查一下自己程序中涉及到数学运算的地方，公式是不是有不妥了。<br /><br />　　4. java.lang.ArrayIndexOutOfBoundsException<br />　　这个异常相信很多朋友也经常遇到过，异常的解释是"数组下标越界"，现在程序中大多都有对数组的操作，因此在调用数组的时候一定要认真检查，看自己调用的下标是不是超出了数组的范围，一般来说，显示（即直接用常数当下标）调用不太容易出这样的错，但隐式（即用变量表示下标）调用就经常出错了，还有一种情况，是程序中定义的数组的长度是通过某些特定方法决定的，不是事先声明的，这个时候，最好先查看一下数组的length，以免出现这个异常。<br /><br />　　5. java.lang.IllegalArgumentException<br />　　这个异常的解释是"方法的参数错误"，很多J2ME的类库中的方法在一些情况下都会引发这样的错误，比如音量调节方法中的音量参数如果写成负数就会出现这个异常，再比如g.setColor(int red,int green,int blue)这个方法中的三个值，如果有超过２５５的也会出现这个异常，因此一旦发现这个异常，我们要做的，就是赶紧去检查一下方法调用中的参数传递是不是出现了错误。<br /><br />　　6. java.lang.IllegalAccessException<br />　　这个异常的解释是"没有访问权限"，当应用程序要调用一个类，但当前的方法即没有对该类的访问权限便会出现这个异常。对程序中用了Package的情况下要注意这个异常。<br /></span>
<img src ="http://www.blogjava.net/mayu/aggbug/74724.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mayu/" target="_blank">my</a> 2006-10-12 10:13 <a href="http://www.blogjava.net/mayu/articles/74724.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>查看自己机器上可以使用的 字体</title><link>http://www.blogjava.net/mayu/articles/74721.html</link><dc:creator>my</dc:creator><author>my</author><pubDate>Thu, 12 Oct 2006 02:10:00 GMT</pubDate><guid>http://www.blogjava.net/mayu/articles/74721.html</guid><wfw:comment>http://www.blogjava.net/mayu/comments/74721.html</wfw:comment><comments>http://www.blogjava.net/mayu/articles/74721.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mayu/comments/commentRss/74721.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mayu/services/trackbacks/74721.html</trackback:ping><description><![CDATA[
		<span id="ShowBody" style="FONT-SIZE: 12px; LINE-HEIGHT: 15px">又学到一个方法<br />import java.awt.*;<br />class Ziti<br />{<br />    public static void main(String args[])<br />    {<br />        String s1[] = GraphicsEnvironment.getLocalGraphicsEnvironment()<br />        .getAvailableFontFamilyNames();<br />        for(int i=0;i&lt;s1.length;i++)<br />        {<br />            System.out.println(s1[i]);        <br />        }<br />    }<br />}<br /></span>
<img src ="http://www.blogjava.net/mayu/aggbug/74721.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mayu/" target="_blank">my</a> 2006-10-12 10:10 <a href="http://www.blogjava.net/mayu/articles/74721.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一个最简单的计算器</title><link>http://www.blogjava.net/mayu/articles/74720.html</link><dc:creator>my</dc:creator><author>my</author><pubDate>Thu, 12 Oct 2006 02:09:00 GMT</pubDate><guid>http://www.blogjava.net/mayu/articles/74720.html</guid><wfw:comment>http://www.blogjava.net/mayu/comments/74720.html</wfw:comment><comments>http://www.blogjava.net/mayu/articles/74720.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mayu/comments/commentRss/74720.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mayu/services/trackbacks/74720.html</trackback:ping><description><![CDATA[
		<span id="ShowBody" style="FONT-SIZE: 12px; LINE-HEIGHT: 15px">import java.awt.*;<br />import java.awt.event.*;<br />import javax.swing.*;<br /><br />class MyFrame extends JFrame implements ActionListener<br />{<br />        private JButton ButtonNum[]=new JButton[16];<br />        private String countCode[]={"/","*","-","+","=","."};<br />        <br />        private JTextField displayField=new JTextField();        <br />        private JPanel pan=new JPanel();<br />        <br />        private String displayStr="";<br />        private double firstNum=0,secondNum=0;<br />        private int countNum;<br />        private boolean start=false,end=false;<br />        <br />    public MyFrame()<br />    {    <br />        super("模拟简便计算器");<br />        setSize(400,400);<br />        Container c=getContentPane();<br />        c.setLayout(new BorderLayout());    <br />        <br />        displayField.setHorizontalAlignment(JTextField.RIGHT);<br />        displayField.setFont(new Font("TimesRoman",Font.BOLD,50));<br />        displayField.setBackground(Color.gray);<br />        displayField.setEditable(false);<br />        displayField.addActionListener(this);        <br />        c.add(displayField,"North");<br />        c.add(pan,"Center");<br />            <br />        pan.setLayout(new GridLayout(4,4));<br />        <br />        for(int n=0;n&lt;16;n++)  //定义按键属性<br />        {    <br />            if(n&lt;10)<br />            {<br />                ButtonNum[n]=new JButton(n+"");<br />                ButtonNum[n].setFont(new Font("TimesRoman",Font.BOLD,50));                <br />                ButtonNum[n].setBackground(Color.lightGray);<br />                ButtonNum[n].addActionListener(this);<br />                pan.add(ButtonNum[n]);<br />            }<br />            <br />            else<br />            {<br />                ButtonNum[n]=new JButton(countCode[15-n]);<br />                ButtonNum[n].setFont(new Font("TimesRoman",Font.BOLD,50));      <br />                ButtonNum[n].addActionListener(this);<br />                pan.add(ButtonNum[n]);<br />            }    <br />        }    <br />        setVisible(true);<br />    }<br />    <br />    public static void main(String args[])<br />    {    <br />        MyFrame myFrame=new MyFrame();<br />    }<br />        <br />    public void windowClosing(WindowEvent e)<br />    {<br />        dispose();<br />        System.exit(0);<br />    }<br />    <br />    public void actionPerformed(ActionEvent e)<br />    {<br />        for(int i=0;i&lt;16;i++)<br />        {<br />            if(i&lt;=10)   //算数按钮输入事件处理  判断并显示输入的运算数字<br />            {<br />                if(e.getSource()==ButtonNum[i] &amp;&amp; start==false)<br />                {<br />                    displayStr=displayStr+ButtonNum[i].getLabel();<br />                    displayField.setText(displayStr);<br />                    <br />                }<br />                <br />                if(e.getSource()==ButtonNum[i] &amp;&amp; start==true)<br />                {<br />                    displayStr=displayStr+ButtonNum[i].getLabel();<br />                    displayField.setText(displayStr);<br />                    end=true;        <br />                }            <br />            }<br />        <br />            if(i&gt;=12 &amp;&amp; i&lt;=15)     //运算按钮事件处理  判断并接受输入的运算数字<br />            {    <br />                if(e.getSource()==ButtonNum[i] &amp;&amp; start==false)<br />                {<br />                    firstNum=Double.valueOf(displayField.getText()).doubleValue();<br />                    countNum=i;<br />                    displayField.setText("");<br />                    displayStr="";<br />                    start=true;            <br />                }<br />                <br />                else<br />                {    if(e.getSource()==ButtonNum[i] )<br />                    {<br />                        countNum=0;<br />                        displayField.setText("");<br />                        displayStr="";<br />                        firstNum=0;<br />                        secondNum=0;<br />                        end=false;    <br />                    }                                                                        <br />                }                    <br />            }<br />        <br />            if(e.getSource()==ButtonNum[11])    //等号按钮事件处理<br />            {<br />                secondNum=Double.valueOf(displayField.getText()).doubleValue();<br />                        <br />                if(start=true &amp;&amp; end==true)<br />                {                                                        <br />                    if(countNum==12)<br />                        displayField.setText(firstNum+secondNum+"");<br />                    if(countNum==13)<br />                        displayField.setText(firstNum-secondNum+"");<br />                    if(countNum==14)<br />                        displayField.setText(firstNum*secondNum+"");<br />                    if(countNum==15 &amp;&amp; secondNum!=0)<br />                        displayField.setText(firstNum/secondNum+"");                                <br />                }<br />                            <br />                countNum=0;<br />                displayStr="";<br />                firstNum=0;<br />                secondNum=0;<br />                start=false;<br />                end=false;    <br />            }<br />        }            <br />    }<br />} <br /></span>
<img src ="http://www.blogjava.net/mayu/aggbug/74720.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mayu/" target="_blank">my</a> 2006-10-12 10:09 <a href="http://www.blogjava.net/mayu/articles/74720.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>对String的深刻理解</title><link>http://www.blogjava.net/mayu/articles/64366.html</link><dc:creator>my</dc:creator><author>my</author><pubDate>Fri, 18 Aug 2006 07:41:00 GMT</pubDate><guid>http://www.blogjava.net/mayu/articles/64366.html</guid><wfw:comment>http://www.blogjava.net/mayu/comments/64366.html</wfw:comment><comments>http://www.blogjava.net/mayu/articles/64366.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mayu/comments/commentRss/64366.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mayu/services/trackbacks/64366.html</trackback:ping><description><![CDATA[1、"abc"与new String("abc");
    经常会问到的面试题：String s = new String("abc");创建了几个String Object?【如这里创建了多少对象? 和一道小小的面试题 】

    这个问题比较简单，涉及的知识点包括：

引用变量与对象的区别； 
字符串文字"abc"是一个String对象； 
文字池[pool of literal strings]和堆[heap]中的字符串对象。
    一、引用变量与对象：除了一些早期的Java书籍和现在的垃圾书籍，人们都可以从中比较清楚地学习到两者的区别。A aa;语句声明一个类A的引用变量aa[我常常称之为句柄]，而对象一般通过new创建。所以题目中s仅仅是一个引用变量，它不是对象。[ref 句柄、引用与对象]

    二、Java中所有的字符串文字[字符串常量]都是一个String的对象。有人[特别是C程序员]在一些场合喜欢把字符串"当作/看成"字符数组，这也没有办法，因为字符串与字符数组存在一些内在的联系。事实上，它与字符数组是两种完全不同的对象。

        System.out.println("Hello".length());
        char[] cc={'H','i'};
        System.out.println(cc.length);

    三、字符串对象的创建:由于字符串对象的大量使用[它是一个对象，一般而言对象总是在heap分配内存]，Java中为了节省内存空间和运行时间[如比较字符串时，==比equals()快]，在编译阶段就把所有的字符串文字放到一个文字池[pool of literal strings]中，而运行时文字池成为常量池的一部分。文字池的好处，就是该池中所有相同的字符串常量被合并，只占用一个空间。我们知道，对两个引用变量，使用==判断它们的值[引用]是否相等，即指向同一个对象：


String s1 = "abc" ;String s2 = "abc" ;if( s1 == s2 )     System.out.println("s1,s2 refer to the same object");else     System.out.println("trouble");

    这里的输出显示，两个字符串文字保存为一个对象。就是说，上面的代码只在pool中创建了一个String对象。

    现在看String s = new String("abc");语句，这里"abc"本身就是pool中的一个对象，而在运行时执行new String()时，将pool中的对象复制一份放到heap中，并且把heap中的这个对象的引用交给s持有。ok，这条语句就创建了2个String对象。


String s1 = new String("abc") ;String s2 = new String("abc") ;if( s1 == s2 ){ //不会执行的语句}

    这时用==判断就可知，虽然两个对象的"内容"相同[equals()判断]，但两个引用变量所持有的引用不同，

    BTW：上面的代码创建了几个String Object? [三个，pool中一个，heap中2个。]
    [Java2 认证考试学习指南 (第4版)( 英文版)p197-199有图解。]


2、字符串的+运算和字符串转换
    字符串转换和串接是很基础的内容，因此我以为这个问题简直就是送分题。事实上，我自己就答错了。

String str = new String("jf"); // jf是接分
str = 1+2+str+3+4;
一共创建了多少String的对象？[我开始的答案：5个。jf、new、3jf、3jf3、3jf34]

    首先看JLS的有关论述：

    一、字符串转换的环境[JLS 5.4 String Conversion]

    字符串转换环境仅仅指使用双元的+运算符的情况，其中一个操作数是一个String对象。在这一特定情形下，另一操作数转换成String，表达式的结果是这两个String的串接。

    二、串接运算符[JLS 15.18.1 String Concatenation Operator + ]

    如果一个操作数/表达式是String类型，则另一个操作数在运行时转换成一个String对象，并两者串接。此时，任何类型都可以转换成String。[这里，我漏掉了"3"和"4"]

如果是基本数据类型，则如同首先转换成其包装类对象，如int x视为转换成Integer(x)。 
现在就全部统一到引用类型向String的转换了。这种转换如同[as if]调用该对象的无参数toString方法。[如果是null则转换成"null"]。因为toString方法在Object中定义，故所有的类都有该方法，而且Boolean, Character, Integer, Long, Float, Double, and String改写了该方法。 
关于+是串接还是加法，由操作数决定。1+2+str+3+4 就很容易知道是"3jf34"。[BTW :在JLS的15.18.1.3中举的一个jocular little example，真的很无趣。]
    下面的例子测试了改写toString方法的情况.。


class A{    int i = 10;    public static void main(String []args){        String str = new String("jf");        str += new A();        System.out.print(str);    }    public String toString(){        return " a.i ="+i+"\n";    }}

三、字符串转换的优化

按照上述说法，str = 1+2+str+3+4;语句似乎应该就应该生成5个String对象：

1+2 ＝3，then 3→Integer(3)→"3" in pool? [假设如此] 
"3"+str(in heap) = "3jf"     (in heap) 
"3jf" +3 ,first 3→Integer(3)→"3" in pool? [则不创建] then "3jf3" 
"3jf3"+4 create "4"  in pool 
then "3jf34"

    这里我并不清楚3、4转换成字符串后是否在池中，所以上述结果仍然是猜测。

    为了减少创建中间过渡性的字符串对象，提高反复进行串接运算时的性能，a Java compiler可以使用StringBuffer或者类似的技术，或者把转换与串接合并成一步。例如：对于 a + b + c ，Java编译器就可以将它视为[as if]

    new StringBuffer().append(a).append(b).append(c).toString();

    注意，对于基本类型和引用类型，在append(a)过程中仍然要先将参数转换，从这个观点看，str = 1+2+str+3+4;创建的字符串可能是"3"、"4"和"3jf34"[以及一个StringBuffer对象]。

    现在我仍然不知道怎么回答str = 1+2+str+3+4;创建了多少String的对象，。或许，这个问题不需要过于研究，至少SCJP不会考它。

3、这又不同：str = "3"+"jf"+"3"+"4";
    如果是一个完全由字符串文字组成的表达式，则在编译时，已经被优化而不会在运行时创建中间字符串。测试代码如下：


String str1 ="3jf34";        String str2 ="3"+"jf"+"3"+"4";         if(str1 == str2) {            System.out.println("str1 == str2");        }else {            System.out.println("think again");        }        if(str2.equals(str1))            System.out.println("yet str2.equals(str1)");

    可见，str1与str2指向同一个对象，这个对象在pool中。所有遵循Java Language Spec的编译器都必须在编译时对constant expressions 进行简化。JLS规定：Strings computed by constant expressions (ý15.28) are computed at compile time and then treated as if they were literals. 

    对于String str2 ="3"+"jf"+"3"+"4";我们说仅仅创建一个对象。注意，“创建多少对象”的讨论是说运行时创建多少对象。

    BTW：编译时优化


    String x = "aaa " + "bbb ";    if (false) {        x = x + "ccc ";    }    x +=  "ddd ";    等价于：    String x = "aaa bbb ";    x = x + "ddd ";

4、不变类
    String对象是不可改变的(immutable)。有人对str = 1+2+str+3+4;语句提出疑问,怎么str的内容可以改变？其实仍然是因为不清楚：引用变量与对象的区别。str仅仅是引用变量，它的值——它持有的引用可以改变。你不停地创建新对象，我就不断地改变指向。[参考TIJ的Read-only classes。]

    不变类的关键是，对于对象的所有操作都不可能改变原来的对象[只要需要，就返回一个改变了的新对象]。这就保证了对象不可改变。为什么要将一个类设计成不变类？有一个OOD设计的原则：Law of Demeter。其广义解读是：

    使用不变类。只要有可能，类应当设计为不变类。
<img src ="http://www.blogjava.net/mayu/aggbug/64366.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mayu/" target="_blank">my</a> 2006-08-18 15:41 <a href="http://www.blogjava.net/mayu/articles/64366.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>