(轉)繼承、重載、覆蓋、多態

http://blog.chinaunix.net/uid-375137-id-2413340.html

 

1、繼承(inheritance)
   一旦你已經創建了一個定義了對象一般屬性的超類,該超類可以被繼承以生成特殊用途的類。每一個子類只增添它自己獨特的屬性。這是繼承的本質。Java 不支持多超類的繼承
   超類變量可以引用子類對象(運行時確定)

 
2、重載(overload)
   a)、方法重載要求參數類型或個數必須不一致
   b)、對返回類型無限制
   c)、對於繼承來說,如果某一方法在父類中是訪問權限是priavte,那麼就不能在子類對其進行重載,如果定義的話,也只是定義了一個新方法,而不會達到重載的效果
 
3、覆蓋(override)
   從字面就可以知道,它是覆蓋了一個方法並且對其重寫,以求達到不同的作用。對我們來說最熟悉的覆蓋就是對接口方法的實現,在接口中一般只是對方法進行了聲明,而我們在實現時,就需要實現接口聲明的所有方法。除了這個典型的用法以外,我們在繼承中也可能會在子類覆蓋父類中的方法。在覆蓋要注意以下的幾點: 
   a)、要求父類和子類的方法名稱、參數相同(簽名相同
   b)、子類中覆蓋的方法的訪問權限要>=父類中的方法的訪問權限(defautl、protected、public)。
   c)、子類中覆蓋的方法的返回值必須和父類中的方法的返回一致; 
   d)、子類中覆蓋的方法所拋出的異常必須和被覆蓋方法的所拋出的異常一致,或者是其子類(異常被包含); 
   e)、被覆蓋的方法不能爲private,否則在其子類中只是新定義了一個方法,並沒有對其進行覆蓋。
   f)、靜態方法(static)和最終方法(帶關鍵字final的方法)不能被覆蓋(“實例方法被覆蓋,靜態方法被隱藏”)
   g)、抽象方法必須在具體類中被覆蓋 
4、多態(polymorphism)
   多態性的概念也可以被說成“一個接口,多個方法”。Java實現運行時多態性的基礎是動態方法調度,它是一種在運行時而不是在編譯期調用重載方法的機制。
   多態的通常含義是能夠呈現出多種不同的形式或形態,即一個特定類型的變量可以用於引用不同類型的對象,並且自動調用該變量引用的特定類型對象的方法,這樣就使得一個方法的調用根據該調用所作用到的不同對象類型而響應不同的操作。
   下面就繼承和接口實現兩方面談談java運行時多態性的實現。
   (1)、通過繼承中超類對象引用變量引用子類對象來實現
       //定義超類superA
       class superA
       {
         void callfun()
         {
            System.out.println("call superA");
         }
       }
     
      // 定義superA的子類subB
      class subB extends superA
      {
        void callfun()
        {
           System.out.println(call subB");
        }
      }
 
      // 定義superA的子類subC
      class subC extends superA
      {
        void callfun()
        {
           System.out.println("call subC");
        }
      }
 
      class mytest
      {
        public static void main(String[] args)
        {
           superA a;
           subB b = new subB();
           subC c = new subC();
           a=b;
           a.callfun();  (1)
           a=c;
           a.callfun();  (2)
        }
      }
 
     運行結果:
     call subB
     call subC
   
     上述代碼中subB和subC是超類superA的子類,我們在類mytest中聲明瞭3個引用變量a, b, c,通過將子類對象引用賦值給超類對象引用變量來實現動態方法調用。也許有人會問:“爲什麼(1)和(2)不輸出:call superA”。java 的這種機制遵循一個原則:當超類對象引用變量引用子類對象時,被引用對象的類型而不是引用變量的類型決定了調用誰的成員方法,但是這個被調用的方法必須是在超類中定義過的,也就是說被子類覆蓋的方法。
   所以,不要被上例中(1)和(2)所迷惑,雖然寫成a.callfun(),但是由於(1)中的a被b賦值,指向了子類subB的一個實例,因而(1)所調用的callfun()實際上是子類subB的成員方法callfun(),它覆蓋了超類superA的成員方法callfun();同樣(2)調用的是子類subC的成員方法callfun()。
   另外,如果子類繼承的超類是一個抽象類,雖然抽象類不能通過new操作符實例化,但是可以創建抽象類的對象引用指向子類對象,以實現運行時多態性。具體的實現方法同上例。
   不過,抽象類的子類必須覆蓋實現超類中的所有的抽象方法,否則子類必須被abstract修飾符修飾,當然也就不能被實例化了。

有人不禁要問,子類重寫了父類的方法,爲什麼不直接用子類創建引用來引用子類的對象,而非要用父類創建個引用來引用子類的對象呢?這不是多此一舉嗎?
   直接用子類創建引用當然可以,但是這無法體現出Java多態的優勢。
   舉個例子,一個公司要派員工出差解決問題,員工裏面有資深員工,有新手,資深員工解決問題的能力當然比新手強了,我們設計幾個類
   class Staff
   {
      void resolve()
      {
         System.Out.Println("爲客戶解決問題");
      }
   }

   class ExperienceStaff extends Staff  //資深員工,能快速解決問題
   {
      void resolve()
      {
         System.Out.Println("快速地爲客戶解決問題");
      }
   }

   class NewStaff extends Staff  //新手,無法單獨解決問題
   {
      void resolve()
      {
         System.Out.Println("我是菜鳥,需要別人幫助才能解決問題");
      }
   }
 
   //現在客戶說產品有問題,要公司派人給解決
   class Customer
   {
      void resolveProblem(Staff sf)
      {
         sf.resolve();
      }
   }
 
   //測試
   Public class Test
   {
      public static void main(String[] args)
      {
         Customer cs = new Customer();
     
         Staff guy = new ExperienceStaff();
         cs.resolveProblem(guy);  //給客戶派去一個資深員工,迅速解決了問題,客戶很滿意
     
         guy = new NewStaff();       
         cs.resolveProblem(guy);  //給客戶派去一個新手,不停的打電話請教別人,客戶很生氣,後果很嚴重
      }
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章