亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

Java 多態

本小節我們來學習面向對象的最后一大特征——多態。多態是面向對象最重要的特性。我們將介紹多態的概念和特點,并帶領大家實現一個多態的案例,你將了解到多態的實現條件、什么是向上轉型以及什么是向下轉型,并學會使用instanceof運算符來檢查對象引用是否是類型的實例。

1. 概念和特點

多態顧名思義就是多種形態,是指對象能夠有多種形態。在面向對象中最常用的多態性發生在當父類引用指向子類對象時。在面向對象編程中,所謂多態意指相同的消息給予不同的對象會引發不同的動作。換句話說:多態意味著允許不同類的對象對同一消息做出不同的響應。

例如,火車類和飛機類都繼承自交通工具類,這些類下都有各自的run()方法,交通工具的run()方法輸出交通工具可以運輸,而火車的run()方法輸出火車會跑,飛機的run()方法則輸出飛機會飛,火車和飛機都繼承父類的run()方法,但是對于不同的對象,擁有不同的操作。

任何可以通過多個IS-A測試的 Java 對象都被視為多態的。在 Java 中,所有 Java 對象都是多態的,因為任何對象都能夠通過IS-A測試以獲取其自身類型和 Object 類。

2. 實現多態

2.1 實現條件

在 Java 中實現多態有 3 個必要條件:

  1. 滿足繼承關系
  2. 要有重寫
  3. 父類引用指向子類對象

2.1 實例

例如,有三個類Pet、Dog、Cat
父類Pet:

class Pet {
  	// 定義方法 eat
  	public void eat() {
      	System.out.println("寵物吃東西");
    }
}

子類Dog繼承Pet

class Dog extends Pet { // 繼承父類
  	// 重寫父類方法 eat
  	public void eat() {
      	System.out.println("狗狗吃狗糧");
    }
}
子類Cat繼承Pet
class Cat extends Pet { // 繼承父類
  	// 重寫父類方法 eat
   	public void eat() {
      	System.out.println("貓貓吃貓糧");
    }
}

在代碼中,我們看到DogCat類繼承自Pet類,并且都重寫了其eat方法。

現在已經滿足了實現多態的前兩個條件,那么如何讓父類引用指向子類對象呢?我們在main方法中編寫代碼:

public void main(String[] args) {
  	// 分別實例化三個對象,并且保持其類型為父類Pet
  	Pet pet = new Pet();
  	Pet dog = new Dog();
  	Pet cat = new Cat();
  	// 調用對象下方法
  	pet.eat();
  	dog.eat();
  	cat.eat();
}

運行結果:

寵物吃東西
狗狗吃狗糧
貓貓吃貓糧

在代碼中,Pet dog = new Dog();、Pet cat = new Cat();這兩個語句,把DogCat對象轉換為Pet對象,這種把一個子類對象轉型為父類對象的做法稱為向上轉型。父類引用指向了子類的實例。也就實現了多態。

2.3 向上轉型

向上轉型又稱為自動轉型、隱式轉型。向上轉型就是父類引用指向子類實例,也就是子類的對象可以賦值給父類對象。例如:

Pet dog = new Dog();

這個是因為Dog類繼承自Pet類,它擁有父類Pet的全部功能,所以如果Pet類型的變量指向了其子類Dog的實例,是不會出現問題的。

向上轉型實際上是把一個子類型安全地變成了更加抽象的父類型,由于所有類的根類都是Object,我們也把子類類型轉換為Object類型:

Cat cat = new Cat();
Object o = cat;

2.4 向下轉型

向上轉型是父類引用指向子類實例,那么如何讓子類引用指向父類實例呢?使用向下轉型就可以實現。向下轉型也被稱為強制類型轉換。例如:

// 為Cat類增加run方法
class Cat extends Pet { // 繼承父類
  	// 重寫父類方法 eat
   	public void eat() {
      	System.out.println("貓貓吃貓糧");
    }
  	
  	public void run() {
      	System.out.println("貓貓跑步");
    }
  
  	public static void main(String[] args) {    	
      	// 實例化子類
      	Pet cat = new Cat();
      	// 強制類型轉換,只有轉換為Cat對象后,才能調用其下面的run方法
      	Cat catObj = (Cat)cat;
      	catObj.run();
    }
}

運行結果:

貓貓跑步

我們為Cat類新增了一個run方法,此時我們無法通過Pet類型的cat實例調用到其下面特有的run方法,需要向下轉型,通過(Cat)catPet類型的對象強制轉換為Cat類型,這個時候就可以調用run方法了。

使用向下轉型的時候,要注意:不能將父類對象轉換為子類類型,也不能將兄弟類對象相互轉換。以下兩種都是錯誤的做法:

// 實例化父類
Pet pet = new Pet();
// 將父類轉換為子類
Cat cat = (Cat) pet;

// 實例化Dog類
Dog dog = new Dog();
// 兄弟類轉換
Cat catObj = (Cat) dog;

不能將父類轉換為子類,因為子類功能比父類多,多的功能無法憑空變出來。兄弟類之間不能轉換,這就更容易理解了,兄弟類之間同樣功能不盡相同,不同的功能也無法憑空變出來。

3. instanceof 運算符

instanceof運算符用來檢查對象引用是否是類型的實例,或者這個類型的子類,并返回布爾值。如果是返回true,如果不是返回false。通常可以在運行時使用 instanceof 運算符指出某個對象是否滿足一個特定類型的實例特征。其使用語法為:

<對象引用> instanceof 特定類型

例如,在向下轉型之前,可以使用instanceof運算符判斷,這樣可以提高向下轉型的安全性:

Pet pet = new Cat();
if (pet instanceof Cat) {
		// 將父類轉換為子類
		Cat cat = (Cat) pet;
}

4. 小結

通過本小節的學習,我們知道了多態意味著一個對象有著多重特征,可以在特定的情況下,表現出不同狀態,從而對應著不同的屬性和方法。實現多態有 3 個必要條件,分別是要有繼承、要有重寫以及父類引用指向子類對象,通過向上轉型可以使父類引用指向子類實例;通過向下轉型可以使子類引用指向父類實例,使用instanceof運算符可以用來檢查對象引用是否是類型的實例。