# 多型
>假設有三個子類別都繼承自某父類別,則可以宣告一個父類別的變數是子類別的實體,這就是最基礎的多型。
例如,創建三個形狀分別是 `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` 類別中的方法,如圖。


## 靜態多型性
靜態多型性指的是程式在編譯時,系統就能決定呼叫哪個函式,如多載(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 的方法*/
```