﻿<?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-★yesjoy★-文章分类-设计模式</title><link>http://www.blogjava.net/yesjoy/category/7369.html</link><description>&lt;font color="red"&gt;★&lt;/font&gt;&lt;font color="blue"&gt;总在爬山 所以艰辛;总在寻梦 所以苦痛&lt;/font&gt;&lt;font color="red"&gt;★&lt;/font&gt;</description><language>zh-cn</language><lastBuildDate>Thu, 09 Sep 2010 04:35:54 GMT</lastBuildDate><pubDate>Thu, 09 Sep 2010 04:35:54 GMT</pubDate><ttl>60</ttl><item><title>单例模式完全剖析(2)---- 探究简单却又使人迷惑的单例模式</title><link>http://www.blogjava.net/yesjoy/articles/30618.html</link><dc:creator>★yesjoy★</dc:creator><author>★yesjoy★</author><pubDate>Tue, 14 Feb 2006 07:33:00 GMT</pubDate><guid>http://www.blogjava.net/yesjoy/articles/30618.html</guid><wfw:comment>http://www.blogjava.net/yesjoy/comments/30618.html</wfw:comment><comments>http://www.blogjava.net/yesjoy/articles/30618.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yesjoy/comments/commentRss/30618.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yesjoy/services/trackbacks/30618.html</trackback:ping><description><![CDATA[<H3>测试单例模式</H3><BR>接下来，我使用与log4j相对应的JUnit来测试单例类，它会贯穿在这篇文章余下的部分。如果你对JUnit或log4j不很熟悉，请参考相关资源。<BR><BR>例2是一个用JUnit测试例1的单例模式的案例：<BR><B>例2.一个单例模式的案例</B><BR>
<DIV class=codeStyle>
<OL>
<LI><B><FONT color=#0000ff>import</FONT></B>&nbsp;org.apache.log4j.<FONT color=#ff0000>Logger</FONT>; 
<LI><B><FONT color=#0000ff>import</FONT></B>&nbsp;junit.framework.<A href="http://www.javaresearch.org/source/junit3.8.1/junit/framework/Assert.java.html" target=_blank><FONT class=classLink><U>Assert</U></FONT></A>; 
<LI><B><FONT color=#0000ff>import</FONT></B>&nbsp;junit.framework.<A href="http://www.javaresearch.org/source/junit3.8.1/junit/framework/TestCase.java.html" target=_blank><FONT class=classLink><U>TestCase</U></FONT></A>; 
<LI>
<LI><B><FONT color=#0000ff>public</FONT></B>&nbsp;<B><FONT color=#0000ff>class</FONT></B>&nbsp;SingletonTest&nbsp;<B><FONT color=#0000ff>extends</FONT></B>&nbsp;<A href="http://www.javaresearch.org/source/junit3.8.1/junit/framework/TestCase.java.html" target=_blank><FONT class=classLink><U>TestCase</U></FONT></A>&nbsp;{ 
<LI>&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>private</FONT></B>&nbsp;ClassicSingleton&nbsp;sone&nbsp;=&nbsp;<B><FONT color=#0000ff>null</FONT></B>,&nbsp;stwo&nbsp;=&nbsp;<B><FONT color=#0000ff>null</FONT></B>; 
<LI>&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>private</FONT></B>&nbsp;<B><FONT color=#0000ff>static</FONT></B>&nbsp;<FONT color=#ff0000>Logger</FONT>&nbsp;logger&nbsp;=&nbsp;<FONT color=#ff0000>Logger</FONT>.getRootLogger(); 
<LI>
<LI>&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>public</FONT></B>&nbsp;SingletonTest(<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target=_blank><FONT class=classLink><U>String</U></FONT></A></B>&nbsp;name)&nbsp;{ 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>super</FONT></B>(name); 
<LI>&nbsp;&nbsp;&nbsp;} 
<LI>&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>public</FONT></B>&nbsp;<B><FONT color=#0000ff>void</FONT></B>&nbsp;setUp()&nbsp;{ 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.info(<FONT color=#ff33ff>"getting&nbsp;singleton..."</FONT>); 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sone&nbsp;=&nbsp;ClassicSingleton.getInstance(); 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.info(<FONT color=#ff33ff>"...got&nbsp;singleton:&nbsp;"</FONT>&nbsp;+&nbsp;sone); 
<LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.info(<FONT color=#ff33ff>"getting&nbsp;singleton..."</FONT>); 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;stwo&nbsp;=&nbsp;ClassicSingleton.getInstance(); 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.info(<FONT color=#ff33ff>"...got&nbsp;singleton:&nbsp;"</FONT>&nbsp;+&nbsp;stwo); 
<LI>&nbsp;&nbsp;&nbsp;} 
<LI>&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>public</FONT></B>&nbsp;<B><FONT color=#0000ff>void</FONT></B>&nbsp;testUnique()&nbsp;{ 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.info(<FONT color=#ff33ff>"checking&nbsp;singletons&nbsp;for&nbsp;equality"</FONT>); 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<A href="http://www.javaresearch.org/source/junit3.8.1/junit/framework/Assert.java.html" target=_blank><FONT class=classLink><U>Assert</U></FONT></A>.assertEquals(<B><FONT color=#0000ff>true</FONT></B>,&nbsp;sone&nbsp;==&nbsp;stwo); 
<LI>&nbsp;&nbsp;&nbsp;} 
<LI>} </LI></OL></DIV><BR>例2两次调用ClassicSingleton.getInstance()，并且把返回的引用存储在成员变量中。方法testUnique()会检查这些引用看它们是否相同。例3是这个测试案例的输出：<BR><B>例3.是这个测试案例的输出</B><BR>
<DIV class=codeStyle>
<OL>
<LI>Buildfile:&nbsp;build.xml 
<LI>
<LI>init: 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[echo]&nbsp;Build&nbsp;20030414&nbsp;(14-04-2003&nbsp;03:08) 
<LI>
<LI>compile: 
<LI>
<LI>run-test-text: 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[java]&nbsp;.INFO&nbsp;main:&nbsp;[b]getting&nbsp;singleton...[/b] 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[java]&nbsp;INFO&nbsp;main:&nbsp;[b]created&nbsp;singleton:[/b]&nbsp;Singleton@e86f41 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[java]&nbsp;INFO&nbsp;main:&nbsp;...got&nbsp;singleton:&nbsp;Singleton@e86f41 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[java]&nbsp;INFO&nbsp;main:&nbsp;[b]getting&nbsp;singleton...[/b] 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[java]&nbsp;INFO&nbsp;main:&nbsp;...got&nbsp;singleton:&nbsp;Singleton@e86f41 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[java]&nbsp;INFO&nbsp;main:&nbsp;checking&nbsp;singletons&nbsp;<B><FONT color=#0000ff>for</FONT></B>&nbsp;equality 
<LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[java]&nbsp;<FONT color=#ff0000>Time</FONT>:&nbsp;0.032 
<LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[java]&nbsp;OK&nbsp;(1&nbsp;test) </LI></OL></DIV><BR>正如前面的清单所示，例2的简单测试顺利通过----通过ClassicSingleton.getInstance()获得的两个单例类的引用确实相同;然而，你要知道这些引用是在单线程中得到的。下面的部分着重于用多线程测试单例类。<BR><BR><B>
<H3>多线程因素的考虑</H3></B><BR>在例1中的ClassicSingleton.getInstance()方法由于下面的代码而不是线程安全的：<BR>
<DIV class=codeStyle>
<OL>
<LI>1:&nbsp;<B><FONT color=#0000ff>if</FONT></B>(instance&nbsp;==&nbsp;<B><FONT color=#0000ff>null</FONT></B>)&nbsp;{ 
<LI>2:&nbsp;&nbsp;&nbsp;&nbsp;instance&nbsp;=&nbsp;<B><FONT color=#0000ff>new</FONT></B>&nbsp;Singleton(); 
<LI>3:&nbsp;} </LI></OL></DIV><BR>如果一个线程在第二行的赋值语句发生之前切换，那么成员变量instance仍然是null，然后另一个线程可能接下来进入到if块中。在这种情况下，两个不同的单例类实例就被创建。不幸的是这种假定很少发生，这样这种假定也很难在测试期间出现（译注：在这可能是作者对很少出现这种情况而导致无法测试从而使人们放松警惕而感到叹惜）。为了演示这个线程轮换，我得重新实现例1中的那个类。例4就是修订后的单例类：<BR><B>例4.人为安排的方式</B><BR>
<DIV class=codeStyle>
<OL>
<LI><B><FONT color=#0000ff>import</FONT></B>&nbsp;org.apache.log4j.<FONT color=#ff0000>Logger</FONT>; 
<LI>
<LI><B><FONT color=#0000ff>public</FONT></B>&nbsp;<B><FONT color=#0000ff>class</FONT></B>&nbsp;Singleton&nbsp;{ 
<LI>&nbsp;&nbsp;<B><FONT color=#0000ff>private</FONT></B>&nbsp;<B><FONT color=#0000ff>static</FONT></B>&nbsp;Singleton&nbsp;singleton&nbsp;=&nbsp;<B><FONT color=#0000ff>null</FONT></B>; 
<LI>&nbsp;&nbsp;<B><FONT color=#0000ff>private</FONT></B>&nbsp;<B><FONT color=#0000ff>static</FONT></B>&nbsp;<FONT color=#ff0000>Logger</FONT>&nbsp;logger&nbsp;=&nbsp;<FONT color=#ff0000>Logger</FONT>.getRootLogger(); 
<LI>&nbsp;&nbsp;<B><FONT color=#0000ff>private</FONT></B>&nbsp;<B><FONT color=#0000ff>static</FONT></B>&nbsp;<B><FONT color=#0000ff>boolean</FONT></B>&nbsp;firstThread&nbsp;=&nbsp;<B><FONT color=#0000ff>true</FONT></B>; 
<LI>
<LI>&nbsp;&nbsp;<B><FONT color=#0000ff>protected</FONT></B>&nbsp;Singleton()&nbsp;{ 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;<I><FONT color=#339900>//&nbsp;Exists&nbsp;only&nbsp;to&nbsp;defeat&nbsp;instantiation.</FONT></I> 
<LI>&nbsp;&nbsp;} 
<LI>&nbsp;&nbsp;<B><FONT color=#0000ff>public</FONT></B>&nbsp;<B><FONT color=#0000ff>static</FONT></B>&nbsp;Singleton&nbsp;getInstance()&nbsp;{ 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>if</FONT></B>(singleton&nbsp;==&nbsp;<B><FONT color=#0000ff>null</FONT></B>)&nbsp;{ 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;simulateRandomActivity(); 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;singleton&nbsp;=&nbsp;<B><FONT color=#0000ff>new</FONT></B>&nbsp;Singleton(); 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.info(<FONT color=#ff33ff>"created&nbsp;singleton:&nbsp;"</FONT>&nbsp;+&nbsp;singleton); 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>return</FONT></B>&nbsp;singleton; 
<LI>&nbsp;&nbsp;} 
<LI>&nbsp;&nbsp;<B><FONT color=#0000ff>private</FONT></B>&nbsp;<B><FONT color=#0000ff>static</FONT></B>&nbsp;<B><FONT color=#0000ff>void</FONT></B>&nbsp;simulateRandomActivity()&nbsp;{ 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>try</FONT></B>&nbsp;{ 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>if</FONT></B>(firstThread)&nbsp;{ 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;firstThread&nbsp;=&nbsp;<B><FONT color=#0000ff>false</FONT></B>; 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.info(<FONT color=#ff33ff>"sleeping..."</FONT>); 
<LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<I><FONT color=#339900>//&nbsp;This&nbsp;nap&nbsp;should&nbsp;give&nbsp;the&nbsp;second&nbsp;thread&nbsp;enough&nbsp;time</FONT></I> 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<I><FONT color=#339900>//&nbsp;to&nbsp;get&nbsp;by&nbsp;the&nbsp;first&nbsp;thread.</FONT></I> 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/Thread.java.html" target=_blank><FONT class=classLink><U>Thread</U></FONT></A></B>.currentThread().sleep(50); 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>catch</FONT></B>(<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/InterruptedException.java.html" target=_blank><FONT class=classLink><U>InterruptedException</U></FONT></A></B>&nbsp;ex)&nbsp;{ 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.warn(<FONT color=#ff33ff>"Sleep&nbsp;interrupted"</FONT>); 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} 
<LI>&nbsp;&nbsp;} 
<LI>} </LI></OL></DIV><BR>除了在这个清单中的单例类强制使用了一个多线程错误处理，例4类似于例1中的单例类。在getInstance()方法第一次被调用时，调用这个方法的线程会休眠50毫秒以便另外的线程也有时间调用getInstance()并创建一个新的单例类实例。当休眠的线程觉醒时，它也会创建一个新的单例类实例，这样我们就有两个单例类实例。尽管例4是人为如此的，但它却模拟了第一个线程调用了getInstance()并在没有完成时被切换的真实情形。<BR>例5测试了例4的单例类：<BR><B>例5.失败的测试</B><BR>
<DIV class=codeStyle>
<OL>
<LI><B><FONT color=#0000ff>import</FONT></B>&nbsp;org.apache.log4j.<FONT color=#ff0000>Logger</FONT>; 
<LI><B><FONT color=#0000ff>import</FONT></B>&nbsp;junit.framework.<A href="http://www.javaresearch.org/source/junit3.8.1/junit/framework/Assert.java.html" target=_blank><FONT class=classLink><U>Assert</U></FONT></A>; 
<LI><B><FONT color=#0000ff>import</FONT></B>&nbsp;junit.framework.<A href="http://www.javaresearch.org/source/junit3.8.1/junit/framework/TestCase.java.html" target=_blank><FONT class=classLink><U>TestCase</U></FONT></A>; 
<LI>
<LI><B><FONT color=#0000ff>public</FONT></B>&nbsp;<B><FONT color=#0000ff>class</FONT></B>&nbsp;SingletonTest&nbsp;<B><FONT color=#0000ff>extends</FONT></B>&nbsp;<A href="http://www.javaresearch.org/source/junit3.8.1/junit/framework/TestCase.java.html" target=_blank><FONT class=classLink><U>TestCase</U></FONT></A>&nbsp;{ 
<LI>&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>private</FONT></B>&nbsp;<B><FONT color=#0000ff>static</FONT></B>&nbsp;<FONT color=#ff0000>Logger</FONT>&nbsp;logger&nbsp;=&nbsp;<FONT color=#ff0000>Logger</FONT>.getRootLogger(); 
<LI>&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>private</FONT></B>&nbsp;<B><FONT color=#0000ff>static</FONT></B>&nbsp;Singleton&nbsp;singleton&nbsp;=&nbsp;<B><FONT color=#0000ff>null</FONT></B>; 
<LI>
<LI>&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>public</FONT></B>&nbsp;SingletonTest(<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/String.java.html" target=_blank><FONT class=classLink><U>String</U></FONT></A></B>&nbsp;name)&nbsp;{ 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>super</FONT></B>(name); 
<LI>&nbsp;&nbsp;&nbsp;} 
<LI>&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>public</FONT></B>&nbsp;<B><FONT color=#0000ff>void</FONT></B>&nbsp;setUp()&nbsp;{ 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;singleton&nbsp;=&nbsp;<B><FONT color=#0000ff>null</FONT></B>; 
<LI>&nbsp;&nbsp;&nbsp;} 
<LI>&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>public</FONT></B>&nbsp;<B><FONT color=#0000ff>void</FONT></B>&nbsp;testUnique()&nbsp;<B><FONT color=#0000ff>throws</FONT></B>&nbsp;<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/InterruptedException.java.html" target=_blank><FONT class=classLink><U>InterruptedException</U></FONT></A></B>&nbsp;{ 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<I><FONT color=#339900>//&nbsp;Both&nbsp;threads&nbsp;call&nbsp;Singleton.getInstance().</FONT></I> 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/Thread.java.html" target=_blank><FONT class=classLink><U>Thread</U></FONT></A></B>&nbsp;threadOne&nbsp;=&nbsp;<B><FONT color=#0000ff>new</FONT></B>&nbsp;<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/Thread.java.html" target=_blank><FONT class=classLink><U>Thread</U></FONT></A></B>(<B><FONT color=#0000ff>new</FONT></B>&nbsp;SingletonTestRunnable()), 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;threadTwo&nbsp;=&nbsp;<B><FONT color=#0000ff>new</FONT></B>&nbsp;<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/Thread.java.html" target=_blank><FONT class=classLink><U>Thread</U></FONT></A></B>(<B><FONT color=#0000ff>new</FONT></B>&nbsp;SingletonTestRunnable()); 
<LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;threadOne.start(); 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;threadTwo.start(); 
<LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;threadOne.join(); 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;threadTwo.join(); 
<LI>&nbsp;&nbsp;&nbsp;} 
<LI>&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>private</FONT></B>&nbsp;<B><FONT color=#0000ff>static</FONT></B>&nbsp;<B><FONT color=#0000ff>class</FONT></B>&nbsp;SingletonTestRunnable&nbsp;<B><FONT color=#0000ff>implements</FONT></B>&nbsp;<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/Runnable.java.html" target=_blank><FONT class=classLink><U>Runnable</U></FONT></A></B>&nbsp;{ 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>public</FONT></B>&nbsp;<B><FONT color=#0000ff>void</FONT></B>&nbsp;run()&nbsp;{ 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<I><FONT color=#339900>//&nbsp;Get&nbsp;a&nbsp;reference&nbsp;to&nbsp;the&nbsp;singleton.</FONT></I> 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Singleton&nbsp;s&nbsp;=&nbsp;Singleton.getInstance(); 
<LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<I><FONT color=#339900>//&nbsp;Protect&nbsp;singleton&nbsp;member&nbsp;variable&nbsp;from</FONT></I> 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<I><FONT color=#339900>//&nbsp;multithreaded&nbsp;access.</FONT></I> 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>synchronized</FONT></B>(SingletonTest.<B><FONT color=#0000ff>class</FONT></B>)&nbsp;{ 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>if</FONT></B>(singleton&nbsp;==&nbsp;<B><FONT color=#0000ff>null</FONT></B>)&nbsp;<I><FONT color=#339900>//&nbsp;If&nbsp;local&nbsp;reference&nbsp;is&nbsp;null...</FONT></I> 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;singleton&nbsp;=&nbsp;s;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<I><FONT color=#339900>//&nbsp;...set&nbsp;it&nbsp;to&nbsp;the&nbsp;singleton</FONT></I> 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<I><FONT color=#339900>//&nbsp;Local&nbsp;reference&nbsp;must&nbsp;be&nbsp;equal&nbsp;to&nbsp;the&nbsp;one&nbsp;and</FONT></I> 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<I><FONT color=#339900>//&nbsp;only&nbsp;instance&nbsp;of&nbsp;Singleton;&nbsp;otherwise,&nbsp;we&nbsp;have&nbsp;two</FONT></I> 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<I><FONT color=#339900>//&nbsp;Singleton&nbsp;instances.</FONT></I> 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<A href="http://www.javaresearch.org/source/junit3.8.1/junit/framework/Assert.java.html" target=_blank><FONT class=classLink><U>Assert</U></FONT></A>.assertEquals(<B><FONT color=#0000ff>true</FONT></B>,&nbsp;s&nbsp;==&nbsp;singleton); 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} 
<LI>&nbsp;&nbsp;&nbsp;} 
<LI>} </LI></OL></DIV><BR>例5的测试案例创建两个线程，然后各自启动，等待完成。这个案例保持了一个对单例类的静态引用，每个线程都会调用Singleton.getInstance()。如果这个静态成员变量没有被设置，那么第一个线程就会将它设为通过调用getInstance()而得到的引用，然后这个静态变量会与一个局部变量比较是否相等。<BR>在这个测试案例运行时会发生一系列的事情：第一个线程调用getInstance()，进入if块，然后休眠;接着，第二个线程也调用getInstance()并且创建了一个单例类的实例。第二个线程会设置这个静态成员变量为它所创建的引用。第二个线程检查这个静态成员变量与一个局部备份的相等性。然后测试通过。当第一个线程觉醒时，它也会创建一个单例类的实例，并且它不会设置那个静态成员变量（因为第二个线程已经设置过了），所以那个静态变量与那个局部变量脱离同步，相等性测试即告失败。例6列出了例5的输出：<BR><B>例6.例5的输出</B><BR>
<DIV class=codeStyle>
<OL>
<LI>Buildfile:&nbsp;build.xml 
<LI>init: 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[echo]&nbsp;Build&nbsp;20030414&nbsp;(14-04-2003&nbsp;03:06) 
<LI>compile: 
<LI>run-test-text: 
<LI>INFO&nbsp;<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/Thread.java.html" target=_blank><FONT class=classLink><U>Thread</U></FONT></A></B>-1:&nbsp;sleeping... 
<LI>INFO&nbsp;<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/Thread.java.html" target=_blank><FONT class=classLink><U>Thread</U></FONT></A></B>-2:&nbsp;created&nbsp;singleton:&nbsp;Singleton@7e5cbd 
<LI>INFO&nbsp;<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/Thread.java.html" target=_blank><FONT class=classLink><U>Thread</U></FONT></A></B>-1:&nbsp;created&nbsp;singleton:&nbsp;Singleton@704ebb 
<LI>junit.framework.<A href="http://www.javaresearch.org/source/junit3.8.1/junit/framework/AssertionFailedError.java.html" target=_blank><FONT class=classLink><U>AssertionFailedError</U></FONT></A>:&nbsp;expected:&nbsp;but&nbsp;was: 
<LI>&nbsp;&nbsp;&nbsp;at&nbsp;junit.framework.<A href="http://www.javaresearch.org/source/junit3.8.1/junit/framework/Assert.java.html" target=_blank><FONT class=classLink><U>Assert</U></FONT></A>.fail(Assert.java:47) 
<LI>&nbsp;&nbsp;&nbsp;at&nbsp;junit.framework.<A href="http://www.javaresearch.org/source/junit3.8.1/junit/framework/Assert.java.html" target=_blank><FONT class=classLink><U>Assert</U></FONT></A>.failNotEquals(Assert.java:282) 
<LI>&nbsp;&nbsp;&nbsp;at&nbsp;junit.framework.<A href="http://www.javaresearch.org/source/junit3.8.1/junit/framework/Assert.java.html" target=_blank><FONT class=classLink><U>Assert</U></FONT></A>.assertEquals(Assert.java:64) 
<LI>&nbsp;&nbsp;&nbsp;at&nbsp;junit.framework.<A href="http://www.javaresearch.org/source/junit3.8.1/junit/framework/Assert.java.html" target=_blank><FONT class=classLink><U>Assert</U></FONT></A>.assertEquals(Assert.java:149) 
<LI>&nbsp;&nbsp;&nbsp;at&nbsp;junit.framework.<A href="http://www.javaresearch.org/source/junit3.8.1/junit/framework/Assert.java.html" target=_blank><FONT class=classLink><U>Assert</U></FONT></A>.assertEquals(Assert.java:155) 
<LI>&nbsp;&nbsp;&nbsp;at&nbsp;SingletonTest$SingletonTestRunnable.run(Unknown&nbsp;<FONT color=#ff0000>Source</FONT>) 
<LI>&nbsp;&nbsp;&nbsp;at&nbsp;java.lang.<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/Thread.java.html" target=_blank><FONT class=classLink><U>Thread</U></FONT></A></B>.run(<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/Thread.java.html" target=_blank><FONT class=classLink><U>Thread</U></FONT></A></B>.java:554) 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[java]&nbsp;. 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[java]&nbsp;<FONT color=#ff0000>Time</FONT>:&nbsp;0.577 
<LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[java]&nbsp;OK&nbsp;(1&nbsp;test) </LI></OL></DIV><BR>到现在为止我们已经知道例4不是线程安全的，那就让我们看看如何修正它。<BR><BR><B>
<H3>同步</H3></B><BR>要使例4的单例类为线程安全的很容易----只要像下面一个同步化getInstance()方法：<BR>
<DIV class=codeStyle>
<OL>
<LI><B><FONT color=#0000ff>public</FONT></B>&nbsp;<B><FONT color=#0000ff>synchronized</FONT></B>&nbsp;<B><FONT color=#0000ff>static</FONT></B>&nbsp;Singleton&nbsp;getInstance()&nbsp;{ 
<LI>&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>if</FONT></B>(singleton&nbsp;==&nbsp;<B><FONT color=#0000ff>null</FONT></B>)&nbsp;{ 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;simulateRandomActivity(); 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;singleton&nbsp;=&nbsp;<B><FONT color=#0000ff>new</FONT></B>&nbsp;Singleton(); 
<LI>&nbsp;&nbsp;&nbsp;} 
<LI>&nbsp;&nbsp;&nbsp;logger.info(<FONT color=#ff33ff>"created&nbsp;singleton:&nbsp;"</FONT>&nbsp;+&nbsp;singleton); 
<LI>&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>return</FONT></B>&nbsp;singleton; 
<LI>} </LI></OL></DIV><BR>在同步化getInstance()方法后，我们就可以得到例5的测试案例返回的下面的结果：<BR>
<DIV class=codeStyle>
<OL>
<LI>
<LI>Buildfile:&nbsp;build.xml 
<LI>
<LI>init: 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[echo]&nbsp;Build&nbsp;20030414&nbsp;(14-04-2003&nbsp;03:15) 
<LI>
<LI>compile: 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;[javac]&nbsp;Compiling&nbsp;2&nbsp;source&nbsp;files 
<LI>
<LI>run-test-text: 
<LI>INFO&nbsp;<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/Thread.java.html" target=_blank><FONT class=classLink><U>Thread</U></FONT></A></B>-1:&nbsp;sleeping... 
<LI>INFO&nbsp;<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/Thread.java.html" target=_blank><FONT class=classLink><U>Thread</U></FONT></A></B>-1:&nbsp;created&nbsp;singleton:&nbsp;Singleton@ef577d 
<LI>INFO&nbsp;<B><A href="http://www.javaresearch.org/source/jdk142/java/lang/Thread.java.html" target=_blank><FONT class=classLink><U>Thread</U></FONT></A></B>-2:&nbsp;created&nbsp;singleton:&nbsp;Singleton@ef577d 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[java]&nbsp;. 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[java]&nbsp;<FONT color=#ff0000>Time</FONT>:&nbsp;0.513 
<LI>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[java]&nbsp;OK&nbsp;(1&nbsp;test) </LI></OL></DIV><BR>这此，这个测试案例工作正常，并且多线程的烦恼也被解决;然而，机敏的读者可能会认识到getInstance()方法只需要在第一次被调用时同步。因为同步的性能开销很昂贵（同步方法比非同步方法能降低到100次左右），或许我们可以引入一种性能改进方法，它只同步单例类的getInstance()方法中的赋值语句。<BR><B>
<H3>一种性能改进的方法</H3></B><BR>寻找一种性能改进方法时，你可能会选择像下面这样重写getInstance()方法：<BR>
<DIV class=codeStyle>
<OL>
<LI>
<LI><B><FONT color=#0000ff>public</FONT></B>&nbsp;<B><FONT color=#0000ff>static</FONT></B>&nbsp;Singleton&nbsp;getInstance()&nbsp;{ 
<LI>&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>if</FONT></B>(singleton&nbsp;==&nbsp;<B><FONT color=#0000ff>null</FONT></B>)&nbsp;{ 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>synchronized</FONT></B>(Singleton.<B><FONT color=#0000ff>class</FONT></B>)&nbsp;{&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;singleton&nbsp;=&nbsp;<B><FONT color=#0000ff>new</FONT></B>&nbsp;Singleton(); 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} 
<LI>&nbsp;&nbsp;&nbsp;} 
<LI>&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>return</FONT></B>&nbsp;singleton; 
<LI>} </LI></OL></DIV><BR>这个代码片段只同步了关键的代码，而不是同步整个方法。然而这段代码却不是线程安全的。考虑一下下面的假定：线程1进入同步块，并且在它给singleton成员变量赋值之前线程1被切换。接着另一个线程进入if块。第二个线程将等待直到第一个线程完成，并且仍然会得到两个不同的单例类实例。有修复这个问题的方法吗？请读下去。<BR><B>
<H3>双重加锁检查</H3></B><BR>初看上去，双重加锁检查似乎是一种使懒汉式实例化为线程安全的技术。下面的代码片段展示了这种技术：<BR>
<DIV class=codeStyle>
<OL>
<LI><B><FONT color=#0000ff>public</FONT></B>&nbsp;<B><FONT color=#0000ff>static</FONT></B>&nbsp;Singleton&nbsp;getInstance()&nbsp;{ 
<LI>&nbsp;&nbsp;<B><FONT color=#0000ff>if</FONT></B>(singleton&nbsp;==&nbsp;<B><FONT color=#0000ff>null</FONT></B>)&nbsp;{ 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>synchronized</FONT></B>(Singleton.<B><FONT color=#0000ff>class</FONT></B>)&nbsp;{ 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>if</FONT></B>(singleton&nbsp;==&nbsp;<B><FONT color=#0000ff>null</FONT></B>)&nbsp;{ 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;singleton&nbsp;=&nbsp;<B><FONT color=#0000ff>new</FONT></B>&nbsp;Singleton(); 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;} 
<LI>&nbsp;&nbsp;} 
<LI>&nbsp;&nbsp;<B><FONT color=#0000ff>return</FONT></B>&nbsp;singleton; 
<LI>} </LI></OL></DIV><BR>如果两个线程同时访问getInstance()方法会发生什么？想像一下线程1进行同步块马上又被切换。接着，第二个线程进入if&nbsp;块。当线程1退出同步块时，线程2会重新检查看是否singleton实例仍然为null。因为线程1设置了singleton成员变量，所以线程2的第二次检查会失败，第二个单例类实例也就不会被创建。似乎就是如此。<BR>不幸的是，双重加锁检查不会保证正常工作，因为编译器会在Singleton的构造方法被调用之前随意给singleton赋一个值。如果在singleton引用被赋值之后而被初始化之前线程1被切换，线程2就会被返回一个对未初始化的单例类实例的引用。<BR><B>
<H3>一个改进的线程安全的单例模式实现</H3></B><BR>例7列出了一个简单、快速而又是线程安全的单例模式实现：<BR><B>例7.一个简单的单例类</B><BR>
<DIV class=codeStyle>
<OL>
<LI><B><FONT color=#0000ff>public</FONT></B>&nbsp;<B><FONT color=#0000ff>class</FONT></B>&nbsp;Singleton&nbsp;{ 
<LI>&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>public</FONT></B>&nbsp;<B><FONT color=#0000ff>final</FONT></B>&nbsp;<B><FONT color=#0000ff>static</FONT></B>&nbsp;Singleton&nbsp;INSTANCE&nbsp;=&nbsp;<B><FONT color=#0000ff>new</FONT></B>&nbsp;Singleton(); 
<LI>&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>private</FONT></B>&nbsp;Singleton()&nbsp;{ 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<I><FONT color=#339900>//&nbsp;Exists&nbsp;only&nbsp;to&nbsp;defeat&nbsp;instantiation.</FONT></I> 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} 
<LI>} </LI></OL></DIV><BR>这段代码是线程安全的是因为静态成员变量一定会在类被第一次访问时被创建。你得到了一个自动使用了懒汉式实例化的线程安全的实现;你应该这样使用它：<BR>
<DIV class=codeStyle>
<OL>
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Singleton&nbsp;singleton&nbsp;=&nbsp;Singleton.INSTANCE; 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;singleton.dothis(); 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;singleton.dothat(); 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;... </LI></OL></DIV><BR>当然万事并不完美，前面的Singleton只是一个折衷的方案;如果你使用那个实现，你就无法改变它以便后来你可能想要允许多个单例类的实例。用一种更折哀的单例模式实现(通过一个getInstance()方法获得实例)你可以改变这个方法以便返回一个唯一的实例或者是数百个实例中的一个．你不能用一个公开且是静态的（public&nbsp;static)成员变量这样做．<BR><BR>你可以安全的使用例７的单例模式实现或者是例１的带一个同步的getInstance()方法的实现．然而，我们必须要研究另一个问题：你必须在编译期指定这个单例类，这样就不是很灵活．一个单例类的注册表会让我们在运行期指定一个单例类．<BR><img src ="http://www.blogjava.net/yesjoy/aggbug/30618.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yesjoy/" target="_blank">★yesjoy★</a> 2006-02-14 15:33 <a href="http://www.blogjava.net/yesjoy/articles/30618.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>单例模式完全剖析(1)---- 探究简单却又使人迷惑的单例模式</title><link>http://www.blogjava.net/yesjoy/articles/30617.html</link><dc:creator>★yesjoy★</dc:creator><author>★yesjoy★</author><pubDate>Tue, 14 Feb 2006 07:32:00 GMT</pubDate><guid>http://www.blogjava.net/yesjoy/articles/30617.html</guid><wfw:comment>http://www.blogjava.net/yesjoy/comments/30617.html</wfw:comment><comments>http://www.blogjava.net/yesjoy/articles/30617.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yesjoy/comments/commentRss/30617.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yesjoy/services/trackbacks/30617.html</trackback:ping><description><![CDATA[<STRONG>概要<BR></STRONG><U>单例模式是最简单的设计模式之一，但是对于Java的开发者来说，它却有很多缺陷。在本月的专栏中，David&nbsp;Geary探讨了单例模式以及在面对多线程（multithreading)、类装载器（classloaders）和序列化(serialization)时如何处理这些缺陷。</U><BR><BR>单例模式适合于一个类只有一个实例的情况，比如窗口管理器，打印缓冲池和文件系统，它们都是原型的例子。典型的情况是，那些对象的类型被遍及一个软件系统的不同对象访问，因此需要一个全局的访问指针，这便是众所周知的单例模式的应用。当然这只有在你确信你不再需要任何多于一个的实例的情况下。<BR>单例模式的用意在于前一段中所关心的。通过单例模式你可以：<BR><BR>
<LI>确保一个类只有一个实例被建立 
<LI>提供了一个对对象的全局访问指针 
<LI>在不影响单例类的客户端的情况下允许将来有多个实例<BR><BR>尽管单例设计模式如在下面的图中的所显示的一样是最简单的设计模式，但对于粗心的Java开发者来说却呈现出许多缺陷。这篇文章讨论了单例模式并揭示了那些缺陷。<BR>注意：你可以从<A class=l2 href="http://www.javaworld.com/javaworld/jw-04-2003/jw-0425-designpatterns.html?#resources" target=_blank><U>Resources</U></A>下载这篇文章的源代码。<BR><BR><B>
<H3>单例模式</H3></B><BR>在《设计模式》一书中，作者这样来叙述单例模式的：确保一个类只有一个实例并提供一个对它的全局访问指针。<BR>下图说明了单例模式的类图。<BR>（图1）<BR><IMG src="http://www.javaworld.com/javaworld/jw-04-2003/images/jw-0425-designpatterns1.jpg"><BR><B>单例模式的类图</B><BR><BR>正如你在上图中所看到的，这不是单例模式的完整部分。此图中单例类保持了一个对唯一的单例实例的静态引用，并且会从静态getInstance()方法中返回对那个实例的引用。<BR>例1显示了一个经典的单例模式的实现。<BR>例1.经典的单例模式<BR>
<DIV class=codeStyle>
<OL>
<LI><B><FONT color=#0000ff>public</FONT></B>&nbsp;<B><FONT color=#0000ff>class</FONT></B>&nbsp;ClassicSingleton&nbsp;{ 
<LI>&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>private</FONT></B>&nbsp;<B><FONT color=#0000ff>static</FONT></B>&nbsp;ClassicSingleton&nbsp;instance&nbsp;=&nbsp;<B><FONT color=#0000ff>null</FONT></B>; 
<LI>
<LI>&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>protected</FONT></B>&nbsp;ClassicSingleton()&nbsp;{ 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<I><FONT color=#339900>//&nbsp;Exists&nbsp;only&nbsp;to&nbsp;defeat&nbsp;instantiation.</FONT></I> 
<LI>&nbsp;&nbsp;&nbsp;} 
<LI>&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>public</FONT></B>&nbsp;<B><FONT color=#0000ff>static</FONT></B>&nbsp;ClassicSingleton&nbsp;getInstance()&nbsp;{ 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>if</FONT></B>(instance&nbsp;==&nbsp;<B><FONT color=#0000ff>null</FONT></B>)&nbsp;{ 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;instance&nbsp;=&nbsp;<B><FONT color=#0000ff>new</FONT></B>&nbsp;ClassicSingleton(); 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<B><FONT color=#0000ff>return</FONT></B>&nbsp;instance; 
<LI>&nbsp;&nbsp;&nbsp;} 
<LI>} </LI></OL></DIV><BR>在例1中的单例模式的实现很容易理解。ClassicSingleton类保持了一个对单独的单例实例的静态引用，并且从静态方法getInstance()中返回那个引用。<BR>关于ClassicSingleton类，有几个让我们感兴趣的地方。首先，ClassicSingleton使用了一个众所周知的懒汉式实例化去创建那个单例类的引用;结果，这个单例类的实例直到getInstance()方法被第一次调用时才被创建。这种技巧可以确保单例类的实例只有在需要时才被建立出来。其次，注意ClassicSingleton实现了一个protected的构造方法，这样客户端不能直接实例化一个ClassicSingleton类的实例。然而，你会惊奇的发现下面的代码完全合法：<BR>
<DIV class=codeStyle>
<OL>
<LI><B><FONT color=#0000ff>public</FONT></B>&nbsp;<B><FONT color=#0000ff>class</FONT></B>&nbsp;SingletonInstantiator&nbsp;{&nbsp; 
<LI>&nbsp;&nbsp;<B><FONT color=#0000ff>public</FONT></B>&nbsp;SingletonInstantiator()&nbsp;{&nbsp; 
<LI>&nbsp;&nbsp;&nbsp;ClassicSingleton&nbsp;instance&nbsp;=&nbsp;ClassicSingleton.getInstance(); 
<LI>ClassicSingleton&nbsp;anotherInstance&nbsp;= 
<LI><B><FONT color=#0000ff>new</FONT></B>&nbsp;ClassicSingleton(); 
<LI>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;...&nbsp; 
<LI>&nbsp;&nbsp;}&nbsp; 
<LI>} </LI></OL></DIV><BR>前面这个代码片段为何能在没有继承ClassicSingleton并且ClassicSingleton类的构造方法是protected的情况下创建其实例？答案是protected的构造方法可以被其子类以及在同一个包中的其它类调用。因为ClassicSingleton和SingletonInstantiator位于相同的包（缺省的包），所以SingletonInstantiator方法能创建ClasicSingleton的实例。<BR>这种情况下有两种解决方案：一是你可以使ClassicSingleton的构造方法变化私有的（private）这样只有ClassicSingleton的方法能调用它;然而这也意味着ClassicSingleton不能有子类。有时这是一种很合意的解决方法，如果确实如此，那声明你的单例类为final是一个好主意，这样意图明确，并且让编译器去使用一些性能优化选项。另一种解决方法是把你的单例类放到一个外在的包中，以便在其它包中的类（包括缺省的包）无法实例化一个单例类。<BR>关于ClassicSingleton的第三点感兴趣的地方是，如果单例由不同的类装载器装入，那便有可能存在多个单例类的实例。假定不是远端存取，例如一些servlet容器对每个servlet使用完全不同的类装载器，这样的话如果有两个servlet访问一个单例类，它们就都会有各自的实例。<BR>第四点，如果ClasicSingleton实现了java.io.Serializable接口，那么这个类的实例就可能被序列化和复原。不管怎样，如果你序列化一个单例类的对象，接下来复原多个那个对象，那你就会有多个单例类的实例。<BR>最后也许是最重要的一点，就是例1中的ClassicSingleton类不是线程安全的。如果两个线程，我们称它们为线程1和线程2，在同一时间调用ClassicSingleton.getInstance()方法，如果线程1先进入if块，然后线程2进行控制，那么就会有ClassicSingleton的两个的实例被创建。<BR><BR>正如你从前面的讨论中所看到的，尽管单例模式是最简单的设计模式之一，在Java中实现它也是决非想象的那么简单。这篇文章接下来会揭示Java规范对单例模式进行的考虑，但是首先让我们近水楼台的看看你如何才能测试你的单例类。<BR><BR>未完待续。 <BR></LI><img src ="http://www.blogjava.net/yesjoy/aggbug/30617.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yesjoy/" target="_blank">★yesjoy★</a> 2006-02-14 15:32 <a href="http://www.blogjava.net/yesjoy/articles/30617.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java23种模式一点就通</title><link>http://www.blogjava.net/yesjoy/articles/30615.html</link><dc:creator>★yesjoy★</dc:creator><author>★yesjoy★</author><pubDate>Tue, 14 Feb 2006 07:31:00 GMT</pubDate><guid>http://www.blogjava.net/yesjoy/articles/30615.html</guid><wfw:comment>http://www.blogjava.net/yesjoy/comments/30615.html</wfw:comment><comments>http://www.blogjava.net/yesjoy/articles/30615.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yesjoy/comments/commentRss/30615.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yesjoy/services/trackbacks/30615.html</trackback:ping><description><![CDATA[创建型模式<BR><BR>FACTORY?人才市场：以往是要哪个人才，就找哪个人才，效率低，现在有了人才市场，我们只需<BR>直接去人才市场挑一个好了；<BR><BR>BUILDER?生产流水线：以前是手工业作坊式的人工单个单个的生产零件然后一步一步组装做，好<BR>比有了工业革命，现在都由生产流水线代替了。如要造丰田汽车，先制定汽车的构造如由车胎、方<BR>向盘、发动机组成。再以此构造标准生产丰田汽车的车胎、方向盘、发动机。然后进行组装。最后<BR>得到丰田汽车；<BR><BR>PROTOTYPE?印刷术的发明：以前只能临贴才能保持和别人的字迹基本相同，直从印刷技术发明，<BR>从而保证了复制得和原物一模一样；<BR><BR>SINGLETON?唯一：以前是商标满天飞，相同的商标难免造成侵权，直从有商标保护法后，就保证<BR>了不会再产生第家企业使用相同的商标；<BR>结构型模式<BR><BR>ADAPTER?集众人之私，成一己之公：武当派张三丰会太极拳，少林派智空大师会金刚般若掌，如<BR>果他们两个都成为我的师傅，我就既会太极拳，又会金刚般若掌了；<BR><BR>DECORATOR?青出于蓝而胜于蓝：武当派张三丰会太极拳，是我师傅，他教会了我太极拳，但我自<BR>己还会点蒙古式摔交，张三丰却不会。于是我就成了DECORATOR模式的实现；<BR><BR>BRIDGE?白马非马：马之颜色有黑白，马之性别有公母。我们说”这是马”太抽象，说”这是黑色<BR>的公马”又太死板，只有将颜色与性别和马动态组合，”这是（黑色的或白色的）（公或母）马”<BR>才显得灵活而飘逸，如此bridge模式精髓得矣。<BR><BR>COMPOSITE?大家族：子又生孙，孙又生子，子子孙孙，无穷尽也，将众多纷杂的人口组织成一个<BR>按辈分排列的大家族即是此模式的实现；<BR><BR>FACADE?求同存异：高中毕业需读初中和高中，博士也需读初中和高中，因此国家将初中和高中普<BR>及成九年制义务教育；<BR><BR>FLYWEIGHT?一劳永逸：认识三千汉字，可以应付日常读书与写字，可见头脑中存在这个汉字库的<BR>重要；<BR><BR>PROXY?垂帘听政：犹如清朝康熙年间的四大府臣，很多权利不在皇帝手里，必须通过辅佐大臣去<BR>办；<BR><BR><BR>行为模式<BR><BR>CHAIN&nbsp;OF&nbsp;RESPONSIBLEITY?租房：以前为了找房到处打听，效率低且找不到好的房源。现在有了<BR>房屋中介，于是向房屋中介提出租房请求，中介提供一个合适的房源，满意则不再请求，不满意<BR>继续看房，直到满意为止；<BR><BR>COMMAND?借刀杀人：以前是想杀谁就杀，但一段时间后领悟到，长此以往必将结仇太多，于是假<BR>手他人，挑拨他人之间的关系从而达到自己的目的；<BR><BR>INTERPRETER?文言文注释：一段文言文，将它翻译成白话文；<BR><BR>ITERATOR?赶尽杀绝：一个一个的搜索，绝不放掉一个；<BR><BR>MEDIATOR?三角债：本来千头万绪的债务关系，忽出来一中介，包揽其一切，于是三角关系变成了<BR>独立的三方找第四方中介的关系；<BR><BR>MEMENTO?有福同享：我有多少，你就有多少；<BR><BR>OBSERVER?看守者：一旦被看守者有什么异常情况，定会及时做出反应；<BR><BR>STATE?进出自由：如一扇门，能进能出，如果有很多人随时进进出出必定显得杂乱而安全，如今<BR>设一保安限制其进出，如此各人进出才显得规范；<BR><BR>STRATEGY?久病成良医：如人生病可以有各种症状，但经过长期摸索，就可以总结出感冒、肺病、<BR>肝炎等几种；<BR><BR><BR>TEMPLATE&nbsp;METHOD??理论不一定要实践：教练的学生会游泳就行了，至于教练会不会则无关紧要；<BR><BR>VISITOR?依法治罪：因张三杀人要被处死，李四偷窃要被罚款。由此势必制定处罚制度，故制定<BR>法律写明杀人、放火、偷窃等罪要受什么处罚，经通过后须变动要小。今后有人犯罪不管是谁，按<BR>共条例处罚即是，这就是访问者模式诞生的全过程；&nbsp;&nbsp; <BR><img src ="http://www.blogjava.net/yesjoy/aggbug/30615.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yesjoy/" target="_blank">★yesjoy★</a> 2006-02-14 15:31 <a href="http://www.blogjava.net/yesjoy/articles/30615.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>设计模式的基础</title><link>http://www.blogjava.net/yesjoy/articles/30306.html</link><dc:creator>★yesjoy★</dc:creator><author>★yesjoy★</author><pubDate>Sat, 11 Feb 2006 14:57:00 GMT</pubDate><guid>http://www.blogjava.net/yesjoy/articles/30306.html</guid><wfw:comment>http://www.blogjava.net/yesjoy/comments/30306.html</wfw:comment><comments>http://www.blogjava.net/yesjoy/articles/30306.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yesjoy/comments/commentRss/30306.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yesjoy/services/trackbacks/30306.html</trackback:ping><description><![CDATA[<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><FONT face=宋体><SPAN class=1Char><SPAN style="FONT-SIZE: 22pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'"><STRONG>设计模式和设计原则</STRONG></SPAN></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 style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">设计模式和设计原则是对面向对象程序设计的一个具体应用，为此我们首先需要回顾和总结一下面向对象程序设计的一些基本内容，同时也是为了引出设计模式和设计原则。</SPAN><SPAN lang=EN-US><BR><BR></SPAN><SPAN class=2Char><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 黑体; mso-ascii-font-family: Arial; mso-bidi-font-family: 'Times New Roman'"><STRONG>1、子类继承所有父类的属性和方法吗？什么是隐藏？什么是覆盖？</STRONG></SPAN></SPAN></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'">解释一：</SPAN><SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 黑体">子类是继承了父类的所有属性和方法，但是并不一定都可见，可认为是间接可见。</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">所谓继承就是指你有的我全有，即父类有的子类全都有。</SPAN></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'">下面一个问题给出了子类是否可见的一个标准。</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">作用域</SPAN><SPAN lang=EN-US style="COLOR: black">public,private,protected,</SPAN><SPAN style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">以及不写时的区别（</SPAN><SPAN style="COLOR: black; FONT-FAMILY: 宋体; mso-bidi-font-family: 宋体">不写时默认为</SPAN><SPAN lang=EN-US style="COLOR: black">friendly</SPAN><SPAN style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">）</SPAN><SPAN lang=EN-US style="COLOR: black"><BR></SPAN><SPAN style="COLOR: black; FONT-FAMILY: 宋体; mso-bidi-font-family: 宋体">答：区别如下：</SPAN><SPAN lang=EN-US style="COLOR: black"><?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /><o:p></o:p></SPAN></P>
<TABLE class=MsoTableGrid style="BORDER-RIGHT: medium none; BORDER-TOP: medium none; BORDER-LEFT: medium none; BORDER-BOTTOM: medium none; BORDER-COLLAPSE: collapse; mso-border-alt: solid windowtext .5pt; mso-yfti-tbllook: 480; mso-padding-alt: 0cm 5.4pt 0cm 5.4pt; mso-border-insideh: .5pt solid windowtext; mso-border-insidev: .5pt solid windowtext" cellSpacing=0 cellPadding=0 border=1>
<TBODY>
<TR style="mso-yfti-irow: 0; mso-yfti-firstrow: yes">
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent; mso-border-alt: solid windowtext .5pt" vAlign=top>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN style="COLOR: black; FONT-FAMILY: 宋体; mso-bidi-font-family: 宋体">作用域</SPAN><SPAN lang=EN-US style="COLOR: black"><o:p></o:p></SPAN></P></TD>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: #ece9d8; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt" vAlign=top>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">当前类</SPAN><SPAN lang=EN-US style="COLOR: black"><o:p></o:p></SPAN></P></TD>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: #ece9d8; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt" vAlign=top>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">同一</SPAN><SPAN lang=EN-US style="COLOR: black">package<o:p></o:p></SPAN></P></TD>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: #ece9d8; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt" vAlign=top>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">子孙类</SPAN><SPAN lang=EN-US style="COLOR: black"><o:p></o:p></SPAN></P></TD>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: #ece9d8; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt" vAlign=top>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">其他</SPAN><SPAN lang=EN-US style="COLOR: black">package<o:p></o:p></SPAN></P></TD></TR>
<TR style="mso-yfti-irow: 1">
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: #ece9d8; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt" vAlign=top>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN lang=EN-US style="COLOR: black">Public<o:p></o:p></SPAN></P></TD>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: #ece9d8; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: #ece9d8; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt" vAlign=top>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">√</SPAN><SPAN lang=EN-US style="COLOR: black"><o:p></o:p></SPAN></P></TD>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: #ece9d8; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: #ece9d8; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt" vAlign=top>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">√</SPAN><SPAN lang=EN-US style="COLOR: black"><o:p></o:p></SPAN></P></TD>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: #ece9d8; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: #ece9d8; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt" vAlign=top>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">√</SPAN><SPAN lang=EN-US style="COLOR: black"><o:p></o:p></SPAN></P></TD>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: #ece9d8; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: #ece9d8; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt" vAlign=top>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">√</SPAN><SPAN lang=EN-US style="COLOR: black"><o:p></o:p></SPAN></P></TD></TR>
<TR style="mso-yfti-irow: 2">
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: #ece9d8; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt" vAlign=top>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN lang=EN-US style="COLOR: black">Protected<o:p></o:p></SPAN></P></TD>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: #ece9d8; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: #ece9d8; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt" vAlign=top>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">√</SPAN><SPAN lang=EN-US style="COLOR: black"><o:p></o:p></SPAN></P></TD>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: #ece9d8; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: #ece9d8; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt" vAlign=top>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">√</SPAN><SPAN lang=EN-US style="COLOR: black"><o:p></o:p></SPAN></P></TD>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: #ece9d8; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: #ece9d8; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt" vAlign=top>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">√</SPAN><SPAN lang=EN-US style="COLOR: black"><o:p></o:p></SPAN></P></TD>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: #ece9d8; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: #ece9d8; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt" vAlign=top>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">×</SPAN><SPAN lang=EN-US style="COLOR: black"><o:p></o:p></SPAN></P></TD></TR>
<TR style="mso-yfti-irow: 3">
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: #ece9d8; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt" vAlign=top>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN lang=EN-US style="COLOR: black">Friendly<o:p></o:p></SPAN></P></TD>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: #ece9d8; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: #ece9d8; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt" vAlign=top>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">√</SPAN><SPAN lang=EN-US style="COLOR: black"><o:p></o:p></SPAN></P></TD>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: #ece9d8; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: #ece9d8; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt" vAlign=top>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">√</SPAN><SPAN lang=EN-US style="COLOR: black"><o:p></o:p></SPAN></P></TD>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: #ece9d8; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: #ece9d8; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt" vAlign=top>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">×</SPAN><SPAN lang=EN-US style="COLOR: black"><o:p></o:p></SPAN></P></TD>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: #ece9d8; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: #ece9d8; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt" vAlign=top>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">×</SPAN><SPAN lang=EN-US style="COLOR: black"><o:p></o:p></SPAN></P></TD></TR>
<TR style="mso-yfti-irow: 4; mso-yfti-lastrow: yes">
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: #ece9d8; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt" vAlign=top>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN lang=EN-US style="COLOR: black">Private<o:p></o:p></SPAN></P></TD>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: #ece9d8; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: #ece9d8; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt" vAlign=top>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">√</SPAN><SPAN lang=EN-US style="COLOR: black"><o:p></o:p></SPAN></P></TD>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: #ece9d8; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: #ece9d8; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt" vAlign=top>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">×</SPAN><SPAN lang=EN-US style="COLOR: black"><o:p></o:p></SPAN></P></TD>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: #ece9d8; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: #ece9d8; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt" vAlign=top>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">×</SPAN><SPAN lang=EN-US style="COLOR: black"><o:p></o:p></SPAN></P></TD>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: #ece9d8; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: #ece9d8; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt" vAlign=top>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">×</SPAN><SPAN lang=EN-US style="COLOR: black"><o:p></o:p></SPAN></P></TD></TR></TBODY></TABLE>
<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'">如下图给出父类和子类的继承关系，绿色部分为父类（其中包括两部分，即对子类不可见①和对子类可见②两部分），绿色加上红色部分③（由子类派生的即子类独有的特性）为子类。说明：①虽然对于子类不可见部分但却是子类必不可少的部分，因为③可能会调用②，而②又可能会调用①，如果子类中没有①，那么程序就会出错。</SPAN><SPAN lang=EN-US><BR><?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" /><v:shapetype id=_x0000_t75 stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"><v:stroke joinstyle="miter"></v:stroke><v:formulas><v:f eqn="if lineDrawn pixelLineWidth 0"></v:f><v:f eqn="sum @0 1 0"></v:f><v:f eqn="sum 0 0 @1"></v:f><v:f eqn="prod @2 1 2"></v:f><v:f eqn="prod @3 21600 pixelWidth"></v:f><v:f eqn="prod @3 21600 pixelHeight"></v:f><v:f eqn="sum @0 0 1"></v:f><v:f eqn="prod @6 1 2"></v:f><v:f eqn="prod @7 21600 pixelWidth"></v:f><v:f eqn="sum @8 21600 0"></v:f><v:f eqn="prod @7 21600 pixelHeight"></v:f><v:f eqn="sum @10 21600 0"></v:f></v:formulas><v:path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></v:path><o:lock aspectratio="t" v:ext="edit"></o:lock></v:shapetype><IMG alt="" hspace=0 src="K:\study\java\吉大面向对象程序设计JAVA1~48\未刻盘吉大面向对象程序设计JAVA(41-48)\子类继承父类关系图.gif" align=baseline border=0><BR></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">解释二：关于隐藏是指子类与父类存在</SPAN><SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 黑体">同名但是有不同解释</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的属性和方法，那么父类中这些属性和方法将会被隐藏。举例，在父类中定义一个属性变量</SPAN><SPAN lang=EN-US>i</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，同时在子类中也定义一个属性变量</SPAN><SPAN lang=EN-US>i</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，此时父类中的属性变量</SPAN><SPAN lang=EN-US>i</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">将被隐藏或者说屏蔽，程序调用属性变量</SPAN><SPAN lang=EN-US>i</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">时则默认是对子类的属性变量</SPAN><SPAN lang=EN-US>i</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的调用，同样方法也是如此。</SPAN></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'">解释三：关于覆盖是指指子类与父类存在</SPAN><SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 黑体">相同头部</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的方法，那么父类中这些的方法将会被覆盖或者说屏蔽。如果程序中需要调用父类中被覆盖的方法则使用</SPAN><SPAN lang=EN-US style="FONT-FAMILY: 'Arial Black'; mso-fareast-font-family: 隶书">s</SPAN><SPAN lang=EN-US style="FONT-SIZE: 12pt; FONT-FAMILY: 'Arial Black'; mso-fareast-font-family: 隶书">uper</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">关键字。</SPAN><SPAN lang=EN-US><BR></SPAN><STRONG><SPAN class=2Char><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 黑体; mso-ascii-font-family: Arial; mso-bidi-font-family: 'Times New Roman'">2、对象代词的意义？</SPAN></SPAN><SPAN class=2Char><SPAN lang=EN-US style="FONT-SIZE: 16pt; mso-bidi-font-family: 'Times New Roman'"><FONT face=Arial>super</FONT></SPAN></SPAN><SPAN class=2Char><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 黑体; mso-ascii-font-family: Arial; mso-bidi-font-family: 'Times New Roman'">和</SPAN></SPAN><SPAN class=2Char><SPAN lang=EN-US style="FONT-SIZE: 16pt; mso-bidi-font-family: 'Times New Roman'"><FONT face=Arial>this</FONT></SPAN></SPAN></STRONG><SPAN lang=EN-US><BR>super</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">：针对隐藏和覆盖来说，大多数情况下我们都是指当前的子类，当我们需要特定</SPAN><SPAN lang=EN-US><BR></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">指明访问父类的时候，则使用</SPAN><SPAN lang=EN-US>super.[</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">属性</SPAN><SPAN lang=EN-US>][</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">方法</SPAN><SPAN lang=EN-US>]<BR>this</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">：既然默认情况是指当前的子类也就是说</SPAN><SPAN lang=EN-US>this.</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">加不加都是一样的，那为什么还要用</SPAN><SPAN lang=EN-US>this</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">这个词呢？这是因为</SPAN><SPAN lang=EN-US>this</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">并不是针对</SPAN><SPAN lang=EN-US>super</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">产生的，而是因为我们在程序中的很多的方法需要返回当前对象，这时候</SPAN><SPAN lang=EN-US>this</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">就有重要的作用。因为在很多对象的内部我们是不能直接提到该对象的名称的，程序是不识别的。比如张三说他自己时用“我”而非“张三”，否则这是不符合常规的。</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN class=2Char><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 黑体; mso-ascii-font-family: Arial; mso-bidi-font-family: 'Times New Roman'"><STRONG>3、重载和覆盖的关系？</STRONG></SPAN></SPAN><SPAN lang=EN-US><BR></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">相同点：两者都是对一个方法的多次实现，或者都体现了多态性（一个内容有多种形式）</SPAN><SPAN lang=EN-US><BR></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">区别：覆盖是指方法头相同时则产生覆盖。如父类和子类有两个方法头完全相同的方法，此时父类的这个方法将被覆盖。</SPAN><SPAN lang=EN-US><BR></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">重载是指方法名相同但是参数不同，注意重载不区分父类和子类，即这两个方法即可以都在父类中也可以都在子类中或者一个在父类中一个在子类中。这样当程序调用方法时是根据其中的参数（个数、类型）进行匹配的。</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN class=2Char><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 黑体; mso-ascii-font-family: Arial; mso-bidi-font-family: 'Times New Roman'"><STRONG>4、接口的作用？</STRONG></SPAN></SPAN><SPAN lang=EN-US><BR></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">接口主要是为了解决多重继承中继承冗余的问题。所谓继承冗余是指如果</SPAN><SPAN lang=EN-US>B</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">继承</SPAN><SPAN lang=EN-US>A</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，</SPAN><SPAN lang=EN-US>C</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">也继承</SPAN><SPAN lang=EN-US>A</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，</SPAN><SPAN lang=EN-US>D</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">继承</SPAN><SPAN lang=EN-US>B</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">同时也继承</SPAN><SPAN lang=EN-US>C</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，那么</SPAN><SPAN lang=EN-US>D</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">中重复出现了</SPAN><SPAN lang=EN-US>A</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的内容（既有来自</SPAN><SPAN lang=EN-US>B</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的也有来自</SPAN><SPAN lang=EN-US>C</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的），这样就产生的继承冗余的问题。接口实际上相当于一个抽象类，但是它和类的最大区别就是它允许实现多个。通过类实现代码复用叫做继承</SPAN><SPAN lang=EN-US>extends</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，通过接口实现代码复用叫做实现</SPAN><SPAN lang=EN-US>implements</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">。可以说接口是变相的实现了多重继承同时又避免的继承冗余，所以对于面向对象的程序设计来说是不可或缺的。关键字</SPAN><SPAN lang=EN-US>interface </SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">继承</SPAN><SPAN lang=EN-US>extends </SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">实现</SPAN><SPAN lang=EN-US>implements</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN class=2Char><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 黑体; mso-ascii-font-family: Arial; mso-bidi-font-family: 'Times New Roman'"><STRONG>5、异常处理的意义？</STRONG></SPAN></SPAN><SPAN lang=EN-US><BR></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">是为了摒弃错误。</SPAN><SPAN lang=EN-US>try</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">监视可能出错的代码，</SPAN><SPAN lang=EN-US>catch</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">处理机制通过异常对象的类型匹配来选择通过哪种机制处理这个错误。意义所在：(</SPAN><SPAN lang=EN-US>1)</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">、解决了程序错误的问题，可以人工干预、提示或者中止程序。(</SPAN><SPAN lang=EN-US>2)</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">、引入了层次的问题，没有异常处理机制时程序遇到错误采用的办法是以</SPAN><SPAN lang=EN-US>return</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">形式层层传递来处理，</SPAN></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'"></SPAN>&nbsp;</P><img src ="http://www.blogjava.net/yesjoy/aggbug/30306.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yesjoy/" target="_blank">★yesjoy★</a> 2006-02-11 22:57 <a href="http://www.blogjava.net/yesjoy/articles/30306.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>