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


          posted @ 2007-12-23 23:01 仰望者 閱讀(163) | 評論 (0)編輯 收藏
          合成與繼承
          繼承:
          super關鍵字的使用:super使用在派生類中,如果派生類中重寫了基類的方法,但在這個被重寫的方法中仍然要調用基類的同名的方法,這就要用到super關鍵字,特別是在創建對象時,在帶參數構造函數中調用基類構造函數的情況。
          如:
          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方法中,要調用基本的scrub方法,那么用super.scrub(); 

           基類的初始化:
                   當你創建一個派生類的對象的時候,這個對象里面還有一個基類的子對象,這個子對象同基類自己創建的對象沒什么兩樣,只是從外面看來,這個子對象被包裹在派生類的對象里面。
                   基類子對象的正確初始化是非常重要的,而且只有一個辦法能保證這一點:調用基類的構造函數來進行初始化,因為只有它才能掌握怎么樣才能正確地進行初始化的信息和權限。java會讓派生類的構造函數自動地調用基類的構造函數。
                    示例:
           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();
            }
          } ///:~
          輸出結果為:
          Art constructor
          Drawing constructor
          Cartoon constructor
          一看結果便一目了然了。

          上面的示例是不帶任何參數的情況,如果構造函數中帶有參數的話,那這里又要用到super的特性了。與上面super的使用涵意一樣,super在這里用作:派生的帶參數構造函數中調用基類的帶參構造函數,只是這里不象上面那樣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();
            }
          } ///:~
          輸出結果是:
          Game constructor
          BoardGame constructor
          Chess constructor

          合成和繼承一起使用,實現類的復用:

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

          class Soup{
              private Soup(){//構造函數聲明為private,其它類不能用此構造函數創建對象;
                  System.out.println("sffewe");
              }
              public static Soup makSoup(){//其它類可通過makSoup來創建對象;
                  return new Soup();
              }
              private static Soup ps1 = new Soup();//自己創建對象;
              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();//不創建對象,但通過Soup中返回的對象引用調用其方法。
              }

          }


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



          posted @ 2007-12-20 11:09 仰望者 閱讀(251) | 評論 (0)編輯 收藏
          主站蜘蛛池模板: 北流市| 汉阴县| 宁都县| 垫江县| 瑞金市| 新营市| 阜阳市| 友谊县| 响水县| 张家口市| 龙江县| 沈阳市| 晋中市| 体育| 万山特区| 陆丰市| 巴东县| 昌图县| 开原市| 钟山县| 新宁县| 津南区| 峨眉山市| 九江县| 故城县| 丰都县| 湖口县| 邻水| 温宿县| 资溪县| 金阳县| 乌什县| 沧源| 突泉县| 洞头县| 资阳市| 旺苍县| 濮阳县| 定日县| 德江县| 平顶山市|