# 繼承
> 讓一個類別去 **修改**&**擴充** 另一個的類別的內容。
**當一個類別是其他類別共通的部分,就可以拉出來做成父類別**。
例如,已知要做出正方形、長方形、圓形三種類別,因為三種類別都是形狀,就可以將形狀拉出來做成父類別。
*但一般來說,開發時會是要先預先定義好父類別,去評估子類別會要如何去使用。*
## 存取修飾詞
### `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()); // 印出"形狀"
}
}
```

---
### 存取修飾詞整理
| 存取修飾詞 | 同一類別 | 同一套件 | 不同套件的子類別 | 不同套件的非子類別 |
| --- | --- | --- | --- | --- |
| 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`。
{"metaMigratedAt":"2023-06-15T20:29:31.966Z","metaMigratedFrom":"Content","title":"繼承","breaks":false,"contributors":"[{\"id\":\"bf8a189c-f841-4d77-86e1-614bb567075f\",\"add\":3722,\"del\":377}]"}