www.baidu.com

          JavaCode--我愛你,芳兒

          JavaStudy--我愛你,芳兒

          Java語法總結 - 方法

          Java語法總結 - 方法
          原文:http://www.aygfsteel.com/raylong1982/以下幾篇都是的....
          一、方法的重寫。

          1、重寫只能出現(xiàn)在繼承關系之中。當一個類繼承它的父類方法時,都有機會重寫該父類的方法。一個特例是父類的方法被標識為final。重寫的主要優(yōu)點是能夠定義某個子類型特有的行為。
              class Animal {
                  public void eat(){
                      System.out.println ("Animal is eating.");
                  }
              }
              
              class Horse extends Animal{
                  public void eat(){
                      System.out.println ("Horse is eating.");
                  }
              }

          2、對于從父類繼承來的抽象方法,要么在子類用重寫的方式設計該方法,要么把子類也標識為抽象的。所以抽象方法可以說是必須要被重寫的方法。

          3、重寫的意義。
          重寫方法可以實現(xiàn)多態(tài),用父類的引用來操縱子類對象,但是在實際運行中對象將運行其自己特有的方法。
              public class Test {
                  public static void main (String[] args) {
                      Animal h = new Horse();
                      h.eat();    
                  }
              }

              class Animal {
                  public void eat(){
                      System.out.println ("Animal is eating.");
                  }
              }
              
              class Horse extends Animal{
                  public void eat(){
                      System.out.println ("Horse is eating.");
                  }
                  public void buck(){
                  }
              }

          一個原則是:使用了什么引用,編譯器就會只調用引用類所擁有的方法。如果調用子類特有的方法,如上例的h.buck(); 編譯器會抱怨的。也就是說,編譯器只看引用類型,而不是對象類型。

          4、重寫方法的規(guī)則。
          若想實現(xiàn)一個合格重寫方法,而不是重載,那么必須同時滿足下面的要求!

          A、重寫規(guī)則之一:重寫方法不能比被重寫方法限制有更嚴格的訪問級別。
          (但是可以更廣泛,比如父類方法是包訪問權限,子類的重寫方法是public訪問權限。)
          比如:Object類有個toString()方法,開始重寫這個方法的時候我們總容易忘記public修飾符,編譯器當然不會放過任何教訓我們的機會。出錯的原因就是:沒有加任何訪問修飾符的方法具有包訪問權限,包訪問權限比public當然要嚴格了,所以編譯器會報錯的。

          B、重寫規(guī)則之二:參數(shù)列表必須與被重寫方法的相同。
          重寫有個孿生的弟弟叫重載,也就是后面要出場的。如果子類方法的參數(shù)與父類對應的方法不同,那么就是你認錯人了,那是重載,不是重寫。

          C、重寫規(guī)則之三:返回類型必須與被重寫方法的返回類型相同。
          父類方法A:void eat(){}  子類方法B:int eat(){}  兩者雖然參數(shù)相同,可是返回類型不同,所以不是重寫。
          父類方法A:int eat(){}   子類方法B:long eat(){}  返回類型雖然兼容父類,但是不同就是不同,所以不是重寫。

          D、重寫規(guī)則之四:重寫方法不能拋出新的異常或者比被重寫方法聲明的檢查異常更廣的檢查異常。但是可以拋出更少,更有限或者不拋出異常。
              import java.io.*;
              public class Test {
                  public static void main (String[] args) {
                      Animal h = new Horse();
                      try {
                          h.eat();    
                      }
                      catch (Exception e) {
                      }
                  }
              }

              class Animal {
                  public void eat() throws Exception{
                      System.out.println ("Animal is eating.");
                      throw new Exception();
                  }
              }
              
              class Horse extends Animal{
                  public void eat() throws IOException{
                      System.out.println ("Horse is eating.");
                      throw new IOException();
                  }
              }
          這個例子中,父類拋出了檢查異常Exception,子類拋出的IOException是Exception的子類,也即是比被重寫的方法拋出了更有限的異常,這是可以的。如果反過來,父類拋出IOException,子類拋出更為寬泛的Exception,那么不會通過編譯的。
          注意:這種限制只是針對檢查異常,至于運行時異常RuntimeException及其子類不再這個限制之中。

          E、重寫規(guī)則之五:不能重寫被標識為final的方法。

          F、重寫規(guī)則之六:如果一個方法不能被繼承,則不能重寫它。
          比較典型的就是父類的private方法。下例會產生一個有趣的現(xiàn)象。
              public class Test {
                  public static void main (String[] args) {
                      //Animal h = new Horse();
                      Horse h = new Horse();
                      h.eat();
                  }
              }

              class Animal {
                  private void eat(){
                      System.out.println ("Animal is eating.");
                  }
              }
              
              class Horse extends Animal{
                  public void eat(){
                      System.out.println ("Horse is eating.");
                  }
              }
          這段代碼是能通過編譯的。表面上看來違反了第六條規(guī)則,但實際上那是一點巧合。Animal類的eat()方法不能被繼承,因此Horse類中的eat()方法是一個全新的方法,不是重寫也不是重載,只是一個只屬于Horse類的全新的方法!這點讓很多人迷惑了,但是也不是那么難以理解。
          main()方法如果是這樣:
              Animal h = new Horse();
              //Horse h = new Horse();
              h.eat();
          編譯器會報錯,為什么呢?Horse類的eat()方法是public的啊!應該可以調用啊!請牢記,多態(tài)只看父類引用的方法,而不看子類對象的方法!


          二、方法的重載。
          重載是有好的,它不要求你在調用一個方法之前轉換數(shù)據類型,它會自動地尋找匹配的方法。方法的重載是在編譯時刻就決定調用哪個方法了,和重寫不同。最最常用的地方就是構造器的重載。

          1、基本數(shù)據類型參數(shù)的重載。
              public class Test {
                  static void method(byte b){
                      System.out.println ("method:byte");
                  }
                  static void method(short s){
                      System.out.println ("method:short");
                  }
                  static void method(int i){
                      System.out.println ("method:int");
                  }
                  static void method(float f){
                      System.out.println ("method:float");
                  }
                  static void method(double d){
                      System.out.println ("method:double");
                  }
                  public static void main (String[] args) {
                      method((byte)1);
                      method('c');
                      method(1);
                      method(1L);
                      method(1.1);
                      method(1.1f);
                  }
              }
          輸出結果:
          method:byte
          method:int
          method:int
          method:float
          method:double
          method:float

          可以看出:首先要尋找的是數(shù)據類型正好匹配方法。如果找不到,那么就提升為表達能力更強的數(shù)據類型,如上例沒有正好容納long的整數(shù)類型,那么就轉換為float類型的。如果通過提升也不能找到合適的兼容類型,那么編譯器就會報錯。反正是不會自動轉換為較小的數(shù)據類型的,必須自己強制轉換,自己來承擔轉變后果。

          char類型比較特殊,如果找不到正好匹配的類型,它會轉化為int而不是short,雖然char是16位的。


          2、重載方法的規(guī)則。

          A、被重載的方法必須改變參數(shù)列表。
          參數(shù)必須不同,這是最重要的!不同有兩個方面,參數(shù)的個數(shù),參數(shù)的類型,參數(shù)的順序。

          B、被重載的方法與返回類型無關。
          也就是說,不能通過返回類型來區(qū)分重載方法。

          C、被重載的方法可以改變訪問修飾符。
          沒有重寫方法那樣嚴格的限制。

          D、被重載的方法可以聲明新的或者更廣的檢查異常。
          沒有重寫方法那樣嚴格的限制。

          E、方法能夠在一個類中或者在一個子類中被重載。


          3、帶對象引用參數(shù)的方法重載。
              class Animal {}
              class Horse extends Animal{}
              
              public class Test {
                  static void method(Animal a){
                      System.out.println ("Animal is called.");
                  }
                  static void method(Horse h){
                      System.out.println ("Horse is called.");
                  }
                  public static void main (String[] args) {
                      Animal a = new Animal();
                      Horse h = new Horse();
                      Animal ah = new Horse();
                      
                      method(a);
                      method(h);
                      method(ah);
                  }
              }
          輸出結果是:
          Animal is called.
          Horse is called.
          Animal is called.
          前兩個輸出沒有任何問題。第三個方法為什么不是輸出“Horse is called.”呢?還是那句老話,要看引用類型而不是對象類型,方法重載是在編譯時刻就決定的了,引用類型決定了調用哪個版本的重載方法。


          4、重載和重寫方法區(qū)別的小結。
          如果能徹底弄明白下面的例子,說明你對重載和重寫非常了解了,可以結束這節(jié)的復習了。
              class Animal {
                  public void eat(){
                      System.out.println ("Animal is eating.");    
                  }
              }
              class Horse extends Animal{
                  public void eat(){
                      System.out.println ("Horse is eating.");    
                  }
                  public void eat(String food){
                      System.out.println ("Horse is eating " + food);
                  }
              }
              
              public class Test {
                  public static void main (String[] args) {
                      Animal a = new Animal();
                      Horse h = new Horse();
                      Animal ah = new Horse();
                      
                      a.eat();
                      h.eat();
                      h.eat("apple");
                      ah.eat();
                      //a.eat("apple");
                      //ah.eat("apple");
                  }
              }

          四個輸出分別是什么?被注釋的兩條語句為什么不能通過編譯?
          第一條:a.eat(); 普通的方法調用,沒有多態(tài),沒什么技術含量。調用了Animal類的eat()方法,輸出:Animal is eating.
          第二條:h.eat(); 普通的方法調用,也沒什么技術含量。調用了Horse類的eat()方法,輸出:Horse is eating.
          第三條:h.eat("apple"); 重載。Horse類的兩個eat()方法重載。調用了Horse類的eat(String food)方法,輸出:Horse is eating apple
          第四條:ah.eat(); 多態(tài)。前面有例子了,不難理解。輸出:Horse is eating.
          第五條:a.eat("apple"); 低級的錯誤,Animal類中沒有eat(String food)方法。因此不能通過編譯。
          第六條:ah.eat("apple"); 關鍵點就在這里。解決的方法還是那句老話,不能看對象類型,要看引用類型。Animal類中沒有eat(String food)方法。因此不能通過編譯。

          小結一下:多態(tài)不決定調用哪個重載版本;多態(tài)只有在決定哪個重寫版本時才起作用。
          重載對應編譯時,重寫對應運行時。夠簡潔的了吧!


          三、構造方法。
          構造方法是一種特殊的方法,沒有構造方法就不能創(chuàng)建一個新對象。實際上,不僅要調用對象實際類型的構造方法,還要調用其父類的構造方法,向上追溯,直到Object類。構造方法不必顯式地調用,當使用new關鍵字時,相應的構造方法會自動被調用。

          1、構造方法的規(guī)則。
          A、構造方法能使用任何訪問修飾符。包括private,事實上java類庫有很多都是這樣的,設計者不希望使用者創(chuàng)建該類的對象。

          B、構造方法的名稱必須與類名相同。這樣使得構造方法與眾不同,如果我們遵守sun的編碼規(guī)范,似乎只有構造方法的首字母是大寫的。

          C、構造方法不能有返回類型。
          反過來說,有返回類型的不是構造方法
              public class Test {
                  int Test(){
                      return 1;
                  }
              }
          這個方法是什么東西?一個冒充李逵的李鬼而已,int Test()和其他任何普通方法沒什么兩樣,就是普通的方法!只不過看起來很惡心,類似惡心的東西在考試卷子里比較多。

          D、如果不在類中創(chuàng)建自己的構造方法,編譯器會自動生成默認的不帶參數(shù)的構造函數(shù)。
          這點很容易驗證!寫一個這樣簡單的類,編譯。
          class Test {
          }
          對生成的Test.class文件反編譯:javap Test,可以看到:
          D:"JavaCode"bin>javap Test
          Compiled from "Test.java"
          class Test extends java.lang.Object{
              Test();
          }
          看到編譯器自動添加的默認構造函數(shù)了吧!

          E、如果只創(chuàng)建了帶參數(shù)的構造方法,那么編譯器不會自動添加無參的構造方法的!

          F、在每個構造方法中,如果使用了重載構造函數(shù)this()方法,或者父類的構造方法super()方法,那么this()方法或者super()方法必須放在第一行。而且這兩個方法只能選擇一個,因此它們之間沒有順序問題。

          G、除了編譯器生成的構造方法,而且沒有顯式地調用super()方法,那么編譯器會插入一個super()無參調用。

          H、抽象類有構造方法。


          四、靜態(tài)方法的重載與重寫(覆蓋)。

          1、靜態(tài)方法是不能被覆蓋的。可以分兩種情況討論:

          A、子類的非靜態(tài)方法“覆蓋”父類的靜態(tài)方法。
          這種情況下,是不能通過編譯的。

          class Father{
              
          static void print(){
                  System.out.println (
          "in father  method");
              }
          }
          class Child extends Father{
              
          void print(){
                  System.out.println (
          "in child method");
              }
          }

          static方法表示該方法不關聯(lián)具體的類的對象,可以通過類名直接調用,也就是編譯的前期就綁定了,不存在后期動態(tài)綁定,也就是不能實現(xiàn)多態(tài)。子類的非靜態(tài)方法是與具體的對象綁定的,兩者有著不同的含義。

          B、子類的靜態(tài)方法“覆蓋”父類靜態(tài)方法。
          這個覆蓋依然是帶引號的。事實上把上面那個例子Child類的print方法前面加上static修飾符,確實能通過編譯!但是不要以為這就是多態(tài)!多態(tài)的特點是動態(tài)綁定,看下面的例子:

          class Father{
              
          static void print(){
                  System.out.println (
          "in father  method");
              }
          }
          class Child extends Father{
              
          static void print(){
                  System.out.println (
          "in child method");
              }
          }

          class Test{
              
          public static void main (String[] args) {
                  Father f 
          =new Child();
                  f.print();
              }
          }

          輸出結果是:in father  method
          從這個結果可以看出,并沒有實現(xiàn)多態(tài)。
          但是這種形式很迷惑人,貌似多態(tài),實際編程中千萬不要這樣搞,會把大家搞懵的!
          它不符合覆蓋表現(xiàn)出來的特性,不應該算是覆蓋!
          總而言之,靜態(tài)方法不能被覆蓋。

          2、靜態(tài)方法可以和非靜態(tài)方法一樣被重載。
          這樣的例子太多了,我不想寫例程了。看看java類庫中很多這樣的例子。
          如java.util.Arrays類的一堆重載的binarySearch方法。
          在這里提一下是因為查資料時看到這樣的話“sun的SL275課程說,靜態(tài)方法只能控制靜態(tài)變量(他們本身沒有),靜態(tài)方法不能被重載和覆蓋……”
          大家不要相信啊!可以重載的。而且靜態(tài)與非靜態(tài)方法可以重載。

          從重載的機制很容易就理解了,重載是在編譯時刻就決定的了,非靜態(tài)方法都可以,靜態(tài)方法怎么可能不會呢?


           

          芳兒寶貝.我愛你

          posted on 2007-12-08 15:05 wǒ愛伱--咾婆 閱讀(256) 評論(0)  編輯  收藏 所屬分類: JavaBaseFiles

          導航

          統(tǒng)計

          公告

          芳兒寶貝.我愛你


          黑客基地
          http://www.hackbase.com
          全球最大的黑客門戶網站


           最近在讀的書:

          常用鏈接

          留言簿(1)

          隨筆分類(37)

          JavaCode

          搜索

          積分與排名

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 福安市| 沽源县| 当雄县| 色达县| 沈阳市| 铜山县| 五河县| 浠水县| 兴义市| 益阳市| 福安市| 高尔夫| 三江| 海丰县| 文安县| 江北区| 当涂县| 蒲江县| 石泉县| 辉县市| 宁南县| 志丹县| 呼伦贝尔市| 唐海县| 临猗县| 肇州县| 栾川县| 阳朔县| 清新县| 威信县| 云南省| 和政县| 渭源县| 施秉县| 巫山县| 莱州市| 榆社县| 汉源县| 柳河县| 西青区| 简阳市|