【Java】繼承 覆蓋 隱藏 綁定

繼承(extends)

  • 繼承可以實現代碼的複用,被繼承的類稱爲父類或超類(Superclass),繼承而得到的類稱爲子類
  • 子類繼承父類可訪問(非私有)的成員變量和成員方法,可以修改父類的成員變量或重寫父類的方法,可以添加新的成員變量或成員方法
  • 所有的類都是繼承JAVA.lang.object而來,如沒有,extends關鍵,則默認該類爲object類的子類
  • 繼承通過extends關鍵字實現,使用此關鍵字指出新定義類的父類,就完成兩個類之間建立的繼承關係
  • 間接子類,一個類的父類又是另一個類的子類,那麼此類爲最上層類的間接子類
  • 子類的每個對象也是其父類的對象(繼承的"即是"性質),但父類對象不一定是他子類的對象
  • 執行子類的構造方法之前會先調用父類中沒有參數的構造方法,其目的是爲了要幫助繼承自父類的成員做初始化操作
    • 構造方法是不能被繼承的,但子類可以調用父類的構造方法,間接地繼承會有父類的父類的構造方法被調用
    • 如果父類中有多個構造方法,通過super( )語句來調用父類特定的構造方法
    • 如果使用super( )語句調用了,父類中有參的構造方法,那麼父類中無參的構造方法將不會被自動調用(子類有參構造方法中也默認有super(),父類無參構造方法調用語句)
    • 調用父類構造方法的super()語句必須寫在子類構造方法的第一行(否則將會出現錯誤信息)
    • 如果沒有用super()語句調用父類中特定的構造方法,而父類中只定義了有參數的構造方法,編譯時會發生錯誤(定義有參構造方法,默認參構造方法消失)
    • Super()語句與this()語句必須放在構造方法內的第一行,所以兩個語句無法共存在同一個構造方法中
  • 與this關鍵字一樣,super指的也是對象,所以super同樣不能在static環境中使用(靜態方法和靜態初始化器,其不需要對象來調用)
  • 在子類中可以使用super訪問父類的成員
    • 如果父類中成員被定義爲 受保護 那麼子類中可以直接訪問父類的成員
    • Protected,修飾符可以被該類自身與他在同一包中的其他類,在其包中的該類的子類訪問
  • 覆蓋(方法覆蓋)
    • 子類重寫父類的方法,要求方法名和參數類型完全一樣(參數不能是子類),返回值和異常比父類小或者相同(即爲父類的子類),訪問修飾符比父類大或者相同。
    • 覆蓋屬於JAVA多態的一種
    • 覆蓋是指在子類中定義名稱 參數個數與類型與父類中完全相同的方法,用以重寫父類中同名方法的功能
    • 覆蓋時保證與父類有完全相同的方法頭聲明(方法名 返回值類型和參數列表),如果子類的方法頭與父類的方法頭完全相同,則不能繼承,此時子類方法覆蓋父類方法
    • 子類不能覆蓋父類中聲明爲final(最終)和static(隱藏)的方法
      • 一個方法被繼承,或者是被繼承後不能被覆蓋,那麼這個方法就採用靜態綁定
      • 靜態綁定,在編譯時分配空間,創建對象,是在運行時,在堆中分配空間
    • 默認情況下,所有的成員變量和成員方法都可以被覆蓋,如果父類的成員不希望被子類的成員所覆蓋,可以將他們聲明爲final(最終),程序中的其他部分可以訪問繼承,但不能修改
    • 方法不能交叉覆蓋:子類實例方法不能覆蓋父類的靜態方法;
    • 子類的靜態方法也不能覆蓋父類的實例方法(編譯時報錯)
    • 如果一個 類 被final修飾符所修飾,說明這個類不能再被其他類繼承,即該類不可能有子類,這種類被稱爲最終類
    • 所有被private修飾符限定爲私有的方法,以及所有被包含在final類中的方法都被默認是final的,這些方法既不可能被子類所繼承,也不可能被覆蓋
    • 如果一個成員變量繼被static修飾也被final修飾,它的含義就是常量,這樣的常量只能在定義時被賦值(靜態初始化器)
    • 覆蓋時子類權限要大於父類權限
      • 在子類中覆蓋父類方法時,可以擴大父類中的方法權限,但不能縮小父類中方法的權限,父類中方法覆蓋時受保護的可以改爲公共的,但不能改爲私有的
    • 通過父類的對象(引用變量)訪問子類的成員
      • 通過父類的對象訪問,子類的成員只限於覆蓋的情況發生時
      • 父類與子類的方法名稱參數個數與類型必須完全相同,且只能訪問覆蓋過的方法
  • 隱藏(成員屬性,static方法)
    • 靜態綁定,在編譯時分配空間,創建對象,是在運行時,在堆中分配空間
    • 父類和子類擁有相同名字的屬性或者方法( 方法隱藏只有一種形式,就是父類和子類存在相同的靜態方法)時,父類的同名的屬性或者方法形式上不見了,實際是還是存在的。(向上轉型訪問的是父類屬性或方法)
    • 父類和子類中含有的其實是兩個沒有關係的方法,它們的行爲也並不具有多態性因此,通過一個指向子類對象的父類引用變量來調用父子同名的靜態方法時,只會調用父類的靜態方法。
    • 隱藏是對於靜態方法和成員變量(靜態變量和實例變量)而言的
    • (1)當發生隱藏的時候,聲明類型是什麼類,就調用對應類的屬性或者方法,而不會發生動態綁定
    • (2) 屬性只能被隱藏,不能被覆蓋
    • (3)變量可以交叉隱藏:子類實例變量/靜態變量可以隱藏父類的實例/靜態變量
    • RTTI(run time type identification,運行時類型檢查)
      • RTTI只針對覆蓋,不針對隱藏:因爲覆蓋是動態綁定,是受RTTI約束的,隱藏(靜態綁定)不受RTTI約束
      • 運行時類型爲引用變量所指向的對象的類型,編譯時類型是引用變量自身的類型
  • 綁定
    • 綁定:將一個方法的調用與方法所在的類(方法主體)關聯起來。即決定調用哪個方法和變量。
    • 在java中,綁定分爲靜態綁定和動態綁定。也叫作前期綁定和後期綁定。
      • 靜態綁定
        • 在程序執行以前已經被綁定(即在編譯過程中就已經知道這個方法到底是哪個類中的方法)。
        • java當中的方法只有final、static、private修飾的的方法和構造方法是靜態綁定的。
        • private修飾的方法:private修飾的方法是不能被繼承的,因此子類無法訪問父類中private修飾的方法。所以只能通過父類對象來調用該方法體。因此可以說private方法和定義這個方法的類綁定在了一起。
        • final修飾的方法:可以被子類繼承,但是不能被子類重寫(覆蓋),所以在子類中調用的實際是父類中定義的final方法。(使用final修飾方法的兩個好處:(1)防止方法被覆蓋;(2)關閉java中的動態綁定)。
        • static修飾的方法:可以被子類繼承,但是不能被子類重寫(覆蓋),但是可以被子類隱藏。
        • 如果父類裏有一個static方法,它的子類裏如果沒有對應的方法,那麼當子類對象調用這個方法時就會使用父類中的方法,而如果子類中定義了相同的方法,則會調用子類中定義的方法,唯一的不同就是:當子類對象向上類型轉換爲父類對象時,不論子類中有沒有定義這個靜態方法,該對象都會使用父類中的靜態方法,因此這裏說靜態方法可以被隱藏而不能被覆蓋。這與子類隱藏父類中的成員變量是一樣的。隱藏和覆蓋的區別在於,子類對象轉換成父類對象後,能夠訪問父類被隱藏的變量和方法,而不能訪問父類被覆蓋的方法
        • 構造方法:構造方法也是不能被繼承的(因爲子類是通過super方法調用父類的構造函數,或者是jvm自動調用父類的默認構造方法),因此編譯時也可以知道這個構造方法方法到底是屬於哪個類的
      • 動態綁定
        • 在運行時期根據具體對象的類型進行綁定
        • 若一種語言實現了後期綁定,同時必須提供一些機制,可在運行期間判斷對象的類型,並分別調用適當的方法。也就是說,編譯器此時依然不知道對象的類型,但方法調用機制能自己去調查,找到正確的方法主體
        • RTTI(run time type identification,運行時類型檢查)
          • RTTI只針對覆蓋,不針對隱藏:因爲覆蓋是動態綁定,是受RTTI約束的,隱藏(靜態綁定)不受RTTI約束
          • 運行時類型爲引用變量所指向的對象的類型,編譯時類型是引用變量自身的類型
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章