# JAVA 繼承 ###### tags: `Java` --- * 子類別繼承父類別,使用關鍵字【extends】 * 可以有很多個父類別,垂直繼承 :::success 舉例程式碼: :::spoiler ```java= package Ex11.MoreExtendDemo; /**多重繼承,爸爸的爸爸的爸爸~無限循環XD**/ //class 父類別 class CMath { public void getMax(int a, int b){ int bigNum; if(a>b) bigNum=a; else bigNum=b; System.out.println(a+ "與" +b+ "的最大數為" +bigNum); } } //class 子類別 class SonCMath extends CMath { //SonCMath繼承父類別CMath public void getFactorial(int a){ int ans = 1, i; System.out.print(a+ "! = "); for (i=1;i<a;i++){ System.out.print(i+ "*"); ans *=i; } ans *= a; System.out.println(a+ " = " +ans); } } class GrandSonCMath extends SonCMath { public void getFabonacci(int a){ int firstNum = 0, secondNum = 1; System.out.println("費氏數列:" +firstNum+ ", " +secondNum); int ans; for(int i=2;i<=a; i++){ ans = firstNum = secondNum; System.out.print(", " +ans); firstNum = secondNum; secondNum = ans; } } } //主程式 public class MoreExtendDemo { public static void main(String[] args) { GrandSonCMath math2 = new GrandSonCMath(); math2.getMax(10,20); //呼叫繼承祖父類別的方法 math2.getFactorial(5); //呼叫繼承父親的方法 math2.getFabonacci(10); //呼叫子類別的方法 } } ``` ::: --- ## Override 複寫 當使用到這個方法時,子類別的方法會覆蓋掉父類別同名稱的方法,也就是說程式會選擇子類別的方法來執行。 :::success 舉例 Override 程式碼: :::spoiler ```java= package Ex11.OverrideDemo; //class 父類別 class CMath { public void getMax(int a, int b){ int bigNum; if(a>b) bigNum=a; else bigNum=b; System.out.println(a+ "與" +b+ "的最大數為" +bigNum); } } //class 子類別 class SonCMath extends CMath { //SonCMath繼承父類別CMath public void getMax(int a, int b){ if(a>b){ System.out.println(a+ "和" +b+ "的最大數為" +a); }else if(a<b){ System.out.println(a+ "和" +b+ "的最大數為" +b); }else{ System.out.println(a+ "和" +b+ "一樣大"); } } } //主程式 public class OverricdDemo { public static void main(String[] args) { CMath math3 = new CMath(); math3.getMax(20, 20); //使用父類別的方法 SonCMath math4 = new SonCMath(); math4.getMax(20, 20); //子類別覆蓋了父類別的方法 } } ``` ::: --- ## 預設建構式 * 就是建立好繼承的class,裡面的程式會預設執行 * 依序由最頂層的父層開始執行(年紀最大的長輩說話子孫都要聽XD) :::success 舉例 預設建構式 程式碼: :::spoiler ```java= package Ex11.constructorExtend; //預設建構式(會預設執行的程式,由最上層的類別先執行 //祖父層 class CMath { protected int a = 1; CMath(){ System.out.println("a = " +a); } } //父層 class SonCMath extends CMath { protected int b = 2; SonCMath(){ System.out.println("a+b=" +(a+b)); } } //子類別 class GrandSonCMath extends SonCMath { protected int c = 4; GrandSonCMath(){ System.out.println("a+b+c=" +(a+b+c)); } } //主程式 public class ConstructorExtend { public static void main(String[] args) { new GrandSonCMath(); //執行子類別,又因為子類別繼承了父層與祖父層, // 所以會預設自動執行繼承內的程式 } } ``` ::: --- ## Final * 當使用final來宣告一個常數時,記得一定要同時給予這個常數初值(常數的值不能被變更的) * final如果應用在方法成員上,就表示這個方法不可以被子類別覆寫。 * 如果在class之前加上final時,則表示該類別無法被繼承。 :::success 舉例 Final 程式碼: :::spoiler ```java= package Ex11.Final; //當使用final來宣告一個常數時,記得一定要同時給予這個常數初值(常數的值不能被變更的) //final如果應用在方法成員上,就表示這個方法不可以被子類別覆寫。 //如果在class之前加上final時,則表示該類別無法被繼承。 final class Cdog { //無法被繼承 int weight; } class Ccar { //private final int speed; //這樣寫是錯的,要給初始值 private final int speed = 120; public final void showBigSpeed(String s){ System.out.println(s+ "最大速度是" +speed+ "公里!"); } } class PiliCcar extends Ccar { /*父類別showBigSpeed方法有設定final,所以子類別無法覆寫 public void showBigSpeed(String s){ System.out.println(s+ "最大速度是" +speed+ "公里!"); } */ } public class FinalDemo1 { public static void main(String[] args) { Ccar car1 = new Ccar(); car1.showBigSpeed("car1"); PiliCcar car2 = new PiliCcar(); car2.showBigSpeed("car2"); } } ``` ::: --- ## Static 的限制 * static方法成員只可以使用static資料成員,和呼叫static方法成員。 * 父類別如有設定static方法,子類別不能使用相同的static方法(不可覆寫) --- ## abstract抽象 * abstract關鍵字宣告 * 抽象方法必須用abstract關鍵字宣告,其修飾子不能為private * 抽象類別被子類別繼承後,其抽象方法必須被子類別覆寫(override)。即子類別必須重新定義該抽象方法,且方法內要有實作敘述區段,如此抽象方法方能具體化。 * 抽象類別無法建立物件實體,其建構式與一般方法成員若要由子類別來呼叫,則須使用super()敘述來呼叫。 :::success 舉例 abstract 程式碼: :::spoiler ```java= package Ex11.AbstractDemo; abstract class Ccar { int speed; public abstract void addSpeed(int s); public static void showData(){ System.out.println("所有車子都可以加速!!\n"); } } class PiliCar extends Ccar { public void addSpeed(int s){ System.out.println("霹靂車目前速度:" +speed); speed += s; System.out.println("霹靂車 加速後:" +speed); } } //繼承抽象類別Ccar,必須實作Ccar類別的addSpeed的抽象方法 class BMWCar extends Ccar { public void addSpeed(int s){ System.out.println("BMW目前速度" +speed); speed += s; if (speed <= 200){ System.out.println("BMW 加速後:" +speed); }else{ System.out.println("BMW最大速度 200 無法再加速了"); } } } //主程式 public class AbstractDemo { public static void main(String[] args) { Ccar.showData(); //呼叫Ccar抽象類別的showData()靜態方法 PiliCar car1 = new PiliCar(); car1.addSpeed(150); car1.addSpeed(120); System.out.println(); BMWCar car2 = new BMWCar(); car1.addSpeed(150); car1.addSpeed(120); // Ccar car3 = new Ccar(); //出現錯誤,抽象類別無法產生實體 } } ``` ::: --- ## Interface 介面 * 定義介面的時候,必須使用保留字interface,方法內的主體一定是空的程式碼 * 引用的資料成員則必須給予初值,實作介面必須使用implements保留字 ![](https://i.imgur.com/JharvhX.png) ![](https://i.imgur.com/ZYdzspd.png) --- ## Interface & extends 介面繼承 :::success 舉例 介面繼承 程式碼: :::spoiler ```java= package Ex11.InterFaceDemo2; interface IMove { public void showSpeed(); } interface IFly { public void showFly(); } interface IAnimal extends IMove, IFly { //IAnimal 介面繼承IMove, IFly public void showAttack(); } class CAirPlane implements IMove, IFly { //實作IMove, IFly 介面 public void showSpeed(){ System.out.println("飛機每一次加速,會增加20公里!"); } public void showFly(){ System.out.println("飛機的最快移動方式,就是飛行!"); } } //實作IAnimal介面,因為IAnimal繼承了IMove, IFly ,所以方法有三個 class CSitrYaMan implements IAnimal { public void showSpeed(){ System.out.println("賽亞人每一次加速,會增加30公里!"); } public void showFly(){ System.out.println("賽亞人飛的速度比光速還快!"); } public void showAttack(){ System.out.println("賽亞人攻擊會使用龜派氣功!"); } } //主程式 public class InterFaceDemo2 { public static void main(String[] args) { CAirPlane air1 = new CAirPlane(); //用CAirPlane建立air1物件 air1.showSpeed(); air1.showFly(); System.out.println(); CSitrYaMan man1 = new CSitrYaMan(); //把class CSitrYaMan製作成物件man1 man1.showSpeed(); man1.showFly(); man1.showAttack(); } } ``` ::: :::warning 小知識: \t 在同一个缓冲区内横向跳8个空格 ::: --- ## 以介面實作多型 * 子類別已繼承父類別,即無法再繼承抽象類別(Java為單一繼承) * 使用介面來達成多型,透過介面來達成多型的寫法和抽象類別大同小異。 --- ## 套件繼承 * 引用不同套件需在最上方宣告<span class="code1">import 某某package名稱;</span> * 可以import 多個套件的類別。 ![](https://i.imgur.com/mlekqvn.png) ![](https://i.imgur.com/ORVFWWH.png) :::success 舉例 套件繼承關係 程式碼: :::spoiler ```java= package Ex11.SelfPackage; import Ex11.OtherPackage.Other; //引用外部Package public class Self { public static void main(String[] args) { //同一套件(The same package) Another obj_a = new Another(); obj_a.show_a(); //預設default (繼承:可 , 使用:可) obj_a.show_b(); //public (繼承:可 , 使用:可) obj_a.show_c(); //protected (繼承:可 , 使用:可) //obj_a.show_d(); //private (繼承:不行 , 使用:不行) System.out.println(); //不同套件(different package) Other obj_o = new Other(); //obj_o.show_a(); //預設default (繼承:不行 , 使用:不行) obj_o.show_b(); //public (繼承:可 , 使用:可) //obj_o.show_c(); //protected (繼承:可 , 使用:不行) //obj_o.show_d(); //private (繼承:不行 , 使用:不行) } } ``` ::: --- <!-- :::success 舉例程式碼: :::spoiler ```java= ``` ::: --> --- <span class="code1"></span> <style> h2 { color: #2383B8; } h3 { color: #1AA340; } h4 { color: white; background-color: #2383B8; padding:8px; } .code1 { padding: 2px 4px; font-size: 90%; color: #c7254e; background-color: #f9f2f4; border-radius: 4px; font-family:'Fira Code'; } .code { padding: 2px 4px; font-size: 90%; font-family:'Fira Code'; } </style>