--- title: Java(下) description: Java 作為一種廣泛應用的程式語言,在後端開發、行動應用與企業級系統等等領域占有重要地位。物件導向是一種靈活,強調「物件」與「類別」關係的程式設計模式,能夠提升程式的擴展性、可讀性。本次課程將介紹物件導向的核心概念,如類別、實例、繼承等。並透過各種物件導向相關的關鍵字,幫助學員學習在Java中使用物件導向設計程式。 tags: - 社課 - 共筆 - 113 學年 --- :::success # Java(下) **時間:** 2025/03/27(星期四)18:00~20:00 **地點:** 挺生大樓 A3-200 教室 **簡報:** [連結](https://slides.com/speedcubin/deck-850388#/18) **Slido:** [連結](https://app.sli.do/event/sR3MTgHAymt6LnCLChXczS) ::: > **簡報:** > https://slides.com/speedcubin/deck-850388#/18 > **Youtube :** > https://www.youtube.com/@speedcubing-top ## Class(類別) 可說是物件藍圖 由non-static-member決定(static屬於類別本身) 物件是類別的實例 ### 宣告成員變數(Field) 成員變數由三個部分組成 - 修飾符(Ex:存取修飾符) - 資料型態 - 變數名稱 基於物件導向的 **封裝(Encapsulation)** 精神,把成員變數設為 private, 只將需要調用的方法 public 使程式碼更好維護。 ## Object(物件) - 建立物件 new ClassName(); - 比較物件 a == b a.equals(b) Objects.equals(a,b) - 使用物件的成員變數 在class內使用: fieldName 直接用名字存取 在class外使用: objectRefernce.fieldName ```java= class Point { public int x; public int y; public void print() { // 可以直接用fieldName System.out.println("(" + x + ", " + y + ")"); } } public class Main { public static void main(String[] args) { Point p1 = new Point(); // objectReference.fieldname p1.x = 100; int x = p1.x; System.out.println(p1.x); } } ``` ## 參考 Java的型別分為兩大類: - 基本型別(Primitive Data Types) - 例如:數值、布林 - 參照型別(Reference Data Types) - 資料放在另外配置的空間裡 - 例如:字串、陣列、**物件**等... ```java= Point p = new Point(); // p 參考new出來的物件 // 口頭上說 p 即為某物件 Point p2 = p; // p2 參考 p 參考的物件 // 白話文: p2 和 p 相同,只是名字不一樣 p2.x = 200;// 故改動 p2 會改動到 p ``` > (指向)同個記憶體空間就是同個物件 > 所以基本類別不會改變原本的值 > [name=阿文] ```java= int i = 1; // i 值是 1 int j = i; // j 值是 i 的值 // i 的記憶體空間跟 j 不同,當然不會改動到 j 的值 j = 30; // j 值是 30 , i 值是 1 ``` ## Access Modifiers(存取修飾符) - default(都不加) - 只給自己和同package用 - private - 只給**自己**用 - protected - 只給**自己**和自己的**子class**,同package用 - public - 給**任何**地方使用 ## Method ### 宣告Method ```java= modifiers return-type method-name(parameter-list) { // method body } // 像是Java的入口方法: public static void main(String[] args) { } ``` 參數名不可重複,如果沒有參數,**括號內空白**就好。 ### Method Signature(方法簽章/方法簽名) Method Name & Parameter Types 來**唯一**標示一個方法,如果回傳值和修飾符不一樣也不行。 一個class內不能有同樣Method Signature的Method。 例如: ```java= public static int sum(int i, int j) { return i + j; } /* //Method Signature sum(int, int) */ ``` ### Overloading(重載/多載) 如果有多個方法使用名字,但是Method Signture不同(參數數量不同、參數資料型態不同),即為Overloading。 ### 使用類別內的方法 > 簡報應該錯了?(物件->類別) 在class內使用: methodName(argumentList); 直接用名字存取 在class外使用: objectRefernce.methodName(argumentList); 方法被傳入**基本型別**時,是**傳值(passed by value)**, 同樣,原本的值**不會**被方法改變。 方法被傳入**參考型別**時,是**傳參(passed by Reference)**, 同樣,原本的物件**會**被方法改變。 但**不能**直接使用new來更改原本的參考。 ## Constructor(建構子) Constructor不屬於Method。 class會有constructor, 在建立object時被呼叫。 - 必須與class同名 - 沒有return-type - 可以寫多個constructor, 但參數不能一樣 - 如果沒有自己寫,會有預設的implict constructor ## this關鍵字 - this指的是目前的物件 - this不能放在static方法中 這樣你在同個Class裡面的Method的參數就可以與Field同名 ```java= class Point { public int x; public int y; public Point(int x, int y) { /* this就是指現在這個物件 也就是 剛剛new出來的物件 */ this.x = x; this.y = y; } } ``` 或是說想使用這個物件, 像是用於呼叫方法的參數 ## Static(靜態) 每個物件都共享同一個Field 加上static的變數也稱為Class Variable(類別變數) 不管class的物件有多少個,他都只有一個值,也就是與class有關聯,與物件無關。 > 優點:可以節省記憶體空間 > 為什麼叫做靜態? > 在程式載入記憶體的時候,跟著程式一起在記憶體中佔有空間。 > 也就是在物件被建立之前,static就先存在。 > 所以不能在static用this,因為沒有物件阿,當然不能用this > [name=阿文] 因此,在類別外使用類別(而不是物件本身)呼叫靜態成員變數是比較好的選擇。 ```java= public class Main { public static void main(String[] args) { // 正常在Class外使用 int count = Point.pointCount; // 強烈不建議 Point p = new Point(); int count = p.pointCount; } } ``` 以上同樣適用static的Method。 不需要物件就可以呼叫static method。 ### Constant(常數) static final用於定義常數 static:共用變數 final:變數的值不能被修改(**要在宣告時同時給值**) ## Extends(繼承) 用法:**Child** extends **Parent** **Child**會有**Parent**的成員。 **Parent** 稱為 **Child** 的 "superclass" (父類別) **Child** 稱為 **Parent** 的 "subclass" (子類別) 一個class**只能同時繼承**一個class 但是可以A繼承B , B繼承C, 這樣C會有A,B的成員 java.lang.Object 若class沒有繼承任何類別,那這個class會繼承Object **每個類別都會是Object的子類別。** 因此每個物件都可以有toString(), equals(), hashCode()等方法這些全部都是從Object繼承來的。 ### instanceof 可以來判斷一個instance(實例)是不是屬於某一個class/interface(child也行)的instance ```java= //MyPrinter extends Printer public class Main { public static void main(String[] args){ Printer s = new Printer(); MyPrinter v = new MyPrinter(); boolean b = s instanceof Printer; boolean b2 = s instanceof MyPrinter; boolean b3 = v instanceof Printer; boolean b4 = v instanceof MyPrinter; System.out.println(b); //true System.out.println(b2); //false System.out.println(b3); //true System.out.println(b4); //true } } ``` ### @Override Override(覆寫) 子類別繼承父類別時,會繼承父類別的方法 如果想要在子類別中,改寫從父類別繼承下來的方法: 直接寫一樣的方法簽章的方法 並且可以加一個@Override的註解(如果沒有Override會報錯) ### super 如果有override方法,但想用父類別原有的方法: super.methodName() ## Interface(介面) 可讓物件遵守了一個共同的「介面規範」 interface(介面) 可以說是一個Method Set template class 能 implements 多個 interface interface 能 extends 多個 interface ### Abstract Method(抽象方法) 定義:無Method Body的方法。 **必須在abstract class/interface裡面**。 Body會在implements的class被實作 ## Abstract Class(抽象類別) 被abstract修飾的class無法直接被實例化, 但可以被繼承。 如果有個子類別繼承某個abstract methods,子類別會實作所有父類別的abstract methods。 ### Abstract vs Interface - Abstract Class - 你的父子類別通常很有關係 - 你希望有些成員不是public - 你想宣告non-static或是non-final fields - Interface - 你的interface與class可以關係不大 - 你想指定某些class的行為, 但不在乎他是怎麼實作的 - 你想使用多重implement ## Anonymous Class(匿名類別) **希望一次性使用Class** 所以我們可以不直接寫子類別,直接new一個interface/abstract class,並且要實作方法。 new InterfaceOrAbstractClass(constructor param) {declaration}; ```java= interface IPrinter { void print(String s); } public class Main { public static void main(String[] args) { IPrinter v2 = new IPrinter() { @Override public void print(String s) { System.out.print("Interface : " + s); } }; // 在new的時候直接實作方法 v2.print("Hello"); // Interface : Hello } } ``` ### Lambda 如果Interface 的non-static方法只有一個 我們可以把傳統的Interface Anoymous Class改寫成: ```java= // 從這樣... new InterfaceName() { @Override public void methodName(param... ) { // do something } }; // 變這樣。 (param) -> { // do something } ``` ## Exception(例外) 當在方法執行時出了錯, 可能會生成一個**Throwable**物件,包含錯誤資訊。 丟擲例外之後,會嘗試在Call Stack(呼叫方法堆疊) **逆序**尋找一個能處理**Throwable**的throwable handler。 如果找到能處理的, 就好了。(繼續執行) 如果沒找到, 程序會結束。(強制終止) Throwable分成兩種: - Error: 比較不太會發生 - 像是OutOfMemoryError,StackOverflowError - Exception: 在程式中比較常遇到 - 像是NullPointerException,IOException - Exception中又分為Checked, Unchecked - Checked: 必須顯式處理的**Exception** - 在方法內要用try-catch處理, 否則要寫**throws** - Unchecked: - 有RuntimeException 與 Error(必為unchecked) ### Tree - Throwable: - Exception: - IOException - … - … - RuntimeException (Unchecked) - NullPointerException - … - … - Error: (Unchecked) - NoClassDefFoundError - OutOfMemoryError - … - … ### try-catch ```java= // 使用一個Exception Handler catch 多種Exception try { // code } catch (IOException | SQLException ex) { // 用同種方式處理兩種例外 } catch (OtherException ex) { } ``` 舉例:字串轉為整數(NumberFormatException) ```java= public static void main(String[] args) { String s = "hello"; try { int i = Integer.parseInt(s); System.out.println(i); } catch (NumberFormatException e) { e.printStackTrace(); // 印出錯誤訊息 } } ``` ### throws 如果method內可能有exception會出現,但是你不想要在此method處理,可以使用 throws 把可能出現的例外丟給上層call stack處理。 ```java= public static void main(String[] args) { try { connect("https://api.speedcubing.top"); } catch (IOException ex) { // } } public static void connect(String url) throws IOException { //可能遇到IOException throws 到 main 處理 new URL(url).openConnection(); } ``` ### Custom Exception 找一個Exception, 然後extends他, 完事。 - extends **Exeption**來製作Checked Exception - extends **RuntimeException**來製作Unchecked Exception ```java= // Custom NumberOutofRangeException class NumberOutofRangeException extends RuntimeException { } class NumberChecker { public static void check(int i, int low, int high) { if(i < low || high < i) { throw new NumberOutofRangeException(); } } } public class Main { public static void main(String[] args) { int i = 20; NumberChecker.check(i, 100, 200); //自訂怎麼樣是超出範圍 System.out.println(i); } } ``` ## 回饋表單 連結:https://forms.gle/YVwrLUxwYFvsjrFr6 ![回饋表單圖片](https://hackmd.io/_uploads/ByYCCoGa1x.png)