Java基礎語法06-面向對象-繼承

七、繼承

多個類中存在相同屬性和行爲時,將這些內容抽取到單獨一個類中,那麼多個類中無需再定義這些屬性和行爲,只需要和抽取出來的類構成繼承關係。

繼承的好處

  • 提高代碼的複用性

  • 提高代碼的擴展性

  • 類與類之間產生了關係,是學習多態的前提。例如:學生 is - a 人。

繼承的格式(extends

【修飾符】 class 父類 {
  ...
}

【修飾符】 class 子類 extends 父類 {
  ...
}

繼承的特點

1、Java只支持單繼承,每一個子類只有一個直接父類

2、Java支持多層繼承,父類還可以有父類

3、子類會繼承父類所有特徵,包括成員變量、成員方法,哪怕是私有的,私有的在子類中無法直接使用。

4、子類不會繼承父類的代碼塊、構造器等。

5、但是子類一定會調用父類的實例初始化方法。

繼承的特點一:成員變量

1、父類成員變量私有化(private)

  • 父類中的成員,無論是公有(public)還是私有(private),均會被子類繼承

  • 子類雖會繼承父類私有(private)的成員,但子類不能對繼承的私有成員直接進行訪問,可通過繼承的get/set方法進行訪問。如圖所示:

子類創建對象時,在堆內存中是要爲從父類繼承的成員變量分配內存空間。

2、父類子類成員變量重名

我們說父類的所有成員變量都會繼承到子類中,那麼如果子類出現與父類同名的成員變量會怎麼樣呢?

結論:

(1)當父類的成員變量私有化時,在子類中是無法直接訪問的,所以是否重名不影響,如果想要訪問父類的私有成員變量,只能通過父類的get/set方法訪問;

(2)當父類的成員變量非私有時,在子類中可以直接訪問,所以如果有重名時,就需要加“super."進行區別。

格式:super.父類成員變量名,但是前提條件,這個成員變量沒有私有化。

說明:雖然我們可以區分父子類的重名成員變量,但是實際開發中,我們不建議這麼幹。

繼承的特點二:成員方法

我們說父類的所有方法子類都會繼承,但是當某個方法被繼承到子類之後,子類覺得父類原來的實現不適合於子類,該怎麼辦呢?

1、方法重寫

1.@Override:寫在方法上面,用來檢測是不是有效的正確覆蓋重寫。這個註解就算不寫,只要滿足要求,也是正確的方法覆蓋重寫。建議保留

2.必須保證父子類之間方法的名稱相同,參數列表也相同

3.子類方法的返回值類型必須【小於等於】父類方法的返回值類型(小於其實就是是它的子類,例如:Student < Person)。

注意:如果返回值類型是基本數據類型和void,那麼必須是相同

4.子類方法的權限必須【大於等於】父類方法的權限修飾符 小擴展提示:public > protected > 缺省 > private

5.幾種特殊的方法不能被重寫

  • 靜態方法不能被重寫

  • 私有等在子類中不可見的方法不能被重寫

  • final方法不能被重寫

小貼士:重寫時,用到super.父類成員方法,表示調用父類的成員方法。

繼承的特點三:構造方法

當類之間產生了關係,其中各類中的構造方法,又產生了哪些影響呢?

首先我們要回憶兩個事情,構造方法的定義格式和作用。

  1. 構造方法的名字是與類名一致的。

    所以子類是無法繼承父類構造方法的。

  2. 構造方法的作用是初始化實例變量的,而子類又會從父類繼承所有成員變量

    所以子類的初始化過程中,必須先執行父類的初始化動作。子類的構造方法中默認有一個super() ,表示調用父類的實例初始化方法,父類成員變量初始化後,纔可以給子類使用。

如果父類沒有無參構造怎麼辦?

解決辦法:在子類構造器中,用super(實參列表),顯示調用父類的有參構造解決。

結論:

子類對象實例化過程中必須先完成從父類繼承的成員變量的實例初始化,這個過程是通過調用父類的實例初始化方法來完成的。

  • super():表示調用父類的無參實例初始化方法,要求父類必須有無參構造,而且可以省略不寫;

  • super(實參列表):表示調用父類的有參實例初始化方法,當父類沒有無參構造時,子類的構造器首行必須寫super(實參列表)來明確調用父類的哪個有參構造(其實是調用該構造器對應的實例初始方法)

  • super()和super(實參列表)都只能出現在子類構造器的首行

繼承的特點四:單繼承限制

1、Java只支持單繼承,不支持多繼承。

2、Java支持多層繼承(繼承體系)。

頂層父類是Object類。所有的類默認繼承Object,作爲父類。

3、子類和父類是一種相對的概念。

4、一個父類可以同時擁有多個子類

final關鍵字

final:最終的,不可更改的,它的用法有:

1、修飾類

表示這個類不能被繼承,沒有子類

2、修飾方法

表示這個方法不能被子類重寫

3、聲明常量

final修飾某個變量(成員變量或局部變量),表示它的值就不能被修改,即常量,常量名建議使用大寫字母。

如果某個成員變量用final修飾後,沒有set方法,並且必須初始化(可以顯式賦值、或在初始化塊賦值、實例變量還可以在構造器中賦值)

當修飾的是數組變量時,數組的地址值不可以改變但數組元素可以改變。

this關鍵字

this代表當前對象的引用(地址值),即對象自己的引用。

  • this可以用於非靜態代碼塊和構造器中:表示正在創建的那個實例對象,即正在new誰,this就代表誰

  • this用於實例方法中:表示調用該方法的對象,即誰在調用,this就代表誰。

this使用格式

1、this.成員變量名

當方法的局部變量與當前對象的成員變量重名時,就可以在成員變量前面加this.,如果沒有重名問題,就可以省略this.

2、this.成員方法

調用當前對象自己的成員方法時,都可以加"this.",也可以省略,實際開發中都省略

3、this()或this(實參列表)

當需要調用本類的其他構造器時,就可以使用該形式。

要求:

必須在構造器的首行

如果一個類中聲明瞭n個構造器,則最多有 n - 1個構造器中使用了"this(【實參列表】)",否則會發生遞歸調用死循環

super關鍵字

super代表父類的引用

注意:在子類中通過super去引用父類的成員時,必須保證該成員在子類中是仍然可見的,即注意權限修飾符問題

(1)super.成員變量

在子類中訪問父類的成員變量,特別是當子類的成員變量與父類的成員變量重名時。

(2)super.成員方法

在子類中調用父類的成員方法,特別是當子類重寫了父類的成員方法時

(3)super()或super(實參列表)

在子類的構造器首行,用於表示調用父類的哪個構造器(本質上是該構造器對應的實例初始化方法)

super() 和 this() 都必須是在構造方法的第一行,所以不能同時出現。

this()和this(實參列表) 與 super()或super(實參列表) 不能同時出現

就近原則:解決複雜問題

  • 沒有super和this

    • 在構造器、代碼塊、方法中如果出現使用某個變量,先查看是否是當前塊聲明的局部變量,

    • 如果不是局部變量,先從當前類去找成員變量

    • 如果當前類中沒有找到,會往上找父類的(非private,跨包還不能是缺省的)

  • this :代表當前對象的引用

    • 通過this找成員變量和成員方法時,先從當前類中找,沒有的會往上找父類的(非private,跨包還不能是缺省的)。

    • 但是this()或this(實參列表)只會在本類中找

  • super :代表父類的存儲空間標識(可以理解爲父類的引用)。

    • 通過super找成員變量和成員方法時,直接從父類空間(包含父類的父類繼承的)找

    • super()或super(實參列表)只能從直接父類

    • 通過super只能訪問父類在子類中可見的(非private,跨包還不能是缺省的)

  • 即:super一定是從直接父類開始找

    this一定是從當前類的成員開始找

    即沒有this又沒有super,一定是從局部變量開始找

注意:super和this都不能出現在靜態方法和靜態代碼塊中,因爲super和this都是存在與對象中的

繼承與初始化

類初始化

實際上,類初始化的過程時在調用一個<clinit>()方法,而這個方法是編譯器自動生成的。編譯器會將如下兩部分的所有代碼,按順序合併到類初始化<clinit>()方法體中。

(1)靜態類成員變量的顯式賦值語句

(2)靜態代碼塊中的語句

整個類初始化只會進行一次,如果子類初始化時,發現父類沒有初始化,那麼會先初始化父類。

結論:

每一個類都有一個類初始化方法<clinit>()方法,然後子類初始化時,如果發現父類沒有加載和沒有初始化,會先加載和初始化父類,然後再加載和初始化子類。一個類,只會初始化一次。

實例初始化

實際上我們編寫的代碼在編譯時,會自動處理代碼,整理出一個<clinit>()的類初始化方法,還會整理出一個或多個的<init>(...)實例初始化方法。一個類有幾個實例初始化方法,由這個類有幾個構造器決定。

實例初始化方法的方法體,由四部分構成:

(1)super()或super(實參列表) 這裏選擇哪個,看原來構造器首行是哪句,沒寫,默認就是super()

(2)非靜態實例變量的顯示賦值語句

(3)非靜態代碼塊

(4)對應構造器中的代碼

特別說明:其中(2)和(3)是按順序合併的,(1)一定在最前面(4)一定在最後面

執行特點:

  • 創建對象時,纔會執行,

  • 調用哪個構造器,就是指定它對應的實例初始化方法

  • 創建子類對象時,父類對應的實例初始化會被先執行(父類的clinit<>(有參或無參)方法執行完後再執行子類的init<>(有參或無參)方法),執行父類哪個實例初始化方法,看用super()還是super(實參列表)

結論:

類初始化肯定優先於實例初始化。

類初始化只做一次。

實例初始化是每次創建對象都要進行。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章