---
# System prepended metadata

title: 繼承

---

# 繼承
> 讓一個類別去 **修改**＆**擴充** 另一個的類別的內容。

**當一個類別是其他類別共通的部分，就可以拉出來做成父類別**。
例如，已知要做出正方形、長方形、圓形三種類別，因為三種類別都是形狀，就可以將形狀拉出來做成父類別。

*但一般來說，開發時會是要先預先定義好父類別，去評估子類別會要如何去使用。*

## 存取修飾詞 
### `private`
子類別不能繼承被設定成 `private` 的屬性，也就是沒有存取權，但依然擁有該屬性。
```[java]=
// Shape.java
public class Shape {
  // 設定成 private，因此子類別沒有存取權
  private String name = "形狀";

 /*  但實際上，name 屬性依然存在，只是取不到。
   所以如果設定了 public String getName，可以取到 name */
  public String getName() {
    return name;
  }
}
```
`Circle` 繼承了 `Shape` 類別
```[java]=12
// Circle.java
public class Circle extends Shape {
  private static float PI = 3.14f;
  private int r;
  
  public Circle(int r){
    this.r = r;
  }
}
```
```[java]=20
// Main.java
public class Main {
  public static void main(String[] args) {
    Circle circle = new Circle(3);
    System.out.println(circle.getName()); // 印出"形狀"
  }
}
```
![執行結果](https://i.imgur.com/EZzb4cS.png)
---

### 存取修飾詞整理

| 存取修飾詞 | 同一類別 | 同一套件 | 不同套件的子類別 | 不同套件的非子類別 |
| --- | --- | --- | --- | --- | 
| private | OK |  |  |  |
| default(無修飾詞) | OK | OK |  |  |
| protected | OK | OK | OK |  |
| public | OK | OK | OK | OK |

- protectd 常會用在方法，讓子類別可以使用，但不希望外部可以使用。

***

## `@Override`
>跟父類別同署名 ( 名字 + 參數 ) 的方法，不一定回傳值相同，但有限制。

如果父類別沒有方法，子類別新增一個方法，叫做擴充。有方法，則子類別去覆寫，叫修改，也就是`@override`。

*Java 有規範，父子類別都有的情況下，優先使用子類別。*

實際上，`@Override` 是把父類別的同署名方法給隱藏，不同署名則符合多載 ( Overloading )，兩個方法都能找到，兩者很常被拿來做比較，面試也常考。

**Override & Overloading 比較**
- Override : 當父子類別有同署名 ( 同名同參數 ) 的方法，子類別會去覆蓋掉父類別的方法。

- Overloading : 不論在相同類別還是父子類別，有同名不同參數的方法，則會同時存在。

### 回傳值的限制
子類別在 `@Override` 方法的時候，回傳值必須是父類別 "**原本回傳值的類別**" 或是 "**原本回傳值的子類別**"。

因此，如果是回傳基本資料型態，基本資料型態沒有繼承關係，所以不能更改成回傳其他基本資料型態。

```[java]=
// Shape.java
public class Shape {
  private String name = "形狀";
  public String getName() {
    return name;
  }

  public Shape test() {
    return this;
  }
}

```
因為 Circle 裡面包含 Shape，因此可以回傳 Circle。
```[java]=13
// Circle.java
public class Circle extends Shape {
  private static float PI = 3.14f;
  private int r;
  public Circle(int r){
    this.r = r;
  }

  /*
  * 父類別設定要回傳 Shape，
  * 因為 Circle 是 Shape 的子類別，
  * 所以包含所有 Shape 的屬性，
  * 因此可以回傳 Circle。
  * */
  @Override
  public Circle test() {
    return null;
  }
}

```
## `super`
`super` 就跟 `this` 一樣，`this` 可以用來呼叫自己的建構子，我們可以利用 `super()` 來呼叫父類別的建構子。
```[java]=
// Shape.java
public class Shape {
  private String name;

  public Shape(String name){
    this.name = name;
  }

  public String getName() {
    return name;
  }

  public Shape test() {
    return this;
  }
}
```
當你在繼承的同時，`java` 會自動幫你在建構子最上方加上 `super()` ，但**如果父類別的建構子有參數**，則系統會不知道你要帶什麼參數，就需要自己呼叫，並且要在第一行呼叫。
```[java]=17
// Circle.java
public class Circle extends Shape {
  private static float PI = 3.14f;
  private int r;
  public Circle(String name, int r){ 
    /*
    * 當你在繼承的同時，
    * java 會自動幫你在建構子最上方加上 super();
    * */
    // super("圓形"); // 直接寫死也可以
    super(name);
    
    /* super 指的是父類別，
    * 因此可以用來呼叫父類別的方法，
    * 不會去呼叫自己 Override 的'
    * */
    super.test(); 
    this.r = r;
  }
  
  @Override
  public Circle test() {
    return null;
  }
}
```
必須要在**建構子第一行**呼叫 `super();` 是因為當繼承了父類別，系統在創建類別時，第一步會先創建父類別。

比如說，要創建一個 `Circle`，系統會先創建 `Shape`，再將 `Circle` 包在 `Shape` 外面，所以如果還有其他類別繼承了 `Circle` ，則會繼續包在外面，以此類推。

*可以確保說，每個類別在創建時，**父類別都已經是創建好的狀態**。*
## 課堂補充
- 當開一個類別，但不希望可以讓人擴充或修改，可以把類別設成 `final`。
- 方法也是，當你不希望被子類別去 Override 你的方法，一樣可以把方法設定成 `final`。