大家可以關註作者的賬號,關註從零開始學Java筆記文集。也可以根據目錄前往作者的博客園博客進行學習。本片文件將基於黑馬程式員就業班視頻進行學習以及資料的分享,並記錄筆記和自己的看法。歡迎大家一起學習和討論。 "【從零開始學Java筆記】目錄" 什麼是多態? 編程其實就是一個將具體世界進行抽象化的過程 ...
大家可以關註作者的賬號,關註從零開始學Java筆記文集。也可以根據目錄前往作者的博客園博客進行學習。本片文件將基於黑馬程式員就業班視頻進行學習以及資料的分享,並記錄筆記和自己的看法。歡迎大家一起學習和討論。
【從零開始學Java筆記】目錄
什麼是多態?
編程其實就是一個將具體世界進行抽象化的過程,多態就是抽象化的一種體現,把一系列具體事物的共同點抽象出來, 再通過這個抽象的事物, 與不同的具體事物進行對話。一句話來說就是,多態是同一個行為具有多個不同表現形式或形態的能力。如果這裡還不懂,不要緊,現急需往下看。
多態的前提
1.子父類的繼承關係
2.方法的重寫
3.父類引用指向子類對象
格式:
1.父類引用Animal a
2.指向=
3.子類對象new Cat( )
示例
對不同類的對象發出相同的消息將會有不同的行為。比如,一個鏟屎官每天早上需要給自己家的寵物喂食,鏟屎官只需要在規定時間下達命令:“開始吃飯”即可,而不需要對貓說:“開始吃魚”,對狗說:“開始吃骨頭”, 因為“寵物”是一個抽象的事物, 只要是寵物就可以吃東西,但是只要他知道自己吃什麼就行了。
public class PolymorphicDemo {
public static void main(String[] args) {
Animal a = new cat();
a.eat();
}
}
class Animal{
public void eat(){
System.out.println("動物吃食物");
}
}
class cat extends Animal {
@Override
public void eat() {
System.out.println("貓吃魚");
}
}
輸出結果
貓吃魚
雖然a指向的是父類Animal,但是調用的確實子類的eat()方法,這就是動態綁定。
動態綁定:運行期間調用的方法,是根據其具體的類型
多態的成員特點
成員變數編譯時看的是左邊,運行時看的左邊
成員方法編譯時看的是左邊,運行時看右邊
靜態方法編譯時看的是左邊,運行時看的也是左邊(使用變數去調用靜態方法,其實相當於用變數類型的類名去調用)
public class Polymorphic {
public static void main(String[] args) {
Dad d = new Son();
System.out.println(d.num);
d.method();
d.function();
}
}
class Dad{
//沒有會報錯
int num = 20;
public void method() {
System.out.println("爸爸的方法");
}
public static void function() {
System.out.println("爸爸的靜態方法");
}
}
class Son extends Dad{
int num = 10;
public void method() {
System.out.println("兒子的方法");
}
public static void function() {
System.out.println("兒子的靜態方法");
}
}
輸出結果
20
兒子的方法
爸爸的靜態方法
總結:編譯時看的都是左邊(編譯錯誤,就是在編譯之前並沒用建立對象,就是說父類並沒有子類的方法,所有必須父類有子類的方法,子類重寫才能運行通過),運行時成員方法看的是右邊(動態綁定),其他(成員變里和靜態的方法)看的都是左邊(沒有動態綁定)
多態中的向上轉型和向下轉型:
引用類型之間的轉換
向上轉型:由小到大(子類型轉換成父類型)
向下轉型:由大到小
基本數據類型的轉換
自動類型轉換
由小到大:byte short char --- int --- long --- float --- double
強制類型轉換
由大到小
public class PolymorphicDemo1 {
public static void main(String[] args) {
Animal2 a = new Dog();//向上轉型
// a.swim();//無法調用
Dog d = (Dog) a;//向下轉型
d.swim();
}
}
class Animal2{
public void eat() {
System.out.println("吃東西");
}
}
class Dog extends Animal2
{
public void eat() {
System.out.println("啃骨頭");
}
public void swim() {
System.out.println("游泳");
}
}
多態的優缺點
優點:可以提高可維護性(多態前提所保證的),提高代碼的可擴展性
缺點:無法直接訪問子類特有的成員
多態的作用
- 應用程式不必為每一個派生類編寫功能調用,只需要對抽象基類進行處理即可。大大提高程式的可復用性。
- 派生類的功能可以被基類的方法或引用變數所調用,這叫向後相容,可以提高可擴充性和可維護性。
一些疑惑
其實作者在剛學習多態的時候一直不理解多態有什麼用?總感覺多此一舉,因為子類重寫了父類的方法,那為什麼不直接實例子類或者父類?這樣不僅可以使用子類的方法,子類還繼承了父類,還能調用父類的方法。
其實作者認為這裡原因有二,一是初學多態的時候,示例總是過於簡單,例如本文之前貓吃魚的例子,確實完全不需要多態反而更方便。二就是繼承和多態沒有分清楚,上述問題全是基於繼承的一種想法去思考,然後發現多態和繼承沒有區別。
這裡再給大家舉個例子:
當有一個基類,比如說形狀類Shape,然後其有一個方法getDesc()
獲得其描述。Shape的子類Circle,Triangle,各自重載其父類的getDesc()
方法,Circle的getDesc()
返回“我是圓形”,Triangle的getDesc()
返回“我是三角形”。然後某一個類的某一個方法如下:
String test(Shape shape){
return shape.getDesc();
}
你在調用test()
方法時可里往裡面傳的參數類型可以是Shape、Circle或Triangle,多態能夠保證getDesc()
方法被正確調用,這叫動態綁定,從而你不用寫三個如下的方法,即test(Shape s)
,test(Circle c)
,test(Triangle t)
。
就可以理解了,多態是為了實現對一個元素進行操作就能滿足所有這個元素子類的操作需求。這也就是為什麼多態只能使用父類的方法,同時在調用時動態綁定實例出來的子類。因為像形狀的例子例子中,以參數的形勢接收父類,編譯父類的方法,在運行時動態綁定相應的子類。即可達到目標。
如果任然不理解,還是沒有問題,因為多態本身就是一個非常抽象的概念。在後期不斷地深入學習中,帶著問題去解決問題,慢慢就會撥開雲霧見青天。然後也會慢慢體會多態的神奇魅力。