1. 程式人生 > 其它 >Java面向物件之多型基礎

Java面向物件之多型基礎

Java面向物件之多型基礎

目錄

1、怎麼理解多型?

  • 同一方法可以根據傳送物件的不同而採用多種不同的行為方式

  • 同一事物,由於條件不同,產生的結果也不同

  • 同一引用型別,使用不同例項時,執行不同的操作而呈現不同的結果

多型是方法的多型(不是屬性!)

子類重寫了父類的方法,執行子類的方法

1.1 多型實現條件

  1. 有繼承關係;

  2. 方法重寫;

  3. 父類引用指向子類例項(子類物件);

    Pet pet = new Dog();

    物件能執行哪些方法,主要看物件左邊的類

1.2 不可重寫的:

  • static方法,屬於類,不屬於例項

  • final 常量,不可重寫

  • private方法,私有的不可重寫

子類繼承父類,子類進行方法重寫,父類引用指向子類物件,執行相應子類方法。


父類有一個和子類一樣的方法,但父類沒有具體的實現,但在不同子類中,各子類有各自的實現方法;此時父類也就是沒有方法體的,我們把它定義為抽象類


// 父類方法
public void eat(){
        // 無方法體——> 抽象方法
    }

就等同於

public abstract void eat();// 抽象方法

父類的抽象方法一定要在子類實現:

2、 抽象類的使用特點

  1. 一個方法沒有方法體(有這個行為,但沒有具體實現)時,就叫抽象方法,給該方法加上 abstract 即可;
  2. 有抽象方法的類一定是抽象類,反之抽象類裡面可以有抽象方法頁可以沒有(為後面程式擴充套件做準備);
  3. 抽象類不可例項化本類物件:A a = new A(),可以作引用型別,建立子類物件(子類不是抽象類);
  4. 抽象類的子類可以是普通類,該普通類一定要實現抽象類中的抽象方法;
  5. 抽象類的子類也可以是抽象類,此時父類中的抽象方法在子類中可以不被實現;

抽象類中,可以有構造方法 ,是供子類建立物件時,初始化父類成員使用的。

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:

  1. <父型別> <引用變數名> = new <子型別>

  2. 此時通過父類引用變數呼叫的方法是子類覆蓋或繼承父類方法,不是父類的方法;

    這就可以解釋為什麼在父類中方法沒有具體實現了

  3. 此時通過父類引用變數無法呼叫子類特有的方法

    這就是前面提到的 “ 物件能執行哪些方法,主要看物件左邊的類 ”

那 就想調子類特有的方法 怎麼辦???

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:

  1. < 子型別 > < 引用變數 > = <子型別>< 父型別的引用變數 >
  2. 在向下轉型過程中,如果沒有轉換為真實子類型別,會出現型別轉換異常;
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、 總結

  • 抽象類和抽象方法特點:

    • 抽象類不能直接例項化,它只能作為其他類的父類;

    • 抽象方法只有宣告,不能具體實現;

  • 定義抽象類意義所在 :

    • 為其子類提供一個公共型別(父類引用指向子類例項);

    • 封裝子類重複內容(成員變數和方法)