Java面向物件之多型基礎
Java面向物件之多型基礎
目錄1、怎麼理解多型?
-
同一方法可以根據傳送物件的不同而採用多種不同的行為方式
-
同一事物,由於條件不同,產生的結果也不同
-
同一引用型別,使用不同例項時,執行不同的操作而呈現不同的結果
多型是方法的多型(不是屬性!)
子類重寫了父類的方法,執行子類的方法
1.1 多型實現條件
-
有繼承關係;
-
方法重寫;
-
父類引用指向子類例項(子類物件);
Pet pet = new Dog();
物件能執行哪些方法,主要看物件左邊的類
1.2 不可重寫的:
-
static方法,屬於類,不屬於例項
-
final 常量,不可重寫
-
private方法,私有的不可重寫
子類繼承父類,子類進行方法重寫,父類引用指向子類物件,執行相應子類方法。
父類有一個和子類一樣的方法,但父類沒有具體的實現,但在不同子類中,各子類有各自的實現方法;此時父類也就是沒有方法體的,我們把它定義為抽象類
// 父類方法 public void eat(){ // 無方法體——> 抽象方法 }
就等同於
public abstract void eat();// 抽象方法
父類的抽象方法一定要在子類實現:
2、 抽象類的使用特點
- 一個方法沒有方法體(有這個行為,但沒有具體實現)時,就叫抽象方法,給該方法加上 abstract 即可;
- 有抽象方法的類一定是抽象類,反之抽象類裡面可以有抽象方法頁可以沒有(為後面程式擴充套件做準備);
- 抽象類不可例項化本類物件:A a = new A(),可以作引用型別,建立子類物件(子類不是抽象類);
- 抽象類的子類可以是普通類,該普通類一定要實現抽象類中的抽象方法;
- 抽象類的子類也可以是抽象類,此時父類中的抽象方法在子類中可以不被實現;
抽象類中,可以有構造方法 ,是供子類建立物件時,初始化父類成員使用的。
3、 多型的使用:
// Pet父類——> 抽象類
public abstract class Pet {
// …………
public abstract void eat();// 父類的抽象方法
// 可理解為子類都有的方法,但父類沒法統一實現
}
// 子類是普通類
public class Dog extends Pet {
// 子類重寫父類的 eat()
public void eat(){
if (this.getHealth()==100){
System.out.println("狗狗"+this.getName()+"吃飽了,無需餵食");
}else{
System.out.println("需要吃骨頭");
this.setHealth(this.getHealth()+3);
//進食後健康值+3
}
}
public class Master {
// 主人給寵物餵食
public void feed(Pet pet){// 需要父類引用型別
pet.eat();
}
}
// 測試類
public static void main(String[] args) {
Master master = new Master();
master.feed(dog);// 指向子類例項——> 調相應的eat方法
}
4、向上轉型
// 測試類
// 上面的程式碼段變成這樣,發現效果也是一樣的~
public static void main(String[] args) {
Pet dog=new Dog("多多",40); //父類型別指向子類物件 **
dog.eat();
// …………
}
- 向上轉型:
父類引用指向子類物件,自動進行型別轉換;
4.1 note:
-
<父型別> <引用變數名> = new <子型別>
-
此時通過父類引用變數呼叫的方法是子類覆蓋或繼承父類方法,不是父類的方法;
這就可以解釋為什麼在父類中方法沒有具體實現了
-
此時通過父類引用變數無法呼叫子類特有的方法;
這就是前面提到的 “ 物件能執行哪些方法,主要看物件左邊的類 ”
那 就想調子類特有的方法 怎麼辦???
5、向下轉型
// 狗狗獨有方法
public void catchfly(){
System.out.println("狗狗可以刁飛碟");
}
// 測試類
Pet dog=new Dog("多多",40);
// dog.catchfly();——> 報錯
Dog d = (Dog)dog;
// ——> 強制轉換:// 將父類 Pet 型別強制轉為子類Dog 型別
d.catchfly(); // 執行子類Dog 類特有的方法
- 向下轉型:
將一個指向子類物件的父類引用賦給一個子類引用:父類型別轉換為子類型別,進行強制轉換
5.1 note:
- < 子型別 > < 引用變數 > = (<子型別>)< 父型別的引用變數 >
- 在向下轉型過程中,如果沒有轉換為真實子類型別,會出現型別轉換異常;
Pet dog=new Dog("多多",40);
Penguin p=(Penguin)dog
// 真實子類型別是狗狗
// 編譯通過了,但
// 執行時報錯:Exception in thread "main" java.lang.ClassCastException:
5.2 ClassCastException(型別轉換錯誤)
//改正:
Pet penguin=new Penguin("Q仔",60);
Penguin p=(Penguin)penguin
p.swim();// 呼叫 Penguin 類特有的swim()
那如何避免這個問題 ???
我們加個判斷;
5.3 instanceof 運算子
// 測試類
Pet dog=new Dog("多多",40);
if (dog instanceof Dog){
Dog d = (Dog)dog;
d.catchfly();
}else if( dog instanceof Penguin ){
Penguin p=(Penguin)dog;
p.swim();
}
注意:使用instanceof 時,物件的型別必須和instanceof 後面的引數所指定的類在繼承上有上下級關係。
6、 總結
-
抽象類和抽象方法特點:
-
抽象類不能直接例項化,它只能作為其他類的父類;
-
抽象方法只有宣告,不能具體實現;
-
-
定義抽象類意義所在 :
-
為其子類提供一個公共型別(父類引用指向子類例項);
-
封裝子類重複內容(成員變數和方法)
-