今日內容
- 繼承
- super關鍵字以及方法重寫
- 多態
01. 繼承的概述
- 什麼是繼承?
- 如何實現繼承關係?
- 什麼時候用繼承?
總結:
1. 繼承就是讓類與類之間產生關係,子父類關係,子類就可以直接使用父類中【非私有的成員】
2. extends
class 子類 extends 父類 {
}
3. 當事物之間產生了一種is..a的關係,誰是誰的一種
老師類,學生類 -> Person類
蘋果類,香蕉類 -> 水果類
狗類,貓類 -> 動物類
稱呼:
父類:超類,基類
子類:派生類
案例演示: 貓,狗,動物類.(不加private)
5分鐘時間練習
02. 繼承的好處和弊端
- 繼承的好處是什麼?
- 繼承的弊端是什麼?
總結:
1.
A. 提高了代碼的複用性
B. 提高了代碼的維護性
C. 是多態的前提
2.
類的耦合性增強了.
開發將就: 高內聚, 低耦合.
耦合: 類與類之間的關係太過緊密
內聚: 自己完成事情的能力.
A類的修改,不要影響到B類
案例演示: 貓,狗,動物類, 屬性加入private
03. Java中繼承的特點
- 思考問題: 一個類是否可以擁有兩個爹?
- 繼承的特點
總結:
1: Java只支持單繼承,不支持多繼承,但是允許多層繼承。
問題:
憑啥不支持多繼承?
假如允許多繼承,多個父類中有相同的方法聲明,但方法的功能主體都不一樣,這時候編譯器無法判斷該執行哪一段功能主體,所以不允許!
例子:
class A {
public void method(){
System.out.println("A....");
}
}
class B {
public void method(){
System.out.println("B....");
}
}
class C extends A, B{
}
C c = new C();
c.method(); // 打印A...還是B... ? 懵了!
多層繼承的例子:
class A {
public void method(){
System.out.println("A");
}
}
class B extends A {
public void show(){
System.out.println("B");
}
}
class C extends B {
}
C c = new C();
c.method();
c.show();
04. Java繼承中成員變量的特點
- 如果子父類中出現了相同的成員變量, 那麼創建子類對象的時候, 用的是誰的成員變量?
- 繼承中成員變量的特點
總結:
1. 子類的成員變量
問題:爲什麼會使用子類的?
此處採用的是就近原則。
05. super關鍵字的概述和使用
- super關鍵字代表什麼?
- this和super的區別又是什麼?
總結:
1. super的作用:用來調用父類中相關的成員【成員變量,成員方法】
this : 代表當前對象的引用,誰來調用我,我就代表誰 (代表子類對象的引用)
super : 代表父類對象的引用
2.
調用成員分類:
1. 成員變量
this : 調用本類的成員變量
class A {
int num = 10;
}
class B extends A {
// this也可以調用父類成員,但是存在前提:子類中沒有定義跟父類相同的成員變量
public void show(){
System.out.println(this.num); // 10
}
}
super : 調用父類的成員變量
2. 成員方法
this : 調用本類成員方法
super : 調用父類成員方法
class Dad {
String name = "建霖";
}
class Kid extends Dad {
String name = "四蔥";
public void show() {
String name = "五蔥";
System.out.println(name); //五蔥
System.out.println(this.name); //四蔥
System.out.println(super.name); //建霖
}
}
06. Java繼承中構造方法的特點
- 需要搞清楚的是子父類誰先完成初始化的問題
總結:
一定是父類先完成初始化
爲什麼?
因爲子類在創建對象並使用的時候,有可能會使用到父類的成員,如果父類沒有完成初始化,子類就訪問不到了
class Fu{
int num = 10;
}
class Zi extends Fu{
public Zi(){
super();
System.out.println(num);
}
}
重點:
子類的每一個構造方法中都默認含有super()這個語句, 目的就是爲了訪問父類的空參構造!!!
意義:爲了完成父類的初始化.
問題: 如果父類沒有空參構造子類怎麼辦?
如果父類沒有空參構造,那絕對存在有參構造
解決方案:
通過super訪問父類的有參構造
結論:子類無論如何,都需要有一個渠道去訪問父類的構造方法
super(); super(10);
建議:今後無論是父類還是子類,空參有參構造都手動給出
注意:
super() : 調用父類構造方法
this() : 調用本類構造方法
兩條語句必須寫在構造方法的第一行有效語句,而且兩者都在爭奪第一行的位置,所以二者衝突
07. Java繼承中成員方法的特點
- 子父類中如果出現了相同的方法, 那麼調用的時候將會採用???
- 成員方法訪問特點:
總結:
1. 子父類中,如果出現了重名的成員方法,在創建子類對象調用方法的時候,使用的是子類的成員方法
2. 如果子父類中沒有出現相同的方法, 那麼在調用的時候, 會看子類有沒有這個方法.
沒有的話, 就調用父類的方法
08. 方法重寫的概述和使用(重點!!!)
- 什麼是方法的重寫?
- 什麼情況下需要使用重寫?
方法的重載(Overload):在同一個類中,方法名相同,參數列表不同,與返回值無關。
總結:
1. 方法的重寫(Override): 在子父類當中,出現了方法聲明一模一樣(方法名相同,參數列表也相同)的方法
2. 當子類需要父類的功能,子類方法的功能主體,又有自己特有的實現方式,這時候就可以對父類的方法進行重寫
這樣做即沿襲了父類的功能,又定義了子類特有的內容
大白話: 子類覺得父類的方法不好,或者說是過於老舊,就可以對父類的方法進行重寫。
@Override : 檢測當前的方法,是否是重寫的方法
舉例: 手機的列子.
09. 方法重寫的注意事項
- 重寫有哪些注意事項?
總結:
1. 子類不能重寫父類中私有的方法
2. 子類重寫父類方法的時候,訪問權限,必須大於等於父類,最好就一致
private
default
protected
public
問題:爲什麼訪問權限一定要大於等於父類呢?
子類重寫父類方法,就是爲了將功能變得更加強大,所以權限需要越來越大.
10. 繼承的練習(學生和老師案例)
學生類:
成員變量:name,age
構造方法:無參,帶參
成員方法:getXxx(),setXxx(),study()
老師類:
成員變量:name,age
構造方法:無參,帶參
成員方法:getXxx(),setXxx(),teach()
我們發現這兩個類中相同的代碼比較多,所以提取出一個父類。
人類:
成員變量:name,age
構造方法getXxx(),setXxx()
學生類:
繼承人類
study()
老師類:
繼承人類
teach()
必須敲明白的代碼:
需求:
程序員類:Coder
姓名 工號 工資
工作
項目經理類:Manager
姓名 工號 工資 獎金
工作.
要求抽取出父類, 私有成員變量, 提供setXxx getXxx方法.
在編寫項目經理類的時候, 通過父類初始化3個共有的變量, 特有的變量自己完成初始化!!!
11. 多態的概述和代碼體現
- 什麼是多態?
- 多態的前提是什麼?
總結:
1. 事物存在的多種形態
Dog d = new Dog(); // 事物是一隻狗
Aniaml a = new Dog(); // 事物是一隻動物
2.
A. 要有繼承關係
B. 要有父類引用指向子類對象
12. 多態中的成員訪問特點
- 多態調用成員變量
- 多態調用成員方法
- 多態調用靜態方法
總結:
1. 編譯看左邊(父類),運行看左邊(父類)
Fu f = new Zi();
System.out.println(f.num); // num執行的是父類的10
原因: 因爲是多態創建對象,持有的是父類的引用,父類的引用有限制,只能看到堆內存中,super的一小塊區域
2. 編譯看左邊(父類),運行看右邊(子類)
原因:在多態創建對象調用成員方法的時候,編譯看父類中是否有此方法
沒有:編譯失敗
有:編譯通過,但是運行的時候,執行子類的邏輯(動態綁定機制)
13. 多態的好處和弊端
總結:
好處:
因爲多態有繼承保證:
1. 提高了代碼的複用性
2. 提高了代碼的維護性
-----------------
1. 提高了代碼的擴展性!!!
可以將一個方法的形參定義爲父類類型,該方法就可以接受這個父類的任意子類對象。
public class Demo1_DuoTai {
public static void main(String[] args) {
useAnimal(new Dog());
useAnimal(new Cat());
}
/*
* 可以將方法的形參,定義爲父類類型,該方法就可以接受這個類的,任意子類對象
*/
public static void useAnimal(Animal a){ // Animal a = new Animal();
// Animal a = new Dog();
// Animla a = new Cat();
a.eat();
}
}
弊端:
不能調用子類特有的屬性和行爲。
非要調用的話,就需要向下轉型!
原因:因爲多態創建對象,編譯時都會看父類中有沒有,而子類特有的屬性和行爲,在父類中都不存在。
報錯!
14. 多態中的轉型問題
- 基本數據類型轉換回顧
- 引用數據類型轉換
總結:
1.
隱式轉換:
概念: 將小的數據類型直接賦值給大的數據類型
double d = 10;
Animal a = new Dog(); // 向上轉型
強制類型轉換:
概念: 將大的數據類型賦值給小的數據類型
double d = 12.3;
int i = (int)d;
2.
Person p = new SuperMan(); // 向上轉型
SuperMan sm = (SuperMan)p; // 向下轉型.
注意: 向下轉型的強轉, 必須發生在子父類的關係當中, 而且必須先轉上去, 才能轉下來.
ClassCastException : 類型轉換異常, 願意: 出現了錯誤的強轉.
錯誤1: Person p = new Person(); SuperMan sm = (SuperMan)p;
錯誤2: Animal a = new Dog(); Cat c = (Cat)a;
15. 多態轉型問題內存圖解
- 看圖說話
16. 多態的練習
- 創建一個“動物類”,包含吃的方法
- 創建一個“貓類”,包含吃的方法和玩的方法
- 創建一個“狗類”,包含吃的方法和玩的方法
關鍵字: instanceOf
判斷左邊的引用, 是否是右邊的數據類型
public static void method(Animal a){ // Animal a = new Dog();
// Animal a = new Cat();
// 調用共有的行爲
a.eat();
// 向下轉型, 調用特有的行爲
if(a instanceof Dog){ // instanceof : 判斷左邊的引用是否是右邊的數據類型.
Dog d = (Dog) a;
d.playGame();
}else if(a instanceof Cat){
Cat c = (Cat) a;
c.playGame();
}
}