文章目錄
一、繼承
面向對象三大特徵:封裝 、 繼承 、 多態
繼承是多態的前提
繼承: 師傅會的徒弟都會,主要解決的是共性抽取 。
1. 共性抽取
- 有這樣兩個類,我們發現,他們有共性
- 如果存在一個父類 ,正好有這些共性,就可以省下存儲空間。
注意: 一個先有父類,再有子類,上面的只是用於理解的推導。
- 父類 也叫基類 ,也叫超類 (super())。
- 子類 也叫派生類
2. 繼承的格式
體會一下這句話:在繼承的關係中,子類就是一個父類 (父類是官員,子類是文官。文官就是一個官員。是一個is a
的關係。也就是說,子類可以當做父類對待)
- 父類格式 :
public class 父類名 {}
- 子類格式:
public class 子類名 extends 父類名稱 {}
3. 示例
- 創建一個父類
- 創建一個空的子類
- 在另一個文件創建子類對象。調用父類方法成功。
4. 成員變量/方法的4種訪問特點
- 子類創建的對象,調用成員方法或使用成員變量,會優先在子類 中找,找不到就向上一級找,實在找不到就報錯。 即以子類爲起點,向上查找。
- 子類調用的方法,如果使用了某個變量,則以該方法的所屬者向上查找。
- 所屬的概念,不僅是類的範疇。局部變量所屬者是其方法區塊,向上是本類變量,再向上是父類變量。所以當各種重名時,是會先從局部開始找起。
- 如果使用某特定部位的變量,則可用使用:
局部變量
、this.成員變量
、super.成員變量名
,來指定調用局部、本類還是父類的變量。
- 總結一下邏輯,太好理解了: 爲啥吃飽了撐的,要定義重名變量(方法)?就是因爲直接使用上一級的變量(方法)不滿足需求,纔會重新定義。而有時確實有用到上一級的需求,只要使用有
this
關鍵字和super
關鍵字即可。
5. 方法重寫override
重寫: 在繼承關係中,方法名與父類方法名相同,參數列表也一樣。也叫覆蓋、覆寫
重載: 方法名相同,參數列表不同的一組方法。
- 名稱必須相同,參數列表也必須相同
@Override // 檢測是否是重寫,如果不是會報錯。
public void method() {} // 方法名和父類相同
@
的意思是註解。@Override
可以不寫(不寫時,只要格式正確,也是正確的重寫),但最好寫上,起到一個安全檢測的功能。
- 子類方法的返回值必須【小於等於】父類方法的返回值範圍
java.lang.Object類
是所有類的祖宗類- 比如父類方法返回值是
Object類
,子類方法是String
類,這就行。反之不行。 (當初定義這個父類方法,是拿來返回無所不包的Object的。子類重寫方法,只能得到String之類的,Object範圍的子集。也就是說,重寫時,父類的方法是一種限制。前面的1. 講的是怎麼重寫。)
- 子類方法的權限 必須【大於等於】父類方法的權限修飾符
- 權限修飾符:
public
>protected
>(default)
>private
- 備註:
(default)
不是關鍵字default
,而是什麼都不寫,留空 。
在絕大多數情況下,父類和子類的返回值和權限是一致的。
6. 方法的重寫實例
爲什麼要進行方法重寫:
- 設計模式: 對於已經投入使用的類,儘量不要進行修改 。最好定義一個新 的類,來重複利用其中共性內容,並且添加改動新內容。
- 這就是繼承 ,宏觀上叫更新迭代 。
- 父類:
- 子類: 輸入要重寫的方法名,出現提示,按回車,自動完成重寫方法
- 子類: 利用
super.方法名()
來調用父類方法(上一步中已經被IDEA寫好了),再添加新代碼
7. 構造方法的4種訪問特點
- 構造方法,會先執行父類 ,再執行子類 。(因爲先有父,纔有子)
1.1 先寫一個父類
1.2 再寫一個子類
1.3 運行,發現父類構造方法先執行了
- 子類構造方法中,會默認隱含
super();
調用。(這是一個無參構造的調用,如果要調用有參的重載形式,需要手動使用super(參數);
)
2.1 父類不變
2.2 子類全參構造方法,手動加上super(參數);
(當然,可以使用Alt + Insert
讓IDE幫你加)
2.3 創建全參子類對象
- 只有子類的構造方法,可以利用
super();
調用父類的構造方法,且這個構造方法,必須是子類構造方法的第一個語句
- 子類必須調用父類構造方法,不寫就贈送,寫了就用新寫的
8. super & this
8.1 super關鍵字的3種用法:
super.成員變量名
訪問父類成員變量super.成員方法名()
訪問父類成員方法super();
訪問父類構造方法
8.2 this關鍵字的3種用法:
- 在本類的成員方法中,訪問本類的成員變量
- 在本類的成員方法中,訪問本類的另一個成員變量
- 在本類的構造方法中,訪問另一個構造方法()
(比如無參構造,調用有參構造。this();
也必須爲第一個語句。)
super();
和this();
都必須是第一個,不能同時使用,如果使用了this();
那麼super();
不再贈送。
- 如果構造方法循環調用 (比如:無參調1參,1參調全參,全參調無參),會報錯
8.3 Demo
8.4 內存圖
-
最開始,方法區載入三個類(特別注意,子類有一個指向父類的
[[super_class]]
,這是程序自動編寫的)。然後檢測到main()
方法,使其進棧。
-
創建一個子類對象時,會new進堆。此時在堆中爲子類開闢的內存空間分爲兩部分,外部是子類自己,內部是一個完整的父類結構。
-
調用子類method();方法。子類通過
super.
去子類內部找到父類的method();方法。結束之後彈棧
-
調用子類打印變量方法
9. Java繼承的特點
- Java語言是單繼承 的。一個類的直接父類只能有唯一一個。(Python中,可以多繼承是由於
__mor__
繼承順序) - Java語言可以多級繼承,一個類的父類的父類還是它的父類,只不過不是直接父類。
- java.lang.Object是一切類的祖宗類
二、抽象類
1. 什麼是抽象
你能知道圖形類的計算面積方法嘛?
如果父類中的方法不確定如何進行具體實現,那麼這就是一個抽象方法
2. 抽象的格式
創建一個圖形類:
- 抽象方法必須在抽象類內部
- 抽象類和抽象方法都用
abstract
修飾
3. 抽象方法的使用
- 不能直接創建抽象類對象(無意義),需用子類來繼承創建
- 子類需要重寫(也叫實現)父類的所有抽象方法(沒有
abstract
關鍵字,有方法體)
注:
Math.pow(a, b)
表示a的b次方
注意:
- 抽象方法也可以有構造方法,是供子類
super();
調用時使用的。 - 抽象類可以沒有抽象方法。此時是爲了,不讓調用這直接創建該類對象。
- 抽象類的子類,必須重寫父類所有抽象方法,除非這個子類也是抽象類。
Test:發紅包
需求分析
- 需求分析: 羣主和羣成員都有各自姓名和餘額。
- 羣主: 羣主發紅包,成員收紅包。 羣主需要知道當前有多少羣成員,以便把紅包分成多少份。返回的紅包錢數用
ArrayList
返回(因爲不確定長度,所以用可以變化長度的集合來做)。羣主只能發比自己餘額少的錢數。 - 羣成員: 需要接收紅包,加入自己餘額
代碼實現
以下僅展示主要方法
父類
羣主類
成員類
運行調用:
結果