# 多型 >假設有三個子類別都繼承自某父類別,則可以宣告一個父類別的變數是子類別的實體,這就是最基礎的多型。 例如,創建三個形狀分別是 `Square`、`Circle`、`Rectabgle`,都繼承 `Shape` 類別 ```[java]= Shape shape = new Square(5); // 可以宣告一個形狀是正方形 ``` 但是這樣就會有限制,因為 `shape` 變數可以是正方形這個實體,相對也可以是其他形狀的實體。 ```[java]= Shape shape = new Square(5); // 宣告一個形狀是正方形 // other code ... shape = new Circle(5); ``` 因為不能確定 `shape` 執行到最後會是誰,所以 `shape` **只能取得 `Shape` 類別裡面的方法及屬性**。 ## `Object` 類別 > Java 所有的類別都繼承自 `Object` 類別。 以上面 `shape` 例子來講,`shape` 只能取得 `Shape` 類別裡的方法及屬性,但底下還有其他能使用的方法,就是最底層`Object` 類別中的方法,如圖。 ![Object 類別](https://i.imgur.com/UkzwiFa.png) ![Object 類別](https://i.imgur.com/z2wDeCb.png) ## 靜態多型性 靜態多型性指的是程式在編譯時,系統就能決定呼叫哪個函式,如多載(Overload)。 多載(Overload)範例: ```java= public Student(String className, int seatNum, String name) { this(className, seatNum, name, 0); } public Student(String className, int seatNum, String name, int score) { setClassName(className); setSeatNum(seatNum); setName(name); setScore(score); } ``` ## 動態多型性 動態多型性指在執行時期才能動態確定操作指標所指的物件,比如覆寫(Override)。 範例程式: ```java= //父類別(Shape) public class Shape{ private String name; public Shape(String name){ this.name = name; } public float getArea(){ return 0; } } ``` ```java= //子類別(Circle) public class Circle extends Shape{ private static float PI =3.14f; private int r; public Circle(String name, int r){ super(name); //super為呼叫父類別 this.r = r; } public float getR(){ return this.r; } @Override public float getArea(){ return this.r*this.r*PI; } } ``` ```java= //子類別Rectangle public class Rectangle extends Shape { private float height; private float width; public Rectangle(String name,int height, int width){ super(name); this.height = height; this.width = width; } public float getArea(){ return height*width; } } ``` ```java= //主程式 public class Main{ public static void main(String[] args){ Shape shapeA = new Circle("circleA",1); /* ↑ 因Circle包含Shape所有特性(Circle屬於Shape,是Shape的子類別), 因此在Shape中宣告一個Circle是可行的 */ System.out.println(shapeA.getArea()); /* ↑ 當函式同屬名時(getArea()),Java會根據當前實例來選擇函式。 以本行為例,此時shape的實例(instance)為子類別(Circle), 因為函式getArea在子類別Circle中被覆寫(Override)了,此時輸出會是this.r*this.r*PI,而非0。 只有在程式執行時期才有辦法判斷當前實例(instance)是子類別Circle還是父類別shape, 屬於動態多型的具體展現。*/ shapeA.getR(); /* ↑ 此時IDE會報錯。由於shapeA宣告時是宣告為父類別(Shape),而父類別Shape中並沒有函式getR。 由於ShapeA宣告為父類別,執行時期其並不能保證當前實例(instance)仍為子類別Circle, 因此無法使用Circle類別中新增的函式,*/ // ↓ 舉例而言,當添加下一行時: shapeA = new Rectangle("rectangleA",2,3); // ↑ 此時shapeA的實例(instance)為子類別Rectangle System.out.println(shapeA.getArea()); // ↑ 此時輸出會是6 } } ``` ## 課堂補充 - 當子類別 Override 父類別的方法,只要有用到同一方法時,會優先取用當前這個實體最靠近子類別,最後被覆寫的方法。 ```[java]= Shape shape = new Square(5); /*這時如果 Square 中有 Override shape 的方法 並在這調用,會優先取用 Square 的方法。*/ shape = new Circle(5); /*如果 Circle 也有 Override, 則是調用 Circle 的方法*/ ```