Patrick Room

          The space of JAVA

          常用鏈接

          統(tǒng)計(jì)

          最新評(píng)論

          2008年3月4日 #

          Inner Class

               摘要:   閱讀全文

          posted @ 2008-03-04 20:44 Patrick 閱讀(125) | 評(píng)論 (0)編輯 收藏

          final

          引用自http://www.chinaitpower.com/A200507/2005-07-24/165848.html, 著作權(quán)歸原作者所有

          final在Java中并不常用,然而它卻為我們提供了諸如在C語(yǔ)言中定義常量的功能,不僅如此,final還可以讓你控制你的成員、方法或者是一個(gè)類(lèi)是否可被覆寫(xiě)或繼承等功能,這些特點(diǎn)使final在Java中擁有了一個(gè)不可或缺的地位,也是學(xué)習(xí)Java時(shí)必須要知道和掌握的關(guān)鍵字之一。
          final成員
          當(dāng)你在類(lèi)中定義變量時(shí),在其前面加上final關(guān)鍵字,那便是說(shuō),這個(gè)變量一旦被初始化便不可改變,這里不可改變的意思對(duì)基本類(lèi)型來(lái)說(shuō)是其值不可變,而對(duì)于對(duì)象變量來(lái)說(shuō)其引用不可再變。其初始化可以在兩個(gè)地方,一是其定義處,也就是說(shuō)在final變量定義時(shí)直接給其賦值,二是在構(gòu)造函數(shù)中。這兩個(gè)地方只能選其一,要么在定義時(shí)給值,要么在構(gòu)造函數(shù)中給值,不能同時(shí)既在定義時(shí)給了值,又在構(gòu)造函數(shù)中給另外的值。下面這段代碼演示了這一點(diǎn):
          1. import java.util.List;
          2. import java.util.ArrayList;
          3. import java.util.LinkedList;
          4. public class Bat{
          5.     final PI=3.14;          //在定義時(shí)便給址值
          6.     final int i;            //因?yàn)橐跇?gòu)造函數(shù)中進(jìn)行初始化,所以此處便不可再給值
          7.     final List list;        //此變量也與上面的一樣
          8.     Bat(){
          9.         i=100;
          10.         list=new LinkedList();
          11.     }
          12.     Bat(int ii,List l){
          13.         i=ii;
          14.         list=l;
          15.     }
          16.     public static void main(String[] args){
          17.         Bat b=new Bat();
          18.         b.list.add(new Bat());
          19.         //b.i=25;
          20.         //b.list=new ArrayList();
          21.         System.out.println("I="+b.i+" List Type:"+b.list.getClass());
          22.         b=new Bat(23,new ArrayList());
          23.         b.list.add(new Bat());
          24.         System.out.println("I="+b.i+" List Type:"+b.list.getClass());
          25.     }
          26. }

          此程序很簡(jiǎn)單的演示了final的常規(guī)用法。在這里使用在構(gòu)造函數(shù)中進(jìn)行初始化的方法,這使你有了一點(diǎn)靈活性。如Bat的兩個(gè)重載構(gòu)造函數(shù)所示,第一個(gè)缺省構(gòu)造函數(shù)會(huì)為你提供默認(rèn)的值,重載的那個(gè)構(gòu)造函數(shù)會(huì)根據(jù)你所提供的值或類(lèi)型為final變量初始化。然而有時(shí)你并不需要這種靈活性,你只需要在定義時(shí)便給定其值并永不變化,這時(shí)就不要再用這種方法。在main方法中有兩行語(yǔ)句注釋掉了,如果你去掉注釋?zhuān)绦虮銦o(wú)法通過(guò)編譯,這便是說(shuō),不論是i的值或是list的類(lèi)型,一旦初始化,確實(shí)無(wú)法再更改。然而b可以通過(guò)重新初始化來(lái)指定i的值或list的類(lèi)型,輸出結(jié)果中顯示了這一點(diǎn):
          I=100 List Type:class java.util.LinkedList
          I=23 List Type:class java.util.ArrayList
          還有一種用法是定義方法中的參數(shù)為final,對(duì)于基本類(lèi)型的變量,這樣做并沒(méi)有什么實(shí)際意義,因?yàn)榛绢?lèi)型的變量在調(diào)用方法時(shí)是傳值的,也就是說(shuō)你可以在方法中更改這個(gè)參數(shù)變量而不會(huì)影響到調(diào)用語(yǔ)句,然而對(duì)于對(duì)象變量,卻顯得很實(shí)用,因?yàn)閷?duì)象變量在傳遞時(shí)是傳遞其引用,這樣你在方法中對(duì)對(duì)象變量的修改也會(huì)影響到調(diào)用語(yǔ)句中的對(duì)象變量,當(dāng)你在方法中不需要改變作為參數(shù)的對(duì)象變量時(shí),明確使用final進(jìn)行聲明,會(huì)防止你無(wú)意的修改而影響到調(diào)用方法。
          另外方法中的內(nèi)部類(lèi)在用到方法中的參變量時(shí),此參變也必須聲明為final才可使用,如下代碼所示:
          1. public class INClass{
          2.    void innerClass(final String str){
          3.         class IClass{
          4.             IClass(){
          5.                 System.out.println(str);
          6.             }
          7.         }
          8.         IClass ic=new IClass();
          9.     }
          10.   public static void main(String[] args){
          11.       INClass inc=new INClass();
          12.       inc.innerClass("Hello");
          13.   }
          14. }

          final方法
          將方法聲明為final,那就說(shuō)明你已經(jīng)知道這個(gè)方法提供的功能已經(jīng)滿足你要求,不需要進(jìn)行擴(kuò)展,并且也不允許任何從此類(lèi)繼承的類(lèi)來(lái)覆寫(xiě)這個(gè)方法,但是繼承仍然可以繼承這個(gè)方法,也就是說(shuō)可以直接使用。另外有一種被稱(chēng)為inline的機(jī)制,它會(huì)使你在調(diào)用final方法時(shí),直接將方法主體插入到調(diào)用處,而不是進(jìn)行例行的方法調(diào)用,例如保存斷點(diǎn),壓棧等,這樣可能會(huì)使你的程序效率有所提高,然而當(dāng)你的方法主體非常龐大時(shí),或你在多處調(diào)用此方法,那么你的調(diào)用主體代碼便會(huì)迅速膨脹,可能反而會(huì)影響效率,所以你要慎用final進(jìn)行方法定義。

          final類(lèi)
          當(dāng)你將final用于類(lèi)身上時(shí),你就需要仔細(xì)考慮,因?yàn)橐粋€(gè)final類(lèi)是無(wú)法被任何人繼承的,那也就意味著此類(lèi)在一個(gè)繼承樹(shù)中是一個(gè)葉子類(lèi),并且此類(lèi)的設(shè)計(jì)已被認(rèn)為很完美而不需要進(jìn)行修改或擴(kuò)展。對(duì)于final類(lèi)中的成員,你可以定義其為final,也可以不是final。而對(duì)于方法,由于所屬類(lèi)為final的關(guān)系,自然也就成了final型的。你也可以明確的給final類(lèi)中的方法加上一個(gè)final,但這顯然沒(méi)有意義。
          下面的程序演示了final方法和final類(lèi)的用法:
          1. final class final{
          2.     final String str="final Data";
          3.     public String str1="non final data";
          4.     final public void print(){
          5.         System.out.println("final method.");
          6.     }
          7.     public void what(){
          8.         System.out.println(str+"\n"+str1);
          9.     }
          10. }
          11. public class FinalDemo {   //extends final 無(wú)法繼承 
          12.     public static void main(String[] args){
          13.         final f=new final();
          14.         f.what();
          15.         f.print();
          16.     }
          17. }

          從程序中可以看出,final類(lèi)與普通類(lèi)的使用幾乎沒(méi)有差別,只是它失去了被繼承的特性。final方法與非final方法的區(qū)別也很難從程序行看出,只是記住慎用。
          final在設(shè)計(jì)模式中的應(yīng)用
          在設(shè)計(jì)模式中有一種模式叫做不變模式,在Java中通過(guò)final關(guān)鍵字可以很容易的實(shí)現(xiàn)這個(gè)模式,在講解final成員時(shí)用到的程序Bat.java就是一個(gè)不變模式的例子。如果你對(duì)此感興趣,可以參考閻宏博士編寫(xiě)的《Java與模式》一書(shū)中的講解。

          posted @ 2008-03-04 20:28 Patrick 閱讀(103) | 評(píng)論 (0)編輯 收藏

          Abstract Class & Interface

          本文引用自http://www.cnblogs.com/Mozier/archive/2006/04/08/369851.html

          abstract class和interface是Java語(yǔ)言中對(duì)于抽象類(lèi)定義進(jìn)行支持的兩種機(jī)制,正是由于這兩種機(jī)制的存在,才賦予了Java強(qiáng)大的面向?qū)ο竽芰Αbstract class和interface之間在對(duì)于抽象類(lèi)定義的支持方面具有很大的相似性,甚至可以相互替換,因此很多開(kāi)發(fā)者在進(jìn)行抽象類(lèi)定義時(shí)對(duì)于abstract class和interface的選擇顯得比較隨意。其實(shí),兩者之間還是有很大的區(qū)別的,對(duì)于它們的選擇甚至反映出對(duì)于問(wèn)題領(lǐng)域本質(zhì)的理解、對(duì)于設(shè)計(jì)意圖的理解是否正確、合理。本文將對(duì)它們之間的區(qū)別進(jìn)行一番剖析,試圖給開(kāi)發(fā)者提供一個(gè)在二者之間進(jìn)行選擇的依據(jù)。

          理解抽象類(lèi)

          abstract class和interface在Java語(yǔ)言中都是用來(lái)進(jìn)行抽象類(lèi)(本文中的抽象類(lèi)并非從abstract class翻譯而來(lái),它表示的是一個(gè)抽象體,而abstract class為Java語(yǔ)言中用于定義抽象類(lèi)的一種方法,請(qǐng)讀者注意區(qū)分)定義的,那么什么是抽象類(lèi),使用抽象類(lèi)能為我們帶來(lái)什么好處呢?

          在面向?qū)ο蟮母拍钪校覀冎浪械膶?duì)象都是通過(guò)類(lèi)來(lái)描繪的,但是反過(guò)來(lái)卻不是這樣。并不是所有的類(lèi)都是用來(lái)描繪對(duì)象的,如果一個(gè)類(lèi)中沒(méi)有包含足夠的信息來(lái)描繪一個(gè)具體的對(duì)象,這樣的類(lèi)就是抽象類(lèi)。抽象類(lèi)往往用來(lái)表征我們?cè)趯?duì)問(wèn)題領(lǐng)域進(jìn)行分析、設(shè)計(jì)中得出的抽象概念,是對(duì)一系列看上去不同,但是本質(zhì)上相同的具體概念的抽象。比如:如果我們進(jìn)行一個(gè)圖形編輯軟件的開(kāi)發(fā),就會(huì)發(fā)現(xiàn)問(wèn)題領(lǐng)域存在著圓、三角形這樣一些具體概念,它們是不同的,但是它們又都屬于形狀這樣一個(gè)概念,形狀這個(gè)概念在問(wèn)題領(lǐng)域是不存在的,它就是一個(gè)抽象概念。正是因?yàn)槌橄蟮母拍钤趩?wèn)題領(lǐng)域沒(méi)有對(duì)應(yīng)的具體概念,所以用以表征抽象概念的抽象類(lèi)是不能夠?qū)嵗摹?

          在面向?qū)ο箢I(lǐng)域,抽象類(lèi)主要用來(lái)進(jìn)行類(lèi)型隱藏。我們可以構(gòu)造出一個(gè)固定的一組行為的抽象描述,但是這組行為卻能夠有任意個(gè)可能的具體實(shí)現(xiàn)方式。這個(gè)抽象描述就是抽象類(lèi),而這一組任意個(gè)可能的具體實(shí)現(xiàn)則表現(xiàn)為所有可能的派生類(lèi)。模塊可以操作一個(gè)抽象體。由于模塊依賴于一個(gè)固定的抽象體,因此它可以是不允許修改的;同時(shí),通過(guò)從這個(gè)抽象體派生,也可擴(kuò)展此模塊的行為功能。熟悉OCP的讀者一定知道,為了能夠?qū)崿F(xiàn)面向?qū)ο笤O(shè)計(jì)的一個(gè)最核心的原則OCP(Open-Closed Principle),抽象類(lèi)是其中的關(guān)鍵所在。

          從語(yǔ)法定義層面看abstract class和interface

          在語(yǔ)法層面,Java語(yǔ)言對(duì)于abstract class和interface給出了不同的定義方式,下面以定義一個(gè)名為Demo的抽象類(lèi)為例來(lái)說(shuō)明這種不同。
          使用abstract class的方式定義Demo抽象類(lèi)的方式如下:

          abstract class Demo 
          
          abstract void method1(); 
          
          abstract void method2()
          … 
          }

           

          使用interface的方式定義Demo抽象類(lèi)的方式如下:

          interface Demo { 
          
          void method1(); 
          
          void method2(); 
          …
          } 

           

          在abstract class方式中,Demo可以有自己的數(shù)據(jù)成員,也可以有非abstarct的成員方法,而在interface方式的實(shí)現(xiàn)中,Demo只能夠有靜態(tài)的不能被修改的數(shù)據(jù)成員(也就是必須是static final的,不過(guò)在interface中一般不定義數(shù)據(jù)成員),所有的成員方法都是abstract的。從某種意義上說(shuō),interface是一種特殊形式的abstract class。

          從編程的角度來(lái)看,abstract class和interface都可以用來(lái)實(shí)現(xiàn)"design by contract"的思想。但是在具體的使用上面還是有一些區(qū)別的。

          首先,abstract class在Java語(yǔ)言中表示的是一種繼承關(guān)系,一個(gè)類(lèi)只能使用一次繼承關(guān)系。但是,一個(gè)類(lèi)卻可以實(shí)現(xiàn)多個(gè)interface。也許,這是Java語(yǔ)言的設(shè)計(jì)者在考慮Java對(duì)于多重繼承的支持方面的一種折中考慮吧。

          其次,在abstract class的定義中,我們可以賦予方法的默認(rèn)行為。但是在interface的定義中,方法卻不能擁有默認(rèn)行為,為了繞過(guò)這個(gè)限制,必須使用委托,但是這會(huì) 增加一些復(fù)雜性,有時(shí)會(huì)造成很大的麻煩。

          在抽象類(lèi)中不能定義默認(rèn)行為還存在另一個(gè)比較嚴(yán)重的問(wèn)題,那就是可能會(huì)造成維護(hù)上的麻煩。因?yàn)槿绻髞?lái)想修改類(lèi)的界面(一般通過(guò)abstract class或者interface來(lái)表示)以適應(yīng)新的情況(比如,添加新的方法或者給已用的方法中添加新的參數(shù))時(shí),就會(huì)非常的麻煩,可能要花費(fèi)很多的時(shí)間(對(duì)于派生類(lèi)很多的情況,尤為如此)。但是如果界面是通過(guò)abstract class來(lái)實(shí)現(xiàn)的,那么可能就只需要修改定義在abstract class中的默認(rèn)行為就可以了。

          同樣,如果不能在抽象類(lèi)中定義默認(rèn)行為,就會(huì)導(dǎo)致同樣的方法實(shí)現(xiàn)出現(xiàn)在該抽象類(lèi)的每一個(gè)派生類(lèi)中,違反了"one rule,one place"原則,造成代碼重復(fù),同樣不利于以后的維護(hù)。因此,在abstract class和interface間進(jìn)行選擇時(shí)要非常的小心。

          從設(shè)計(jì)理念層面看abstract class和interface

          上面主要從語(yǔ)法定義和編程的角度論述了abstract class和interface的區(qū)別,這些層面的區(qū)別是比較低層次的、非本質(zhì)的。本小節(jié)將從另一個(gè)層面:abstract class和interface所反映出的設(shè)計(jì)理念,來(lái)分析一下二者的區(qū)別。作者認(rèn)為,從這個(gè)層面進(jìn)行分析才能理解二者概念的本質(zhì)所在。

          前面已經(jīng)提到過(guò),abstarct class在Java語(yǔ)言中體現(xiàn)了一種繼承關(guān)系,要想使得繼承關(guān)系合理,父類(lèi)和派生類(lèi)之間必須存在"is a"關(guān)系,即父類(lèi)和派生類(lèi)在概念本質(zhì)上應(yīng)該是相同的(參考文獻(xiàn)〔3〕中有關(guān)于"is a"關(guān)系的大篇幅深入的論述,有興趣的讀者可以參考)。對(duì)于interface 來(lái)說(shuō)則不然,并不要求interface的實(shí)現(xiàn)者和interface定義在概念本質(zhì)上是一致的,僅僅是實(shí)現(xiàn)了interface定義的契約而已。為了使論述便于理解,下面將通過(guò)一個(gè)簡(jiǎn)單的實(shí)例進(jìn)行說(shuō)明。

          考慮這樣一個(gè)例子,假設(shè)在我們的問(wèn)題領(lǐng)域中有一個(gè)關(guān)于Door的抽象概念,該Door具有執(zhí)行兩個(gè)動(dòng)作open和close,此時(shí)我們可以通過(guò)abstract class或者interface來(lái)定義一個(gè)表示該抽象概念的類(lèi)型,定義方式分別如下所示:

          使用abstract class方式定義Door:

          abstract class Door 
          
          abstract void open(); 
          
          abstract void close(); 
          }

           

          使用interface方式定義Door:

           

          interface Door 
          
          void open(); 
          
          void close(); 
          }

           

          其他具體的Door類(lèi)型可以extends使用abstract class方式定義的Door或者implements使用interface方式定義的Door。看起來(lái)好像使用abstract class和interface沒(méi)有大的區(qū)別。

          如果現(xiàn)在要求Door還要具有報(bào)警的功能。我們?cè)撊绾卧O(shè)計(jì)針對(duì)該例子的類(lèi)結(jié)構(gòu)呢(在本例中,主要是為了展示abstract class和interface反映在設(shè)計(jì)理念上的區(qū)別,其他方面無(wú)關(guān)的問(wèn)題都做了簡(jiǎn)化或者忽略)?下面將羅列出可能的解決方案,并從設(shè)計(jì)理念層面對(duì)這些不同的方案進(jìn)行分析。

          解決方案一:

          簡(jiǎn)單的在Door的定義中增加一個(gè)alarm方法,如下:

           

          abstract class Door 
          
          abstract void open(); 
          
          abstract void close(); 
          
          abstract void alarm(); 
          }

           

          或者

           

          interface Door 
          
          void open(); 
          
          void close(); 
          
          void alarm(); 
          }

           

          那么具有報(bào)警功能的AlarmDoor的定義方式如下:

           

          class AlarmDoor extends Door 
          
          void open() { … } 
          
          void close() { … } 
          
          void alarm() { … } 
          }

           

          或者

           

          class AlarmDoor implements Door {
          
          void open() { … }
          
          void close() { … }
          
          void alarm() { … }
          }
           

           

          這種方法違反了面向?qū)ο笤O(shè)計(jì)中的一個(gè)核心原則ISP(Interface Segregation Priciple),在Door的定義中把Door概念本身固有的行為方法和另外一個(gè)概念"報(bào)警器"的行為方法混在了一起。這樣引起的一個(gè)問(wèn)題是那些僅僅依賴于Door這個(gè)概念的模塊會(huì)因?yàn)?報(bào)警器"這個(gè)概念的改變(比如:修改alarm方法的參數(shù))而改變,反之依然。

          解決方案二:

          既然open、close和alarm屬于兩個(gè)不同的概念,根據(jù)ISP原則應(yīng)該把它們分別定義在代表這兩個(gè)概念的抽象類(lèi)中。定義方式有:這兩個(gè)概念都使用abstract class方式定義;兩個(gè)概念都使用interface方式定義;一個(gè)概念使用abstract class方式定義,另一個(gè)概念使用interface方式定義。

          顯然,由于Java語(yǔ)言不支持多重繼承,所以兩個(gè)概念都使用abstract class方式定義是不可行的。后面兩種方式都是可行的,但是對(duì)于它們的選擇卻反映出對(duì)于問(wèn)題領(lǐng)域中的概念本質(zhì)的理解、對(duì)于設(shè)計(jì)意圖的反映是否正確、合理。我們一一來(lái)分析、說(shuō)明。

          如果兩個(gè)概念都使用interface方式來(lái)定義,那么就反映出兩個(gè)問(wèn)題:1、我們可能沒(méi)有理解清楚問(wèn)題領(lǐng)域,AlarmDoor在概念本質(zhì)上到底是Door還是報(bào)警器?2、如果我們對(duì)于問(wèn)題領(lǐng)域的理解沒(méi)有問(wèn)題,比如:我們通過(guò)對(duì)于問(wèn)題領(lǐng)域的分析發(fā)現(xiàn)AlarmDoor在概念本質(zhì)上和Door是一致的,那么我們?cè)趯?shí)現(xiàn)時(shí)就沒(méi)有能夠正確的揭示我們的設(shè)計(jì)意圖,因?yàn)樵谶@兩個(gè)概念的定義上(均使用interface方式定義)反映不出上述含義。

          如果我們對(duì)于問(wèn)題領(lǐng)域的理解是:AlarmDoor在概念本質(zhì)上是Door,同時(shí)它有具有報(bào)警的功能。我們?cè)撊绾蝸?lái)設(shè)計(jì)、實(shí)現(xiàn)來(lái)明確的反映出我們的意思呢?前面已經(jīng)說(shuō)過(guò),abstract class在Java語(yǔ)言中表示一種繼承關(guān)系,而繼承關(guān)系在本質(zhì)上是"is a"關(guān)系。所以對(duì)于Door這個(gè)概念,我們應(yīng)該使用abstarct class方式來(lái)定義。另外,AlarmDoor又具有報(bào)警功能,說(shuō)明它又能夠完成報(bào)警概念中定義的行為,所以報(bào)警概念可以通過(guò)interface方式定義。如下所示:

           

          abstract class Door {
          
          abstract void open();
          
          abstract void close();
          }

          
          interface Alarm {
          
          void alarm();
          }

          
          class AlarmDoor extends Door implements Alarm {
          
          void open() { … }
          
          void close() { … }
          
          void alarm() { … }
          }

           

          這種實(shí)現(xiàn)方式基本上能夠明確的反映出我們對(duì)于問(wèn)題領(lǐng)域的理解,正確的揭示我們的設(shè)計(jì)意圖。其實(shí)abstract class表示的是"is a"關(guān)系,interface表示的是"like a"關(guān)系,大家在選擇時(shí)可以作為一個(gè)依據(jù),當(dāng)然這是建立在對(duì)問(wèn)題領(lǐng)域的理解上的,比如:如果我們認(rèn)為AlarmDoor在概念本質(zhì)上是報(bào)警器,同時(shí)又具有Door的功能,那么上述的定義方式就要反過(guò)來(lái)了。

          結(jié)論

          abstract class和interface是Java語(yǔ)言中的兩種定義抽象類(lèi)的方式,它們之間有很大的相似性。但是對(duì)于它們的選擇卻又往往反映出對(duì)于問(wèn)題領(lǐng)域中的概念本質(zhì)的理解、對(duì)于設(shè)計(jì)意圖的反映是否正確、合理,因?yàn)樗鼈儽憩F(xiàn)了概念間的不同的關(guān)系(雖然都能夠?qū)崿F(xiàn)需求的功能)。這其實(shí)也是語(yǔ)言的一種的慣用法,希望讀者朋友能夠細(xì)細(xì)體會(huì)。

          posted @ 2008-03-04 20:09 Patrick 閱讀(116) | 評(píng)論 (0)編輯 收藏

          僅列出標(biāo)題  
          主站蜘蛛池模板: 大余县| 武川县| 寿光市| 鱼台县| 新乡市| 安康市| 四子王旗| 贵阳市| 前郭尔| 繁峙县| 高淳县| 海门市| 新野县| 巴马| 前郭尔| 库车县| 阿拉尔市| 缙云县| 城市| 聂拉木县| 资中县| 上饶市| 弋阳县| 缙云县| 马龙县| 莆田市| 馆陶县| 平度市| 遂川县| 米易县| 阳曲县| 文山县| 沁源县| 祁阳县| 潍坊市| 高雄县| 晋州市| 绥芬河市| 凌云县| 思南县| 客服|