owned this note
owned this note
Published
Linked with GitHub
---
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
