# 繼承 > 讓一個類別去 **修改**&**擴充** 另一個的類別的內容。 **當一個類別是其他類別共通的部分,就可以拉出來做成父類別**。 例如,已知要做出正方形、長方形、圓形三種類別,因為三種類別都是形狀,就可以將形狀拉出來做成父類別。 *但一般來說,開發時會是要先預先定義好父類別,去評估子類別會要如何去使用。* ## 存取修飾詞 ### `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`。
{"metaMigratedAt":"2023-06-15T20:29:31.966Z","metaMigratedFrom":"Content","title":"繼承","breaks":false,"contributors":"[{\"id\":\"bf8a189c-f841-4d77-86e1-614bb567075f\",\"add\":3722,\"del\":377}]"}
Expand menu