posts - 12,  comments - 0,  trackbacks - 0
            2007年11月28日
          方法調(diào)用的綁定:
          將方法的調(diào)用連到方法本身被稱為“綁定”。當綁定發(fā)生在程序運行之前時,被稱作“前綁定”。
          后綁定也稱為“動態(tài)綁定”或“運行時綁定”,指程序運行的時候,根據(jù)對象的類型來決定該綁定哪個方法。如果語言實現(xiàn)了后綁定,那它就必須要有能在運行時判斷對象類型,并且調(diào)用其合適方法的機制。也就是說編譯器還是不知道對象的類型,但是方法的調(diào)用機制會找出,并且調(diào)用正確的方法。
          除了static和final方法(private方法隱含有final的意思),java的所有的方法都采用后綁定。也就是說,通常情況下你不必考慮是不是應(yīng)該采用后綁定--它是自動的。 為什么要聲明final方法,上一章指出,這樣可以禁止別人覆寫這個方法,不過更重要的可能還是要“關(guān)閉”它的動態(tài)綁定,或者理確切的說,告訴編譯器這里不需要使用后綁定。
          shape為circle的基類,下面這句就是在“上傳”:
          Shape s = new Circle();
          這里先創(chuàng)建了一個Circle對象,接著馬上把它的引用賦給了Shape,看上去這像是一個錯誤(一種類型怎么能賦給另一種);但是由于Circle是由Shape派生出來的,Circle就是一種Shape,因此這種做法是非常正確的。假設(shè)你調(diào)用了一個基類的方法:s.draw();這里派生類里已經(jīng)覆寫了此方法,那么可能你會認為,這次應(yīng)該總調(diào)用Shape的draw()了吧,因為畢竟這是Shape的引用,但是由于實現(xiàn)了后綁定(多態(tài)性),實際上它會調(diào)用Circle.draw().
          posted @ 2008-01-05 19:18 仰望者 閱讀(220) | 評論 (0)編輯 收藏
          1、 float f=1.3;
              是不對的,編譯時會出錯,java認為1.3是double型的,所以定義時應(yīng)寫成:float f=1.3f,或float f= (float)1.3;
          2、 byte b = 3;  b=b*3;
              是不對的,原因是在*運算過程中,java會做類型的提升,將b提升為int型,所以應(yīng)改為:b=(byte)(b*3);
          3、 while(1),if(1)
              是不對的,原因是java中布爾型只有true 和false兩個值,這里與C語言不同,只能用while(true)..
          4、 數(shù)組聲明:int num[3];
              這是不對的,java中聲明數(shù)組時不應(yīng)對空間限定,正確的語法應(yīng)是:
              int[] num = new int[3];
              或
              int[] num;
              num = new int[3];
          5、數(shù)組初始化:int[] num;
                         num {1,3,4,4};
             是不對的,應(yīng)在定義的時候初始化。如:int[] num={1,3,4,4};
          6、int[] num3 =new int[]{1,2,3};
             int[] num5 =new int[3]{1,2,3};
             int[] num3 =new int[]{1,2,3};是對的。
              int[] num5 =new int[3]{1,2,3};是錯的。已經(jīng)初始化的數(shù)組,不應(yīng)再列明:[3]
                 


          posted @ 2007-12-23 23:01 仰望者 閱讀(163) | 評論 (0)編輯 收藏
          合成與繼承
          繼承:
          super關(guān)鍵字的使用:super使用在派生類中,如果派生類中重寫了基類的方法,但在這個被重寫的方法中仍然要調(diào)用基類的同名的方法,這就要用到super關(guān)鍵字,特別是在創(chuàng)建對象時,在帶參數(shù)構(gòu)造函數(shù)中調(diào)用基類構(gòu)造函數(shù)的情況。
          如:
          class Cleanser {
            private String s = new String("Cleanser");
            public void append(String a) { s += a; }
            public void dilute() { append(" dilute()"); }
            public void apply() { append(" apply()"); }
            public void scrub() { append(" scrub()"); }
            public void print() { System.out.println(s); }
            public static void main(String[] args) {
              Cleanser x = new Cleanser();
              x.dilute(); x.apply(); x.scrub();
              x.print();
            }
          }
          public class Detergent extends Cleanser {
            // Change a method:
            public void scrub() {
              append(" Detergent.scrub()");
              super.scrub(); // Call base-class version
            }
          // Add methods to the interface:
            public void foam() { append(" foam()"); }
            // Test the new class:
            public static void main(String[] args) {
              Detergent x = new Detergent();
              x.dilute();
              x.apply();
              x.scrub();
              x.foam();
              x.print();
              System.out.println("Testing base class:");
              Cleanser.main(args);
            }
          } ///:~
          可以看到基類Cleanser 中定義了scrub方法,但派生類Detergent 中對scrub方法進行了修改,并用在派生類Detergent 的scrub方法中,要調(diào)用基本的scrub方法,那么用super.scrub(); 

           基類的初始化:
                   當你創(chuàng)建一個派生類的對象的時候,這個對象里面還有一個基類的子對象,這個子對象同基類自己創(chuàng)建的對象沒什么兩樣,只是從外面看來,這個子對象被包裹在派生類的對象里面。
                   基類子對象的正確初始化是非常重要的,而且只有一個辦法能保證這一點:調(diào)用基類的構(gòu)造函數(shù)來進行初始化,因為只有它才能掌握怎么樣才能正確地進行初始化的信息和權(quán)限。java會讓派生類的構(gòu)造函數(shù)自動地調(diào)用基類的構(gòu)造函數(shù)。
                    示例:
           class Art {
            Art() {
              System.out.println("Art constructor");
            }
          }

          class Drawing extends Art {
            Drawing() {
              System.out.println("Drawing constructor");
            }
          }

          public class Cartoon extends Drawing {
            Cartoon() {
              System.out.println("Cartoon constructor");
            }
            public static void main(String[] args) {
              Cartoon x = new Cartoon();
            }
          } ///:~
          輸出結(jié)果為:
          Art constructor
          Drawing constructor
          Cartoon constructor
          一看結(jié)果便一目了然了。

          上面的示例是不帶任何參數(shù)的情況,如果構(gòu)造函數(shù)中帶有參數(shù)的話,那這里又要用到super的特性了。與上面super的使用涵意一樣,super在這里用作:派生的帶參數(shù)構(gòu)造函數(shù)中調(diào)用基類的帶參構(gòu)造函數(shù),只是這里不象上面那樣super.scrub();這里只使用super(i);即可。
                  
          class Game {
            Game(int i) {
              System.out.println("Game constructor");
            }
          }

          class BoardGame extends Game {
            BoardGame(int i) {
              super(i);
              System.out.println("BoardGame constructor");
            }
          }

          public class Chess extends BoardGame {
            Chess() {
              super(11);
              System.out.println("Chess constructor");
            }
            public static void main(String[] args) {
              Chess x = new Chess();
            }
          } ///:~
          輸出結(jié)果是:
          Game constructor
          BoardGame constructor
          Chess constructor

          合成和繼承一起使用,實現(xiàn)類的復(fù)用:

          class Plate {
            Plate(int i) {
              System.out.println("Plate constructor");
            }
          }

          class DinnerPlate extends Plate {
            DinnerPlate(int i) {
              super(i);
              System.out.println(
                "DinnerPlate constructor");
            }
          }

          class Utensil {
            Utensil(int i) {
              System.out.println("Utensil constructor");
            }
          }

          class Spoon extends Utensil {
            Spoon(int i) {
              super(i);
              System.out.println("Spoon constructor");
            }
          }

          class Fork extends Utensil {
            Fork(int i) {
              super(i);
              System.out.println("Fork constructor");
            }
          }

          class Knife extends Utensil {
            Knife(int i) {
              super(i);
              System.out.println("Knife constructor");
            }
          }

          // A cultural way of doing something:
          class Custom {
            Custom(int i) {
              System.out.println("Custom constructor");
            }
          }

          public class PlaceSetting extends Custom {
            Spoon sp;
            Fork frk;
            Knife kn;
            DinnerPlate pl;
            PlaceSetting(int i) {//把初始化工作都放在構(gòu)造函數(shù)中
              super(i + 1);
              sp = new Spoon(i + 2);
              frk = new Fork(i + 3);
              kn = new Knife(i + 4);
              pl = new DinnerPlate(i + 5);
              System.out.println(
                "PlaceSetting constructor");
            }
            public static void main(String[] args) {
              PlaceSetting x = new PlaceSetting(9);
            }
          } ///:~
                  盡管編譯器會強迫我們對基礎(chǔ)類進行初始化,并要求我們在構(gòu)建器最開頭做這一工作,但它并不會監(jiān)視我們是否正確初始化了成員對象。所以對此必須特別加以留意。
          FINAL關(guān)鍵字:
                  FINAL關(guān)鍵字指“那樣東西是不允許改動”,你可能會出于兩點考慮不想讓別人作改動:設(shè)計和效率。由于這兩個原因差別很大,所以很可能會誤用final關(guān)鍵字。
          final的三種用途:數(shù)據(jù)(Data)、方法(method)、類(class)。
           很多語言通知編譯器:“這段常量(constant)數(shù)據(jù)”的手段。常量能用下列兩種情況出現(xiàn):
                  1、可以是“編譯時的常量”,這樣以后就不能改了;
                  2、也可以是運行時初始化的值,這個值以后就不想再改了。
                  如果是編譯時的常量,編譯器會把常量放到算式里面;這樣編譯的時候就能進行計算,因此也就降低了運行時的開銷。在Java 中這種常量必須是primitive 型的,而且要用final 關(guān)鍵詞表示。這種常量的賦值必須在定義的時候進行。
                  一個既是static 又是final 的數(shù)據(jù)成員會只占據(jù)一段內(nèi)存,并且不可修改。
                  當final 不是指primitive,而是用于對象的reference 的時候,意思就有點不一樣了。對primitive 來說,final 會將這個值定義成常量,但是對于對象的reference 而言,final 的意思則是這個reference 是常量。初始化的時候,一旦將reference 連到了某個對象,那么它就再也不能指別的對象了。但是這個對象本身是可以修改的;Java 沒有提供將某個對象作成常量的方法。
                  (但是你可以自己寫一個類,這樣就能把類當做常量了)
                  這種局限性也體現(xiàn)在數(shù)組上,因為它也是一個對象。
          注意,通常約定,被初始化為常量值的final static 的primitive 的名字全都用大寫,詞與詞之間用下
          劃線分開,如VAL_ONE
          Final 方法
          使用final 方法的目的有二:
                  第一,為方法上“鎖”,禁止派生類進行修改。這是出于設(shè)計考慮。當你希望某個方法的功能,能在繼承過程中被保留下來,并且不被覆寫,就可以使用這個方法。
                  第二個原因就是效率。如果方法是final 的,那么編譯器就會把調(diào)用轉(zhuǎn)換成“內(nèi)聯(lián)的(inline)”。它會用方法本身的拷貝來代替方法的調(diào)用
          final 和private
                  private 方法都隱含有final 的意思。由于你不能訪問private 的方法,因此你也不能覆寫它。你可以給private 方法加一個final 修飾符,但是這樣做什么意義也沒有。
                  這個問題有可能會造成混亂,因為即使你覆寫了一個private 方法(它隱含有final 的意思),看上去它還是可以運行的,而且編譯器也不會報錯:
                  class WithFinals {
                      // Identical to "private" alone:
                      private final void f() {
                              System.out.println("WithFinals.f()");
                                                    }
                      / / Also automatically "final":
                     private void g() {
                              System.out.println("WithFinals.g()");
                                           }
                  }
                  class OverridingPrivate extends WithFinals {
                          private final void f() {
                                  System.out.println("OverridingPrivate.f()");
                                                            }
                          private void g() {
                                  System.out.println("OverridingPrivate.g()");
                                                            }
                   }
          只有是基類接口里的東西才能被“覆寫”,如果方法是private 的,那它就不屬于基類的接口。它只能算是被類隱藏起來的,正好有著相同的名字的代碼。如果你在派生類里創(chuàng)建了同名的public 或protected,或package 權(quán)限的方法,那么它們同基類中可能同名的方法,沒有任何聯(lián)系。你并沒有覆寫那個方法,你只是創(chuàng)建了一個新的方法。由于private 方法是無法訪問的,實際上是看不見的,因此這么作除了會影響類的代碼結(jié)構(gòu),其它什么意義都沒有。
          Final 類
          把整個類都定義成final 的(把final 關(guān)鍵詞放到類的定義部分的前面)就等于在宣布,你不會去繼承這個類,你也不允許別人去繼承這個類。換言之,出于類的設(shè)計考慮,它再也不需要作修改了,或者從安全角度出發(fā),你不希望它再生出子類。
          final class Dinosaur{}
          注意,final 類的數(shù)據(jù)可以是final 的,也可以不是final 的,這要由你來決定。無論類是不是final 的,這一條都適用于“將final 用于數(shù)據(jù)的”場合。但是,由于final 類禁止了繼承,覆寫方法已經(jīng)不可能了,因
          此所有的方法都隱含地變成final 了。你可以為final 類的方法加一個final 修飾符,但是這一樣沒什么意義。
          posted @ 2007-12-20 17:33 仰望者 閱讀(240) | 評論 (0)編輯 收藏
          訪問控制符:public 、private、protected、friendly
          public包內(nèi)包外均可訪問。
          private只有本類可訪問。
          protected針對繼承而使用的:1、包內(nèi)繼承,因為在包內(nèi),聲明為protected不影響它本來的friendly權(quán)限。
                                     2、包外繼承,必須聲明為protected。
          派生類可以訪問基類的protected成員。
          注意不可將類設(shè)成private(那樣會使除類之外的其他東西都不能訪問它),也不能設(shè)成protected。因此,我們現(xiàn)在對于類的訪問只有兩個選擇:“友好的”或者public。若不愿其他任何人訪問那個類,可將所有構(gòu)建器設(shè)為private,這樣除你之外,沒有可以用類創(chuàng)建的了。而你可以使用static成員創(chuàng)建對象。
          package com.access.external;

          class Soup{
              private Soup(){//構(gòu)造函數(shù)聲明為private,其它類不能用此構(gòu)造函數(shù)創(chuàng)建對象;
                  System.out.println("sffewe");
              }
              public static Soup makSoup(){//其它類可通過makSoup來創(chuàng)建對象;
                  return new Soup();
              }
              private static Soup ps1 = new Soup();//自己創(chuàng)建對象;
              public static Soup access(){//返回對象的引用。
                  return ps1;
              }
              public void f(){}
          }

          class Sandwich{
              void f(){
                  new Lunch();
              }
          }

          public class Lunch {
              void test(){
                  //Soup priv1 = new Soup();
                  Soup priv2 = Soup.makSoup();
                  Sandwich f1 = new Sandwich();
                  Soup.access().f();//不創(chuàng)建對象,但通過Soup中返回的對象引用調(diào)用其方法。
              }

          }


          該方法返回一個句柄,它指向類Soup的一個對象。
          Soup類向我們展示出如何通過將所有構(gòu)建器都設(shè)為private,從而防止直接創(chuàng)建一個類。請記住,假若不明確地至少創(chuàng)建一個構(gòu)建器,就會自動創(chuàng)建默認構(gòu)建器(沒有自變量)。若自己編寫默認構(gòu)建器,它就不會自動創(chuàng)建。把它變成private后,就沒人能為那個類創(chuàng)建一個對象。但別人怎樣使用這個類呢?上面的例子為我們揭示出了兩個選擇。第一個選擇,我們可創(chuàng)建一個static方法,再通過它創(chuàng)建一個新的Soup,然后返回指向它的一個句柄。如果想在返回之前對Soup進行一些額外的操作,或者想了解準備創(chuàng)建多少個Soup對象(可能是為了限制它們的個數(shù)),這種方案無疑是特別有用的。
          第二個選擇是采用“設(shè)計方案”(Design Pattern)技術(shù),本書后面會對此進行詳細介紹。通常方案叫作“獨子”,因為它僅允許創(chuàng)建一個對象。類Soup的對象被創(chuàng)建成Soup的一個static private成員,所以有一個而且只能有一個。除非通過public方法access(),否則根本無法訪問它。



          posted @ 2007-12-20 11:09 仰望者 閱讀(249) | 評論 (0)編輯 收藏
          Eclipse提供了很好的工具:
          1、實時運算薄頁面(java scrapbook page)具體的說就是一小段代碼,比如一個for循環(huán),就可以在里面執(zhí)行,無須寫出main函數(shù)等。
          操作如下:new->other->java->java run/debug->scrapbook page
          創(chuàng)建頁面后,輸入代碼:
          for (int i = 0; i < 10; i++) {
           System.out.println(Integer.toString(i));
          }
          選擇代碼,右鍵excute即可看到結(jié)果。。很方便。。。。。

          2、程序代碼產(chǎn)生模板
          window->prefrences->java->editor->Templates
              添加:name:Sys
                          context:java
                          Description:shortcut for System.out.println
                          pattern:System.out.println(${cursor});
          確定后,在程序中輸入s或Sys時再按alt+/會提示語句。。。接著按enter鍵吧。。。


          3、產(chǎn)生 getter 與 setter Java 編輯器可以為編譯單元內(nèi)的類型字段,產(chǎn)生存取元(accessors,也就是getter和setter的method)。 I. 「Source」→「Generate Getter and Setter...」 (或是在Java編輯器按右鍵,「Source」→「Generate Getter and Setter...」)
          挑選哪些需要建立getter和setter的method ;
          選擇method要建立的地方 ;
          排序的方式;
          選擇Access modifier ;
          選擇是否需要建立批注;
          按OK;

          4、建立新的 JAR 檔案 如果要在工作臺中建立新 JAR 檔,請執(zhí)行下列動作: I. 在「Package Explorer」中,可以選擇性地預(yù)選一或多個要匯出的 Java 元素。(在步驟IV中,這些會在JAR Package Specification精靈頁面中自動選出。) II. 從快速菜單或從菜單列的File菜單,選取Export。 III. 選取JAR file,然后按一下Next。
          IV. 在JAR Package Specification頁面的Select the resources to export字段中,選取要匯出的資源。 V. 選取適當?shù)墓催x框,以指出想Export generated class files and resourcess或Export java source files and resources。附注:這兩種情況皆會匯出所選的資源。 VI. 在Select the export destination字段中,輸入或按一下Browse以選取 JAR 文件的位置。 VII. 選取或清除Compress the contents of the JAR file勾選框。 VIII. 選取或清除Overwrite existing files without warning勾選框。如果清除這個勾選框,則會提示確認是否要更換每一個將被改寫的檔案。 IX. 附注:在撰寫 JAR 檔、JAR 說明與 Manifest 檔時,會套用改寫選項。 X. 有兩項選擇: ?? 按一下Finish來立即建立 JAR 檔。 ?? 按一下Next,使用「JAR 套裝選項」頁面,以設(shè)定進階選項,建立 JAR 說明,或變更預(yù)設(shè) manifest。
          posted @ 2007-12-18 15:53 仰望者 閱讀(181) | 評論 (0)編輯 收藏
               摘要: 菜單 功能 熱鍵 說明 Edit Add Block Comment Ctrl+Shift+/ Editing in Structured Text Editors ...  閱讀全文
          posted @ 2007-12-18 15:36 仰望者 閱讀(318) | 評論 (0)編輯 收藏

          JDK SRC中注解:

          基于哈希表的 Map 接口的實現(xiàn)。此實現(xiàn)提供所有可選的映射操作,并允許使用 null 值和 null 鍵。(除了不同步和允許使用 null 之外,HashMap 類與 Hashtable 大致相同。)此類不保證映射的順序,特別是它不保證該順序恒久不變。

          此實現(xiàn)假定哈希函數(shù)將元素正確分布在各桶之間,可為基本操作(getput)提供穩(wěn)定的性能。迭代集合視圖所需的時間與 HashMap 實例的“容量”(桶的數(shù)量)及其大小(鍵-值映射關(guān)系數(shù))的和成比例。所以,如果迭代性能很重要,則不要將初始容量設(shè)置得太高(或?qū)⒓虞d因子設(shè)置得太低)。

          HashMap 的實例有兩個參數(shù)影響其性能:初始容量加載因子。容量 是哈希表中桶的數(shù)量,初始容量只是哈希表在創(chuàng)建時的容量。加載因子 是哈希表在其容量自動增加之前可以達到多滿的一種尺度。當哈希表中的條目數(shù)超出了加載因子與當前容量的乘積時,通過調(diào)用 rehash 方法將容量翻倍。

          通常,默認加載因子 (.75) 在時間和空間成本上尋求一種折衷。加載因子過高雖然減少了空間開銷,但同時也增加了查詢成本(在大多數(shù) HashMap 類的操作中,包括 getput 操作,都反映了這一點)。在設(shè)置初始容量時應(yīng)該考慮到映射中所需的條目數(shù)及其加載因子,以便最大限度地降低 rehash 操作次數(shù)。如果初始容量大于最大條目數(shù)除以加載因子,則不會發(fā)生 rehash 操作。

          如果很多映射關(guān)系要存儲在 HashMap 實例中,則相對于按需執(zhí)行自動的 rehash 操作以增大表的容量來說,使用足夠大的初始容量創(chuàng)建它將使得映射關(guān)系能更有效地存儲。

          注意,此實現(xiàn)不是同步的。如果多個線程同時訪問此映射,而其中至少一個線程從結(jié)構(gòu)上修改了該映射,則它必須 保持外部同步。(結(jié)構(gòu)上的修改是指添加或刪除一個或多個映射關(guān)系的操作;僅改變與實例已經(jīng)包含的鍵關(guān)聯(lián)的值不是結(jié)構(gòu)上的修改。)這一般通過對自然封裝該映射的對象進行同步操作來完成。如果不存在這樣的對象,則應(yīng)該使用 Collections.synchronizedMap 方法來“包裝”該映射。最好在創(chuàng)建時完成這一操作,以防止對映射進行意外的不同步訪問,如下所示:

           Map m = Collections.synchronizedMap(new HashMap(...));

          由所有此類的“集合視圖方法”所返回的迭代器都是快速失敗 的:在迭代器創(chuàng)建之后,如果從結(jié)構(gòu)上對映射進行修改,除非通過迭代器自身的 removeadd 方法,其他任何時間任何方式的修改,迭代器都將拋出 ConcurrentModificationException。因此,面對并發(fā)的修改,迭代器很快就會完全失敗,而不冒在將來不確定的時間任意發(fā)生不確定行為的風險。

          注意,迭代器的快速失敗行為不能得到保證,一般來說,存在不同步的并發(fā)修改時,不可能作出任何堅決的保證。快速失敗迭代器盡最大努力拋出 ConcurrentModificationException。因此,編寫依賴于此異常程序的方式是錯誤的,正確做法是:迭代器的快速失敗行為應(yīng)該僅用于檢測程序錯誤。


          Hashtable和HashMap的區(qū)別:

          1.Hashtable是Dictionary的子類,HashMap是Map接口的一個實現(xiàn)類;
          2.Hashtable 中的方法是同步的,而HashMap中的方法在缺省情況下是非同步的。即是說,在多線程應(yīng)用程序中,不用專門的操作就安全地可以使用Hashtable 了;而對于HashMap,則需要額外的同步機制。但HashMap的同步問題可通過Collections的一個靜態(tài)方法得到解決:
          Map Collections.synchronizedMap(Map m)
          這個方法返回一個同步的Map,這個Map封裝了底層的HashMap的所有方法,使得底層的HashMap即使是在多線程的環(huán)境中也是安全的。
          3. 在HashMap中,null可以作為鍵,這樣的鍵只有一個;可以有一個或多個鍵所對應(yīng)的值為null。當get()方法返回null值時,即可以表示 HashMap中沒有該鍵,也可以表示該鍵所對應(yīng)的值為null。因此,在HashMap中不能由get()方法來判斷HashMap中是否存在某個鍵, 而應(yīng)該用containsKey()方法來判斷。
          posted @ 2007-12-14 12:06 仰望者 閱讀(439) | 評論 (0)編輯 收藏
                    MVC模式是"Model-View-Controller"的縮寫,中文翻譯為"模式-視圖-控制器"。MVC應(yīng)用程序總是由這三個部分組成。Event(事件)導致Controller改變Model或View,或者同時改變兩者。只要Controller改變了Models的數(shù)據(jù)或者屬性,所有依賴的View都會自動更新。似的,只要Controller改變了View,View會從潛在的Model中獲取數(shù)據(jù)來刷新自己。MVC模式最早是smalltalk語言研究團提出的,應(yīng)用于用戶交互應(yīng)用程序中。smalltalk語言和java語言有很多相似性,都是面向?qū)ο笳Z言,很自然的SUN在petstore(寵物店)事例應(yīng)用程序中就推薦MVC模式作為開發(fā)Web應(yīng)用的架構(gòu)模式。MVC模式是一種架構(gòu)模式,其實需要其他模式協(xié)作完成。J2EE模式目錄中,通常采用service to worker模式實現(xiàn),而service to worker模式可由集中控制器模式,派遣器模式和Page Helper模式組成。Struts只實現(xiàn)了MVC的View和Controller兩個部分,Model部分需要開發(fā)者自己來實現(xiàn),Struts提供了抽象類Action使開發(fā)者能將Model應(yīng)用于Struts框架。

                MVC模式是一個復(fù)雜的架構(gòu)模式,其實現(xiàn)也顯得非常復(fù)雜。但是,我們已經(jīng)終結(jié)出了很多可靠的設(shè)計模式,多種設(shè)計模式結(jié)合在一起,使MVC模式的實現(xiàn)變得相對簡單易行。Views可以看作一棵樹,顯然可以用Composite Pattern來實現(xiàn)。Views和Models之間的關(guān)系可以用Observer Pattern體現(xiàn)。Controller控制Views的顯示,可以用Strategy Pattern實現(xiàn)。Model通常是一個調(diào)停者,可采用Mediator Pattern來實現(xiàn)。

                現(xiàn)在讓我們來了解一下MVC三個部分在J2EE架構(gòu)中處于什么位置,這樣有助于我們理解MVC模式的實現(xiàn)。MVC與J2EE架構(gòu)的對應(yīng)關(guān)系是:View處于Web Tier或者說是Client Tier,通常是JSP/Servlet,即頁面顯示部分。Controller也處于Web Tier,通常用Servlet來實現(xiàn),即頁面顯示的邏輯部分實現(xiàn)。Model處于Middle Tier,通常用服務(wù)端的javaBean或者EJB實現(xiàn),即業(yè)務(wù)邏輯部分的實現(xiàn)。(Enterprise Bean 與 JavaBean 不同。JavaBean 是使用 java.beans 包開發(fā)的,它是 Java 2 標準版的一部分。JavaBean 是一臺機器上同一個地址空間中運行的組件。JavaBean 是進程內(nèi)組件。Enterprise Bean 是使用 javax.ejb 包開發(fā)的,它是標準 JDK 的擴展,是 Java 2 Enterprise Edition 的一部分。Enterprise Bean 是在多臺機器上跨幾個地址空間運行的組件。因此 Enterprise Bean 是進程間組件。JavaBean 通常用作 GUI 窗口小部件,而 Enterprise Bean 則用作分布式商業(yè)對象.
                

          一、MVC設(shè)計思想

            MVC英文即Model-View-Controller,即把一個應(yīng)用的輸入、處理、輸出流程按照Model、View、Controller的方式進行分離,這樣一個應(yīng)用被分成三個層——模型層、視圖層、控制層。

            視圖(View)代表用戶交互界面,對于Web應(yīng)用來說,可以概括為HTML界面,但有可能為XHTML、XMLApplet。隨著應(yīng)用的復(fù)雜性和規(guī)模性,界面的處理也變得具有挑戰(zhàn)性。一個應(yīng)用可能有很多不同的視圖,MVC設(shè)計模式對于視圖的處理僅限于視圖上數(shù)據(jù)的采集和處理,以及用戶的請求,而不包括在視圖上的業(yè)務(wù)流程的處理。業(yè)務(wù)流程的處理交予模型(Model)處理。比如一個訂單的視圖只接受來自模型的數(shù)據(jù)并顯示給用戶,以及將用戶界面的輸入數(shù)據(jù)和請求傳遞給控制和模型。

            模型(Model):就是業(yè)務(wù)流程/狀態(tài)的處理以及業(yè)務(wù)規(guī)則的制定。業(yè)務(wù)流程的處理過程對其它層來說是黑箱操作,模型接受視圖請求的數(shù)據(jù),并返回最終的處理結(jié)果。業(yè)務(wù)模型的設(shè)計可以說是MVC最主要的核心。目前流行的EJB模型就是一個典型的應(yīng)用例子,它從應(yīng)用技術(shù)實現(xiàn)的角度對模型做了進一步的劃分,以便充分利用現(xiàn)有的組件,但它不能作為應(yīng)用設(shè)計模型的框架。它僅僅告訴你按這種模型設(shè)計就可以利用某些技術(shù)組件,從而減少了技術(shù)上的困難。對一個開發(fā)者來說,就可以專注于業(yè)務(wù)模型的設(shè)計。MVC設(shè)計模式告訴我們,把應(yīng)用的模型按一定的規(guī)則抽取出來,抽取的層次很重要,這也是判斷開發(fā)人員是否優(yōu)秀的設(shè)計依據(jù)。抽象與具體不能隔得太遠,也不能太近。MVC并沒有提供模型的設(shè)計方法,而只告訴你應(yīng)該組織管理這些模型,以便于模型的重構(gòu)和提高重用性。我們可以用對象編程來做比喻,MVC定義了一個頂級類,告訴它的子類你只能做這些,但沒法限制你能做這些。這點對編程的開發(fā)人員非常重要。

            業(yè)務(wù)模型還有一個很重要的模型那就是數(shù)據(jù)模型。數(shù)據(jù)模型主要指實體對象的數(shù)據(jù) 保存(持續(xù)化)。比如將一張訂單保存到數(shù)據(jù)庫,從數(shù)據(jù)庫獲取訂單。我們可以將這個模型單獨列出,所有有關(guān)數(shù)據(jù)庫的操作只限制在該模型中。

            控制(Controller)可以理解為從用戶接收請求, 將模型與視圖匹配在一起,共同完成用戶的請求。劃分控制層的作用也很明顯,它清楚地告訴你,它就是一個分發(fā)器,選擇什么樣的模型,選擇什么樣的視圖,可以完成什么樣的用戶請求。控制層并不做任何的數(shù)據(jù)處理。例如,用戶點擊一個連接,控制層接受請求后, 并不處理業(yè)務(wù)信息,它只把用戶的信息傳遞給模型,告訴模型做什么,選擇符合要求的視圖返回給用戶。因此,一個模型可能對應(yīng)多個視圖,一個視圖可能對應(yīng)多個模型。模型、視圖與控制器的分離,使得一個模型可以具有多個顯示視圖。如果用戶通過某個視圖的控制器改變了模型的數(shù)據(jù),所有其它依賴于這些數(shù)據(jù)的視圖都應(yīng)反映到這些變化。因此,無論何時發(fā)生了何種數(shù)據(jù)變化,控制器都會將變化通知所有的視圖,導致顯示的更新。這實際上是一種模型的變化-傳播機制。模型、視圖、控制器三者之間的關(guān)系和各自的主要功能,如圖1所示。


                

           

          二、MVC設(shè)計模式的實現(xiàn)

            ASP.NET提供了一個很好的實現(xiàn)這種經(jīng)典設(shè)計模式的類似環(huán)境。開發(fā)者通過在ASPX頁面中開發(fā)用戶接口來實現(xiàn)視圖;控制器的功能在邏輯功能代碼(.cs)中實現(xiàn);模型通常對應(yīng)應(yīng)用系統(tǒng)的業(yè)務(wù)部分。在ASP.NET中實現(xiàn)這種設(shè)計而提供的一個多層系統(tǒng),較經(jīng)典的ASP結(jié)構(gòu)實現(xiàn)的系統(tǒng)來說有明顯的優(yōu)點。將用戶顯示(視圖)從動作(控制器)中分離出來,提高了代碼的重用性。將數(shù)據(jù)(模型)從對其操作的動作(控制器)分離出來可以讓你設(shè)計一個與后臺存儲數(shù)據(jù)無關(guān)的系統(tǒng)。就MVC結(jié)構(gòu)的本質(zhì)而言,它是一種解決耦合系統(tǒng)問題的方法。

            2.1 視圖

            視圖是模型的表示,它提供用戶交互界面。使用多個包含單顯示頁面的用戶部件,復(fù)雜的Web頁面可以展示來自多個數(shù)據(jù)源的內(nèi)容,并且網(wǎng)頁人員,美工能獨自參與這些Web頁面的開發(fā)和維護。

            在ASP.NET下,視圖的實現(xiàn)很簡單??梢韵耖_發(fā)WINDOWS界面一樣直接在集成開發(fā)環(huán)境下通過拖動控件來完成頁面開發(fā)本。本文中介紹每一個頁面都采用復(fù)合視圖的形式即:一個頁面由多個子視圖(用戶部件)組成;子視圖可以是最簡單HTML 控件、服務(wù)器控件或多個控件嵌套構(gòu)而成的Web自定義控件。頁面都由模板定義,模板定義了頁面的布局,用戶部件的標簽和數(shù)目,用戶指定一個模板,平臺根據(jù)這些信息自動創(chuàng)建頁面。針對靜態(tài)的模板內(nèi)容,如頁面上的站點導航,菜單,友好鏈接,這些使用缺省的模板內(nèi)容配置;針對動態(tài)的模板內(nèi)容(主要是業(yè)務(wù)內(nèi)容),由于用戶的請求不同,只能使用后期綁定,并且針對用戶的不同,用戶部件的顯示內(nèi)容進行過濾。使用由用戶部件根據(jù)模板配置組成的組合頁面,它增強了可重用性,并原型化了站點的布局。

            視圖部分大致處理流程如下:首先,頁面模板定義了頁面的布局;頁面配置文件定義視圖標簽的具體內(nèi)容(用戶部件);然后,由頁面布局策略類初始化并加載頁面;每個用戶部件根據(jù)它自己的配置進行初始化,加載校驗器并設(shè)置參數(shù),以及事件的委托等;用戶提交后,通過了表示層的校驗,用戶部件把數(shù)據(jù)自動提交給業(yè)務(wù)實體即模型。

            這一部分主要定義了WEB頁面基類PageBase;頁面布局策略類PageLayout,完成頁面布局,用于加載用戶部件到頁面;用戶部件基類UserControlBase即用戶部件框架,用于動態(tài)加載檢驗部件,以及實現(xiàn)用戶部件的個性化。為了實現(xiàn)WEB應(yīng)用的靈活性,視圖部分也用到了許多配置文件例如:置文件有模板配置、頁面配置、路徑配置、驗證配置等。

            2.2 控制器

            為了能夠控制和協(xié)調(diào)每個用戶跨越多個請求的處理,控制機制應(yīng)該以集中的方式進行管理。因此,為了達到集中管理的目的引入了控制器。應(yīng)用程序的控制器集中從客戶端接收請求(典型情況下是一個運行瀏覽器的用戶),決定執(zhí)行什么商業(yè)邏輯功能,然后將產(chǎn)生下一步用戶界面的責任委派給一個適當?shù)囊晥D組件。

            用控制器提供一個控制和處理請求的集中入口點,它負責接收、截取并處理用戶請求;并將請求委托給分發(fā)者類,根據(jù)當前狀態(tài)和業(yè)務(wù)操作的結(jié)果決定向客戶呈現(xiàn)的視圖。在這一部分主要定義了HttpReqDispatcher(分發(fā)者類)、HttpCapture(請求捕獲者類)、Controller(控制器類)等,它們相互配合來完成控制器的功能。請求捕獲者類捕獲HTTP請求并轉(zhuǎn)發(fā)給控制器類。控制器類是系統(tǒng)中處理所有請求的最初入口點??刂破魍瓿梢恍┍匾奶幚砗蟀颜埱笪薪o分發(fā)者類;分發(fā)者類分發(fā)者負責視圖的管理和導航,它管理將選擇哪個視圖提供給用戶,并提供給分發(fā)資源控制。在這一部分分別采用了分發(fā)者、策略、工廠方法、適配器等設(shè)計模式。

            為了使請求捕獲者類自動捕獲用戶請求并進行處理,ASP.NET 提供低級別的請求/響應(yīng) API,使開發(fā)人員能夠使用 .NET 框架類為傳入的 HTTP 請求提供服務(wù)。為此,必須創(chuàng)作支持 System.Web.IHTTPHandler 接口和實現(xiàn) ProcessRequest() 方法的類即:請求捕獲者類,并在web.config 的 <httphandlers> 節(jié)中添加類。ASP.NET 收到的每個傳入 HTTP 請求最終由實現(xiàn) IHTTPHandler 的類的特定實例來處理。IHttpHandlerFactory 提供了處理 IHttpHandler 實例 URL 請求的實際解析的結(jié)構(gòu)。HTTP 處理程序和工廠在 ASP.NET 配置中聲明為 web.config 文件的一部分。ASP.NET 定義了一個 <httphandlers> 配置節(jié),在其中可以添加和移除處理程序和工廠。子目錄繼承 HttpHandlerFactory 和 HttpHandler 的設(shè)置。 HTTP 處理程序和工廠是 ASP.NET 頁框架的主體。工廠將每個請求分配給一個處理程序,后者處理該請求。 例如,在全局 machine.config 文件中,ASP.NET 將所有對 ASPx 文件的請求映射到 HttpCapture類:

          <httphandlers>
          ...
          ...
          </httphandlers>

            2.3 模型

            MVC系統(tǒng)中的模型從概念上可以分為兩類――系統(tǒng)的內(nèi)部狀態(tài)和改變系統(tǒng)狀態(tài)的動作。模型是你所有的商業(yè)邏輯代碼片段所在。本文為模型提供了業(yè)務(wù)實體對象和業(yè)務(wù)處理對象:所有的業(yè)務(wù)處理對象都是從ProcessBase類派生的子類。業(yè)務(wù)處理對象封裝了具體的處理邏輯,調(diào)用業(yè)務(wù)邏輯模型,并且把響應(yīng)提交到合適的視圖組件以產(chǎn)生響應(yīng)。業(yè)務(wù)實體對象可以通過定義屬性描述客戶端表單數(shù)據(jù)。所有業(yè)務(wù)實體對象都EntityBase派生子類對象,業(yè)務(wù)處理對象可以直接對它進行讀寫,而不再需要和request、response對象進行數(shù)據(jù)交互。通過業(yè)務(wù)實體對象實現(xiàn)了對視圖和模型之間交互的支持。實現(xiàn)時把"做什么"(業(yè)務(wù)處理)和"如何做"(業(yè)務(wù)實體)分離。這樣可以實現(xiàn)業(yè)務(wù)邏輯的重用。由于各個應(yīng)用的具體業(yè)務(wù)是不同的,這里不再列舉其具體代碼實例。

          三、MVC設(shè)計模式的擴展

            通過在ASP.NET中的MVC模式編寫的,具有極其良好的可擴展性。它可以輕松實現(xiàn)以下功能:

            ①實現(xiàn)一個模型的多個視圖;

           ?、诓捎枚鄠€控制器;

            ③當模型改變時,所有視圖將自動刷新;

            ④所有的控制器將相互獨立工作。

            這就是MVC模式的好處,只需在以前的程序上稍作修改或增加新的類,即可輕松增加許多程序功能。以前開發(fā)的許多類可以重用,而程序結(jié)構(gòu)根本不再需要改變,各類之間相互獨立,便于團體開發(fā),提高開發(fā)效率。下面討論如何實現(xiàn)一個模型、兩個視圖和一個控制器的程序。其中模型類及視圖類根本不需要改變,與前面的完全一樣,這就是面向?qū)ο缶幊?/span>的好處。對于控制器中的類,只需要增加另一個視圖,并與模型發(fā)生關(guān)聯(lián)即可。該模式下視圖、控制器、模型三者之間的示意圖如圖2所示。

          同樣也可以實現(xiàn)其它形式的MVC例如:一個模型、兩個視圖和兩個控制器。從上面可以看出,通過MVC模式實現(xiàn)的應(yīng)用程序具有極其良好的可擴展性,是ASP.NET面向?qū)ο?/span>編程的未來方向。

          四、MVC的優(yōu)點

            大部分用過程語言比如ASP、PHP開發(fā)出來的Web應(yīng)用,初始的開發(fā)模板就是混合層的數(shù)據(jù)編程。例如,直接向數(shù)據(jù)庫發(fā)送請求并用HTML顯示,開發(fā)速度往往比較快,但由于數(shù)據(jù)頁面的分離不是很直接,因而很難體現(xiàn)出業(yè)務(wù)模型的樣子或者模型的重用性。產(chǎn)品設(shè)計彈性力度很小,很難滿足用戶的變化性需求。MVC要求對應(yīng)用分層,雖然要花費額外的工作,但產(chǎn)品的結(jié)構(gòu)清晰,產(chǎn)品的應(yīng)用通過模型可以得到更好地體現(xiàn)。

            首先,最重要的是應(yīng)該有多個視圖對應(yīng)一個模型的能力。在目前用戶需求的快速變化下,可能有多種方式訪問應(yīng)用的要求。例如,訂單模型可能有本系統(tǒng)的訂單,也有網(wǎng)上訂單,或者其他系統(tǒng)的訂單,但對于訂單的處理都是一樣,也就是說訂單的處理是一致的。按MVC設(shè)計模式,一個訂單模型以及多個視圖即可解決問題。這樣減少了代碼的復(fù)制,即減少了代碼的維護量,一旦模型發(fā)生改變,也易于維護。 其次,由于模型返回的數(shù)據(jù)不帶任何顯示格式,因而這些模型也可直接應(yīng)用于接口的使用。

            再次,由于一個應(yīng)用被分離為三層,因此有時改變其中的一層就能滿足應(yīng)用的改變。一個應(yīng)用的業(yè)務(wù)流程或者業(yè)務(wù)規(guī)則的改變只需改動MVC的模型層。

            控制層的概念也很有效,由于它把不同的模型和不同的視圖組合在一起完成不同的請求,因此,控制層可以說是包含了用戶請求權(quán)限的概念。

            最后,它還有利于軟件工程化管理。由于不同的層各司其職,每一層不同的應(yīng)用具有某些相同的特征,有利于通過工程化、工具化產(chǎn)生管理程序代碼。

          五、MVC的不足

            MVC的不足體現(xiàn)在以下幾個方面:

           ?。?)增加了系統(tǒng)結(jié)構(gòu)和實現(xiàn)的復(fù)雜性。對于簡單的界面,嚴格遵循MVC,使模型、視圖與控制器分離,會增加結(jié)構(gòu)的復(fù)雜性,并可能產(chǎn)生過多的更新操作,降低運行效率。

           ?。?)視圖與控制器間的過于緊密的連接。視圖與控制器是相互分離,但確實聯(lián)系緊密的部件,視圖沒有控制器的存在,其應(yīng)用是很有限的,反之亦然,這樣就妨礙了他們的獨立重用。

            (3)視圖對模型數(shù)據(jù)的低效率訪問。依據(jù)模型操作接口的不同,視圖可能需要多次調(diào)用才能獲得足夠的顯示數(shù)據(jù)。對未變化數(shù)據(jù)的不必要的頻繁訪問,也將損害操作性能。

            (4) 目前,一般高級的界面工具或構(gòu)造器不支持MVC模式。改造這些工具以適應(yīng)MVC需要和建立分離的部件的代價是很高的,從而造成使用MVC的困難。

          posted @ 2007-12-13 15:22 仰望者 閱讀(154) | 評論 (0)編輯 收藏

          構(gòu)造函數(shù)重載:重載三要素(參數(shù)數(shù)量、參數(shù)類型、參數(shù)的排列順序)。
          基本數(shù)據(jù)類型的重載:如果實參比形參的類型小,數(shù)據(jù)會先提升,如果實參比形參大,那么要先進行強制類型轉(zhuǎn)換。
          返回值類型不是重載的要素:理解之一是,構(gòu)造函數(shù)要實現(xiàn)重載,但構(gòu)造函數(shù)無返回值。另外調(diào)用函數(shù)的時候可以沒有返回值類型。

          this關(guān)鍵詞的使用:

          1、this只能用于方法內(nèi)部,它負責返回調(diào)用這個方法的對象的引用。你可以把this對象的引用當成任何對象的引用。

          2、this用于在構(gòu)造函數(shù)中調(diào)用其他構(gòu)造函數(shù),但只能調(diào)用一個,且調(diào)用的代碼應(yīng)放在程序最前面,否則編譯器會報錯。

          3、this.s=s當類的數(shù)據(jù)成員與類的方法的參數(shù)同名時,使用this.s=s消除歧義。

          static的含義:

          它的意思是,這個方法沒有this,你不能在static方法里調(diào)用非static的方法,但你卻可以不通過對象,直接調(diào)用static方法。類的static方法只能訪問其它static方法static成員。

          垃圾回收:
          java提供finalize()方法用于垃圾回收器回收前執(zhí)行方法中的代碼進行非new所創(chuàng)建內(nèi)存的清理。你可以自己定義類的finalize()方法。不過要注意java對象并不總是會被回收的。它不象C++一樣提供析構(gòu)函數(shù),可做到總是回收。java垃圾回收特點:
          1、對象不一定會被垃圾回收器回收;
          2、垃圾回收不是析構(gòu);
          3、你可以自己寫方法時行垃圾回收;
          4、垃圾回收只與內(nèi)存有關(guān);
          5、垃圾回收和finalize()都是靠不住的,只要jvm還沒到快要耗盡內(nèi)存的地步,它是不會浪費時間來回收垃圾以恢復(fù)內(nèi)存的。

          初始化的順序:初始化的順序是由變量在類的定義里面的順序所決定的。變量的定義可能會分散在類定義的各個地方,并且與方法的定義相互交錯,但是變量的初始化會先于任何方法,甚至是構(gòu)造函數(shù)的調(diào)用。以下為例:
              class Tag{
              Tag(int marker){
                  System.out.println("Tag("+marker+")");
              }
          }
          class Card{
              Tag t1 = new Tag(1);
              Card(){
                  System.out.println("Card()");
                  t3 = new Tag(22);
              }
              Tag t2 = new Tag(2);
              void f(){
                  System.out.println("f()");
              }
              Tag t3 = new Tag(3);
          }
          public class Clean {

              /**
               * @param args
               */
              public static void main(String[] args) {
                  // TODO Auto-generated method stub
                  Card t = new Card();
                  t.f();

              }

          }
          輸出結(jié)果為:
          Tag(1)
          Tag(2)
          Tag(3)
          Card()
          Tag(22)
          f()

          Static數(shù)據(jù)的初始化(注意結(jié)合代碼調(diào)試理解):

          package com.initialization.order;
          class Bowl {
             Bowl(){
              System.out.println("Bowl(9)");
             }
             Bowl(int marker) {
               System.out.println("Bowl(" + marker + ")");
             }
              static Bowl b6 = new Bowl(6);
              static Bowl b9 = new Bowl();
              
              void f(int marker) {
               System.out.println("f(" + marker + ")");
             }
           }

          class Table {
            static Bowl b1 = new Bowl(1);
            Table() {
              System.out.println("Table()");
              b2.f(1);
            }
            void f2(int marker) {
              System.out.println("f2(" + marker + ")");
            }
            static Bowl b2 = new Bowl(2);
          }
          class Cupboard {
            Bowl b3 = new Bowl(3); 
            Bowl b10 = new Bowl(); 
            static Bowl b4 = new Bowl(4);
            Cupboard() {
              System.out.println("Cupboard()");
              b4.f(2);
            }
            void f3(int marker) {
              System.out.println("f3(" + marker + ")");
            }
            static Bowl b5 = new Bowl(5);
          }

          public class StaticInitialization {
           //static Bowl b7 = new Bowl(7);                     //----------(1)
            public static void main(String[] args) {
              System.out.println(
                "Creating new Cupboard() in main");
              new Cupboard();
              System.out.println(
                "Creating new Cupboard() in main");
              new Cupboard();
              //t2.f2(1);                                 //--------------(2)
              //t3.f3(1);                                 //---------------(3)
            }
            //static Bowl b8 = new Bowl(8);  //----------------(4)
            //static Table t2 = new Table();   //----------------(5)
            //static Cupboard t3 = new Cupboard();  //---------(6)
          } ///:~

          調(diào)試以上代碼,總結(jié)出以下結(jié)論:

          一、初始化的過程:總體來說順序為:static初始化->非static初始化->執(zhí)行構(gòu)造函數(shù);
          二、代碼分析一:對現(xiàn)有代碼執(zhí)行結(jié)果如下:

          Creating new Cupboard() in main
          Bowl(6)
          Bowl(9)
          Bowl(4)
          Bowl(5)
          Bowl(3)
          Bowl(9)
          Cupboard()
          f(2)
          Creating new Cupboard() in main
          Bowl(3)
          Bowl(9)
          Cupboard()
          f(2)
          執(zhí)行過程:
                   1、java解釋器尋找public class類,加載StaticInitialization 類;
                   2、尋找StaticInitialization 類中的static定義代碼段;這里因為(1)、(4)、(5)、(6)均加了注釋,所以StaticInitialization 中沒有static需要初始化;

                   3、進入main函數(shù)中執(zhí)行代碼輸出Creating new Cupboard() in main;
                   4、繼續(xù)執(zhí)行new Cupboard();,注意初始化的順序是static初始化->非static初始化->執(zhí)行構(gòu)造函數(shù);所以加載類Cupboard后,首先尋找Cupboard類中的static代碼段
          發(fā)現(xiàn)static段是:  static Bowl b4 = new Bowl(4); static Bowl b5 = new Bowl(5);
          同時發(fā)現(xiàn)有非static段是: Bowl b3 = new Bowl(3);   Bowl b10 = new Bowl();  
          按順序先執(zhí)行:static Bowl b4 = new Bowl(4); 初始化,因為定義的是Bowl類的實例,所以先加載Bowl類,進入Bowl類發(fā)現(xiàn)又有static代碼段static Bowl b6 = new Bowl(6);
              static Bowl b9 = new Bowl();然而們知道初始化static Bowl b4 = new Bowl(4); 需要調(diào)用Bowl 的構(gòu)造函數(shù),但調(diào)用構(gòu)造函數(shù)之前必須將該類需要初始化的部分先進行初始化,所以執(zhí)行到這里就要先進行Bowl類中的static代碼段的初始化,之后才能調(diào)用構(gòu)造函數(shù)Bowl(int marker) 為static Bowl b4 = new Bowl(4); 進行初始化。于是b6,b9分別調(diào)用構(gòu)造函數(shù)Bowl(int marker),Bowl(),輸出Bowl(6),Bowl(9),完了之后,b4調(diào)用構(gòu)造函數(shù)Bowl(int marker)輸出Bowl(4),b4初始化結(jié)束,返回Cupboard類繼續(xù)執(zhí)行,初始化b5,輸出Bowl(5),此時Cupboard類中static部分初始化完,接下來對非static部分初始化,即對b3和b10初始化,一樣的方法,加載Bowl類,發(fā)現(xiàn)static字段在上面已經(jīng)初始化,所以這里直接調(diào)用Bowl類的構(gòu)造函數(shù),輸出Bowl(3),Bowl(9)。至此Cupboard類中需要初始化的部分已經(jīng)初始化完了,所以放心大膽的調(diào)用Cupboard類的構(gòu)造函數(shù),為main函數(shù)中代碼完成new Cupboard();的實現(xiàn),輸出Cupboard(),f(2)。程序執(zhí)行返回到main函數(shù),輸出:Creating new Cupboard() in main,代碼new Cupboard();又一次出現(xiàn),這里實際上是想演示static只會初始化一次,而非static只要創(chuàng)建了對象或調(diào)用了成員、成員函數(shù),會進行第二次初始化,于是可以看到輸出結(jié)果并沒有再輸出Bowl(6)、Bowl(9)、Bowl(4)、Bowl(5),而是輸出:Bowl(3)、Bowl(9)、Cupboard()、f(2)。
          5、取消注釋(1)、(4),發(fā)現(xiàn)結(jié)果如下:
          Bowl(6)
          Bowl(9)
          Bowl(7)
          Bowl(8)
          Creating new Cupboard() in main
          Bowl(4)
          Bowl(5)
          Bowl(3)
          Bowl(9)
          Cupboard()
          f(2)
          Creating new Cupboard() in main
          Bowl(3)
          Bowl(9)
          Cupboard()
          f(2)
          可以看出輸出了Bowl(7)、Bowl(8),這說明在main()函數(shù)執(zhí)行之前,程序要先對StaticInitialization進行檢查,如果有static部分,則先初始化。
          6、再取消注釋(2)、(5)輸出結(jié)果為:
          Bowl(6)
          Bowl(9)
          Bowl(7)
          Bowl(8)
          Bowl(1)
          Bowl(2)
          Table()
          f(1)
          Creating new Cupboard() in main
          Bowl(4)
          Bowl(5)
          Bowl(3)
          Bowl(9)
          Cupboard()
          f(2)
          Creating new Cupboard() in main
          Bowl(3)
          Bowl(9)
          Cupboard()
          f(2)
          f2(1)
          在前面的基礎(chǔ)上又輸出了Bowl(1)、Bowl(2)、Table()、f(1)。然而我們看到當沒有代碼
          static Table t2 = new Table();的時候Table類中的static部分沒有被初始化,這說明什么?
          static初始化只有在必要的時候才會進行。只有在創(chuàng)建了第一個Table對象之后才會進行初始化。

          總結(jié)如下:初始化順序為:加載public StaticInitialization類->初始化static->加載類Cupboard->初始化static->加載類Bowl->初始化static->執(zhí)行Bowl類構(gòu)造函數(shù)->初始化Cupboard類非static->調(diào)用Bowl類構(gòu)造函數(shù)執(zhí)行->調(diào)用Cupboard類構(gòu)造函數(shù)執(zhí)行->返回StaticInitialization類.


          posted @ 2007-12-12 17:16 仰望者 閱讀(250) | 評論 (0)編輯 收藏
          正則表達式:是一種用通用術(shù)語描述字符串的方法。要表示一個可能有也可能沒有的負號,你可以負號后面加一個問號,如:-?,表示整數(shù),就是表示一個或多個阿拉伯數(shù)字。在正則表達式中,阿拉伯數(shù)字用‘\d’表示的,但在JAVA的String里,前面應(yīng)加\,如下表示“前面可能有個負號后面跟一串阿拉伯數(shù)字,寫成:-?\\d+,在正則表達式里表示“一個或多個前述的表達式”,使用“+”。
          posted @ 2007-12-12 14:43 仰望者 閱讀(168) | 評論 (0)編輯 收藏
          創(chuàng)建新的對象String s = new String("sfsff");s為對象的引用。
          數(shù)據(jù)的存儲:寄存器、棧、堆、靜態(tài)存儲、固定存儲、非內(nèi)存的存儲
          基礎(chǔ)類型:Java決定了每種primitive(原始)類型的大小。它不像其它語言那樣,隨機器架構(gòu)的不同而不同。變量大小的一致性是Java程序可移植的基礎(chǔ)之一。
          對象作用域:{String s=new String("sfsfsf");}end scope
          對象引用s在end scope處已經(jīng)在作用域外,但對象還在,只是此時對象沒有人操作。
          Static關(guān)鍵字:通常只有創(chuàng)建了對象才能分配內(nèi)存,才能夠使用類中的方法.假如我要一段代碼保存數(shù)據(jù)的內(nèi)存或我要一個不從屬任何對象的方法,則通過Static關(guān)鍵字實現(xiàn).當你聲明某種東西是static的時候,你的意思是這項數(shù)據(jù)或方法沒有被連到任何一個類的實例.因此即使不創(chuàng)建這個類 的實例也可以使用這個static數(shù)據(jù)或方法.但是static的方法不能直接訪問非static的成員或方法.
          static數(shù)據(jù)及方法的訪問:
          class StaticTest{static int i=23;}
          可以用兩種方法使用變量i,
          一種使用類的對象StaticTest st1=new StaticTest();st1.i++;
          一種是直接使用類名.StaticTest.i++;
          注意:如果使用類的多個對象使用變量i時,改變其中一個另一個跟著改變,因為他們使用的是同一段內(nèi)存.
          StaticTest st1=new StaticTest();
          StaticTest st2=new StaticTest();
          st1.i++;
          st2.i++;
          如main函數(shù)中的方法.
          public static void main(String[] args){
              System.out.println("slfsfsfsf");
          }
          因為out是System類中聲明為static類型的對象




          posted @ 2007-11-28 16:59 仰望者 閱讀(120) | 評論 (0)編輯 收藏
          第一章:對象簡介
          對象有狀態(tài)、行為、標識。
          類與數(shù)據(jù)類型區(qū)別:
          類實際上是一種數(shù)據(jù)類型。它們的區(qū)別在于:類是程序員為解決特定問題而定做的,而數(shù)據(jù)類型是為了表示機器的存儲單元而設(shè)計的,它是現(xiàn)成的,是程序員無可奈何時的選擇。
          面向?qū)ο缶幊痰奶魬?zhàn)之一就是:如何在問題空間的元素與解決空間的對象之間建立一種一對一的映射。

          可以向每個對象發(fā)送請求,這樣才能讓對象為你解決問題,但每個對象只能滿足某些請求,具體能夠滿足哪些請求呢?這是由對象的接口(interface)所定義的。決定接口的是對象的類型。接口只管你能向?qū)ο蟀l(fā)送什么請求,但還必須要有滿足這一請求的代碼,這些代碼以及隱藏著的數(shù)據(jù),組成了實現(xiàn)(implementation)

          將對象做為服務(wù)的提供者
          隱藏實現(xiàn):
          將程序分為類的創(chuàng)造者(class creator)和客戶程序員(client programmer).訪問控制符:public,private,protected.public表示后面跟著的東西誰都能用。而private表示除非是類的創(chuàng)建者用這個類的方法進行訪問,否則沒人能訪問到這個元素。protected很像private,它們的區(qū)別在于,繼承類能夠訪問 protected成員但是不能訪問private成員。Java還有一個“缺省”的訪問權(quán)限。通常稱為package訪問權(quán)限。國為同屬這個 package的類可以訪問這個package中其它類的“缺省權(quán)限”的成員。但是出了這個package,它們就都是private的了。

          復(fù)用實現(xiàn)(合成):在一個類中用另一個類創(chuàng)建對象,為了能讓新的類提供我所設(shè)計的功能,它可以由任意多個,任意類型的對象,以任意形式組合在一起。由于你是用已有的類來合成新的類,因此這一概念被稱為合成。如果這個對象是動態(tài)合成的,通常稱為聚合。通常交合成稱為“有(has-a )"關(guān)系。

          繼承:(復(fù)用接口)當你繼承一個類時,你也創(chuàng)建了一個新類,這個新的類不僅包含了已有類的所有成員,更重要的是它復(fù)制了基類的接口,于是所有能夠傳給基類的消息也都可以傳給派生類。
          你有兩種辦法來區(qū)分新的派生出來的類和那個原來的基類。第一種方法很簡單:直接往派生類里加新的方法。這些新的方法不屬于基類的接口。也就是說由于基類不能完成所有的工作,你必須加上更多的方法。第二種方法是在新的類中修改基類方法的行為,這被稱為覆寫(override)那個方法。要覆寫一個方法直接在類中重新定義這個方法就行了。

          多態(tài)性:
          多態(tài)性指的是相關(guān)的對象按照各自類型來實現(xiàn)方法的能力。繼承性指的就是派生類(子類)繼承抽象類(基類、父類),它是一種類特殊化的方式,用于聯(lián)系派生類和抽象類。在這里我把這兩個特點一起舉例說明一下。在魔獸里,四個種族都有農(nóng)民,而且屬性和方法基本一樣,那我們就可以為農(nóng)民這個概念設(shè)置一個基類,然后將每族農(nóng)民設(shè)為一個子類。每個子類方法的類型可能不一樣。在運行時,通過判定對象所屬的類型再去執(zhí)行相應(yīng)類型所對應(yīng)的方法的。所以多態(tài)性與繼承是緊密關(guān)聯(lián)的。

          抽象類與接口(abstrcat與interface): 通常在有些設(shè)計方案中,你只想讓基類去表示由其派生出的類的接口。也就是你不想讓人創(chuàng)建一個基類的對象,而只是想把對象上傳給它,以期能使用這個類的接口。這樣你就需要使用abstract關(guān)鍵詞來把這個類做成抽象類。編譯器會阻止任何人創(chuàng)建abstrcat的對象。abstrcat 關(guān)鍵詞也可以用來表示這個方法還沒有實現(xiàn)--它就象是一個聲明”由這個類所派生出的所有類都有這個方法,但是它的實現(xiàn)不在這里“。abstrcat方法只能存在于abstrcat類里。如果有個類繼承了這個abstrcat類,那么它要么實現(xiàn)這個方法,要么也是一個abstrcat類。abstrcat方法能讓你將方法放到接口而不必為它寫一些無意義的代碼。interface關(guān)鍵詞更是對abstrcat類的概念的深化,它不允許你實現(xiàn)任何方法。如果你愿意你可以繼承多個接口,因為要繼承多個常規(guī)或是抽象類是不允許的。
          posted @ 2007-11-28 15:21 仰望者 閱讀(138) | 評論 (0)編輯 收藏
          主站蜘蛛池模板: 望奎县| 昭觉县| 万山特区| 北票市| 巴东县| 海林市| 温州市| 柏乡县| 孝感市| 宁武县| 桑植县| 明水县| 云梦县| 天祝| 化州市| 永春县| 海门市| 天气| 聊城市| 集贤县| 尉氏县| 嘉峪关市| 六安市| 紫金县| 礼泉县| 三都| 白山市| 祁门县| 渝中区| 佛坪县| 中卫市| 泾源县| 剑川县| 佛山市| 荆门市| 元谋县| 荥经县| 玉溪市| 卢氏县| 太原市| 德钦县|