---
# System prepended metadata

title: NCKU_Java_C2
tags: [NCKU_PD2]

---

## polymorphism
* 編譯時多型(靜態) **Method Overloading**
    同一個class可以有多種同名method，但參數列表必須不同（==參數類型、個數或者參數的順序不同==）。
* 運行時多型(動態) **Method Overriding**
    在子類別的覆寫
## super 關鍵字
如果要調用已經被子類別override的父類別method時，有兩種方式:
* 在子類別的method中直接調用父類別的方法:==在子類別class中的method中使用super==
* 顯式轉型（Casting）到父類別類型
```=java=
class Parent {
    void display() {
        System.out.println("This is Parent class");
    }
}

class Child extends Parent {
    @Override
    void display() {
        System.out.println("This is Child class");
    }

    void callParentDisplay() {    //在method裡
        super.display(); // 使用 super 調用父類的 display 方法
    }
}

public class TestCasting {
    public static void main(String[] args) {
        Child child = new Child();

        // 直接調用子類別的 display 方法
        child.display(); // 輸出: This is Child class

        // 通過子類別調用父類別的 display 方法
        child.callParentDisplay(); // 輸出: This is Parent class
        
    }
}
```
**顯式轉型:(down-casting)**
```=java=
class Animal{
    public void makesound(){
        System.out.println("Some generic sound");

    }
}
class Dog extends Animal{
    
    public void makesound(){
        System.out.println("Dog sound");

    }

    public void fetch(){
        System.out.println("Dog fetch!!");
    }

}
public class superts {
    public static void main(String[] args) {
        System.out.println("yy");
        Animal mypet=new Dog();    //隱性轉型
        mypet.makesound();
        mypet.fetch();    //error!!!   

    }
}

```
```
mypet 並不能調用Dog特有的方法fetch()
想調用特有方法必須顯性轉型到Dog
 if (myAnimal instanceof Dog) {
            Dog myDog = (Dog) mypet;    //顯式轉型
            myDog.fetch(); 
        }
```
**隱性轉型:(up-casting)**
```=java=
class animal{

}
class cat extend animal{
	public void makesound(){System.out.println("meow");}
}
class dog extend animal{
	public void makesound(){System.out.println("bark");}
}

public static void main(){
	animal mypet = new animal();    
	animal mypet = new cat();    //將cat物件向上轉為animal
	animal mypet = new dog();    //=>先知道牠是animal，但實際上是animal,cat or dog

	mypet.makesound();=>看實際上是什麼動物而用該類別的method
}

```
```

```
:::danger
▲==只能使用繼承鏈共同有的method==，假設dog class有別的method，則無法調用。因為本質上mypet 還是一個animal class的物件。
=>調用animal 的makesound()，沒想到它發出了狗叫，但會不會做其他dog的method則不知道。
:::
:::info
隱性轉型:一開始不知道要new什麼物件，依使用者的輸入而定，先從parent的角度去看一個obj
:::




## instanceof 關鍵字
>::::success
>instanceof是一個關鍵字，not method!!!，用於檢查一個物件是否屬於特定的==類別==或==其子類別==。
>回傳一個布林值。
>::::
```=java=
class Animal { }

class Dog extends Animal { }

public class Main {
    public static void main(String[] args) {
        Animal myAnimal = new Animal();
        Dog myDog = new Dog();

        System.out.println(myAnimal instanceof Animal); //myAnimal屬於Animal的類別嗎>true
        System.out.println(myDog instanceof Animal); //myDog屬於Animal的子類別嗎>true
        System.out.println(myAnimal instanceof Dog); //False
    }
}
```
也可以用來檢查物件是否有實現某個interface
```=java=
interface animal{
    void eat();
    void drink();
}

class birds implements animal{
    public void eat(){
        System.out.println("ate something");
    }
    public void drink(){
        System.out.println("drank something");
    }
}
class toy_birds{
    
}
public class basic {
    public static void main(String[] args) {
       birds that_bird =new birds();
       toy_birds this_bird=new toy_birds();
       System.out.println(that_bird instanceof animal);//true
       System.out.println(this_bird instanceof animal);//false
    }
    
}

```
::::info
A instanceof B : A是B的實例嗎? >>>true/false
::::


## Constructor建構子
>::::success
>在Java中，建構子是一種特殊的方法，用於初始化新創建的物件。==它的名稱必須與類別名稱完全相同==，並且不返回任何類型（包括void）
>::::
```=java=
public class Person {
    String name;
    int age;

    // 第一個 constructor
    public Person(String name) {
        this.name = name;
        this.age = 0; // 預設年齡為 0
    }

    // 第二個 constructor
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
```
在new物件的時候會依照建構子預設的參數來初始化物件的attributes
<font color="#f00">一個class可以有多個建構子。</font>
```
Person person1 = new Person("Alice"); // 調用第一個 constructor，age 將設為預設值 0
Person person2 = new Person("Bob", 25); // 調用第二個 constructor，age 將設為 25

```
:::danger
當一個class有constructor時，繼承它的class也要有相同的constructor!!
:::




---


:::warning
###  **review:**
在Java中，方法的參數傳遞方式可分為 "Call by Value" 和 "Call by Reference"（或者說，都是Call by Value)。
#### **call by value:**
primitive type的資料類型都是傳遞它的實際value，可以在method中自由進行修改而不會影響到原來的值。
```=java=
public class basic {
    public static void main(String[] args) {
        int a=10;
        int b=a;
        System.out.println(b-4); //6
        System.out.println(a);    //10
    }
}
```
==基本數據類型的變數在賦值或傳遞時會創建新的資料實體的copy。==

#### **call by reference:**
"Call by Reference" 意味著我們將一個變數的Reference傳遞給方法。因此，如果方法修改了這個參照參照的物件，那麼這個改變會反映到原來的物件上。這種方式適用於物件。
```=java=
class MyObject {
    int value;
}

void updateValue(MyObject obj) {    //傳入的是該物件的ref
    obj.value = 55;    //那個address的.value值改變為55
}

public static void main(String[] args) {
    MyObject obj = new MyObject();
    obj.value = 22;
    System.out.println("Before: " + obj.value);  // Output: Before: 22
    updateValue(obj);
    System.out.println("After: " + obj.value);  // Output: After: 55
}

```
==but當我們嘗試**在method中**改變reference本身（例如，使它參照到另一個物件）時，這個改變不會反映到原來的物件上。==
```=java=
class my_pet{
    String name;
    my_pet(String name){
        this.name=name;
    }
    
}
public class basic {
    static void change_dog(my_pet Dog){
        Dog = new my_pet("bob");
    }
    public static void main(String[] args) {
       my_pet my_dog=new my_pet("rogger");
       System.out.println(my_dog.name);//rogger

       change_dog(my_dog);
       System.out.println(my_dog.name);//rogger
    }
    
}
//my_dog.name值不變
```

比較
```=java=
class my_pet{
    String name;
    my_pet(String name){
        this.name=name;
    }
}
public class basic {
    
    public static void main(String[] args) {
       my_pet my_dog=new my_pet("rogger");
       System.out.println(System.identityHashCode(my_dog));//hash code 1421795058
       System.out.println(my_dog.name);//rogger

       my_pet another_dog=new my_pet("bob");
       System.out.println(System.identityHashCode(another_dog));//hashcode 1555009629

       my_dog=another_dog;
       System.out.println(my_dog.name);//bob
       System.out.println(System.identityHashCode(my_dog));hash code 1555009629
    }
    
}
my_dog的reference指向another_dog，所有my_dog.name的值會是"bob"
```
::::info
假設我把call by reference先當成是call by value，value的值是那個address，那這個value傳遞到method中就會呼應前面primitive type的情況，value是沒辦法被更改的，所以無法改變參數value(reference的值)。
::::






## Java Dynamic Binding
::::success
>### 定義
>
>在Java中，動態綁定（Dynamic Binding）是一種在運行時確定物件方法調用的機制。這意味著當你調用一個物件的方法時，被調用的方法版本（子類別或父類別中的方法）是在程序運行時基於物件的實際類型決定的，而不是在編譯時。這是Java多型的核心。

::::info
簡單來說就是依照我做的動作而有不一樣的結果
::::
```=java=
class Animal {
    void eat() {
        System.out.println("Animal is eating");
    }
}

class Dog extends Animal {
    @Override
    void eat() {
        System.out.println("Dog is eating");
    }
}

public class TestDynamicBinding {
    public static void main(String[] args) {
        Animal myAnimal = new Dog();
        myAnimal.eat(); // Prints "Dog is eating"
    }
}

```
 雖然我的<font color="#f00">myAnimal</font>是用<font color="#f00">Animal</font> class創建，但我new出來是<font color="#f00">Dog</font>物件，所以<font color="#f00">myAnimal</font>是使用<font color="#f00">Dog</font>的已經被覆寫的method。
 ```
 @Override
    void eat() {
        System.out.println("Dog is eating");
    }
```
同樣
```=java=
class Animal {
    void eat() {
        System.out.println("Animal is eating");
    }
}

class Dog extends Animal {
    @Override
    void eat() {
        System.out.println("Dog is eating");
    }
}

class Cat extends Animal{
    @Override
    void eat(){
        System.out.println("cat is eating");

    }
}

public class dynamic_bounding {
    public static void main(String[] args) {
        if(args[0].equals("Dog")){
            Animal myAnimal = new Dog();
            myAnimal.eat(); // Prints "Dog is eating"
        }
        else{
            Animal myAnimal=new Cat();
            myAnimal.eat();
        }
        
    }
}

```
實際物件為何由args[0]輸入而決定。

## this.
::::success
>在Java中，this是一個關鍵字，用於參照當前物件，即正在被方法或建構子呼叫的物件。它有以下幾種用途
><font color="#f00">●參照物件的實例變數：當方法的參數變數/區域變數與物件的Member變數名稱相同時，可以使用this來參照物件的實例Member變數。</font>
><font color="#f00">●呼叫物件的其他建構子：在一個建構子裡，你可以使用this()來呼叫物件的其他建構子></font>

><font color="#f00">●作為當前物件reference的回傳：你可以使用this來回傳當前物件的reference。</font>

::::




```=java=
class Box {
    private int width, height, depth;

    // constructor，使用this區分實例變數和constructor參數
    public Box(int width, int height, int depth) {
        this.width = width;
        this.height = height;
        this.depth = depth;
    }

    // 設置尺寸的方法，使用this區分實例變數和方法參數
    public void setDimensions(int width, int height, int depth) {
        this.width = width;
        this.height = height;
        this.depth = depth;
    }

    // 使用this返回當前類的實例
    public Box getSelf() {
        return this;
    }

    // 顯示尺寸的方法
    public void displayDimensions() {
        System.out.println("Width: " + width + ", Height: " + height + ", Depth: " + depth);
    }
}

public class TestThis {
    public static void main(String[] args) {
        Box myBox = new Box(10, 20, 30);
        myBox.displayDimensions();  // 輸出: Width: 10, Height: 20, Depth: 30

        // 使用setDimensions方法重新設置尺寸
        myBox.setDimensions(50, 60, 70);
        myBox.displayDimensions();  // 輸出: Width: 50, Height: 60, Depth: 70

        // 使用this返回當前類的實例
        Box anotherBox = myBox.getSelf();
        anotherBox.displayDimensions();  // 輸出: Width: 50, Height: 60, Depth: 70
    }
}
```
```=java=4
// constructor，使用this區分實例變數和constructor參數
    public Box(int width, int height, int depth) {
        this.width = width;
        this.height = height;
        this.depth = depth;
    }
//多加以下
    public Box(){
        System.out.println("hellow");//這行會error!!!!  
        this(width=1,height= 1,depth=1);
        system.out.println("hellow");//要在constructor後
    }

```
呼叫同名Box的建構子並賦值1,1,1
::::danger
- 如果沒有this.，建構子參數指向local var(local優先)，有this.才是指到該物件的lnstance var
- 物件的constructor一定要先寫(放在最前面)(先初始化)，才能進行其他宣告
::::

## interface 用法
::::success
它是這些類別的公共==抽象方法==的集合。當一個類別實現了某個Interface，它會被要求提供Interface中所有方法的具體實現（implementation）。
Interface的主要用途：

- 實現抽象：提供了一種機制，用於指定一組必須由實作此interface的類別來實現的方法。
- 實現多重繼承：Java不支持多重繼承（一個類別有多個父類別），但通過實現多個Interface，一個類別可以”類似”繼承了多個Interface的特性。
::::
**usage:**
```
interface interface_name{
    method() //抽象方法只有聲明
}

class name importments interface_name{

}
```
```=java=
// 定義Interface Vehicle
interface Vehicle {
    // Interface中的抽象方法 move
    void move();
}

// Car 類別實現 Vehicle Interface
class Car implements Vehicle {
    // 實現 move 方法
    public void move() {
        System.out.println("Car is moving");
    }
}

// Bicycle 類別實現 Vehicle Interface
class Bicycle implements Vehicle {
    // 實現 move 方法
    public void move() {
        System.out.println("Bicycle is moving");
    }
}

public class TestInterface {
    public static void main(String[] args) {
        // 創建一個 Vehicle 類型的reference指向 Car object
        Vehicle myCar = new Car();
        myCar.move();  // 輸出: Car is moving

        // 創建一個 Vehicle 類型的reference指向 Bicycle object
        Vehicle myBicycle = new Bicycle();
        myBicycle.move();  // 輸出: Bicycle is moving
    }
}
```
::::info
interface定義了哪些動作，importments它的class就一定要實現出那些方法
::::
```=java=
interface flyable{
    void fly();
    void getWings();
}
interface can_eat{
    void eat();
}
class bird importments flyable,animal{    //可以importments多個interface
    void fly...
    void getWings...
    void eat..
}

public static void main(){
    flyable birds =new bird(); 
}
```
interface 近似於parent class(我知道它會fly、會進食，但實際上不知道是什麼東西)



:question:	如果你要implements兩個interface，其中都需實作一個同名的method，會發生什麼事呢?
```
A:沒有error發生
```

### Interface Member Variable
```=java=
interface MyInterface {
    // 這是一個接口中的成員變數，它實際上是一個常數
    int MY_CONSTANT = 10;
}

class MyClass implements MyInterface {
    public void printConstant() {
        System.out.println("The constant is: " + MY_CONSTANT);
    }
}

public class TestInterface {
    public static void main(String[] args) {
        MyClass myObject = new MyClass();
        myObject.printConstant();  // 輸出: The constant is: 10
    }
}

```
在這個例子中，<font color="#AC19C9">MyInterface</font> Interface有一個成員變數<font color="#F7A004">MY_CONSTANT</font>。MyClass類實現了該介面，並可以訪問該常數。然而，它不能改變<font color="#F7A004">MY_CONSTANT</font>的值，因為它實際上真的是一個常數
::::warning
**recap**:
class 的member var是可以改變的，除非是FINAL
::::

## Abstract Class
::::success
抽象類別（Abstract Class）是一種不能直接實例化（不可透過new來生成物件）的特殊類別。我們可以通過繼承抽象類別並實現其抽象方法來創建新的類別。抽象類別通常被用來作為所有具有共同特性的類別的基礎。是一種介於Interface（不能提供任何實作內容）與class之間的物件機制。
### 特點

- **抽象方法（abstraction method)**：抽象類別可以包含一個或多個抽象方法。抽象方法是一種只有聲明沒有實現的方法，它的實現由子類別提供。
- **實例方法(instance method)**：除了抽象方法外，抽象類別也可以包含實例方法。這些方法可以有實現，子類別可以選擇覆寫或直接使用它們。
- **不能直接實例化**：我們不能直接使用 `new` 關鍵字來創建抽象類別的實例。然而，我們可以使用抽象類別類型的reference來引用子類別的實例。
::::
```=java=
// 定義一個抽象類別 Animal
abstract class Animal {
    private int age;
    //static 
    private static int size;
    //Final
    Final int number;
    // 抽象方法 sound
    abstract void sound();
    //實例方法 
    void make_noise();
    //建構子
    public Animal(int age,int size){
        this.age=age;
    }
}

// Dog 類別繼承 Animal 抽象類別
class Dog extends Animal {
    public Dog(int age, int size) {
        super(age, size);    //呼叫parent class的建構子
    }
    // 實現 sound 方法
    public void sound() {
        System.out.println("Dog says: Woof Woof!");
    }
}

public class TestAbstractClass {
    public static void main(String[] args) {
        // 創建一個 Dog
        Dog myDog = new Dog();//Dog class 創建出mydog物件
        myDog.sound();  // 輸出: Dog says: Woof Woof!
        
        Animal dog=new Dog();//abstrct class 也可以，實際上是Dog的物件
        dog.sound();

    }
}

```
::::info
abstract class跟interface很像，都可以僅聲明一些method，到被extand/importments時再被實現。
這樣，我們就可以在不知道實際類別的情況下，通過一個 Animal 參照來調用 sound() 方法，這是多型的一種體現。
::::


:question:想想看，一個abstract class能不能被另一個abstract class繼承？ 
```
yesss!!
```

## inner class
::::success
Inner Class是一種定義在另一個類別內部的類別。這種機制允許我們將一些相關的類別組織在一起，讓程式碼更加整潔且易於維護。內部類也可以訪問其外部類別的成員（包括private member data）。
::::
```=java
class OuterClass {
    private String myField = "Hello, World!";

    class InnerClass {
        void printMyField() {
            // 內部類可以訪問外部類的成員
            System.out.println(myField);
        }
    }
```
inner class可以訪問outer class的member，即使它是private(因為還是同屬於outer class以內
```=java=
class OuterClass {
    private String myField = "Hello, Outer World!";

    class InnerClass {
        private String myField = "Hello, Inner World!";

        void printMyField() {
            // 內部類別讀取自己的變數
            System.out.println(myField);

            // 內部類別讀取外部類別的變數
            System.out.println(OuterClass.this.myField);//
        }
    }

    void testInnerClass() {
        // 創建內部類別的實例
        InnerClass myInner = new InnerClass();
        myInner.printMyField();
    }
}

public class TestInnerClass {
    public static void main(String[] args) {
        // 創建外部類的實例
        OuterClass myOuter = new OuterClass();
        myOuter.testInnerClass();
        // 輸出: Hello, Inner World!
        // 輸出: Hello, Outer World!
    }
}

```
如果inner class有自己的local member，那要存取outer class的member且同名時
使用
- 外部類別名.this.變數名  
- 外部類別名.this.方法名()

來進行訪問
::::warning
**tips**
如果內部類別和外部類別有同名的變數或方法，內部類別會默認訪問其自身的變數或方法。
::::
# 補final

::::warning
**recap:**
- public:可以被所有package，所有class 訪問
- protected:只能在同個package內，但如果別的package有extends該class的子類別的話，也可以訪問
- default(package-private):嚴格限定在同個package
- private:只能在同個class之內訪問

::::
![image](https://hackmd.io/_uploads/HyjowvTlR.png)
[來源](https://blog.csdn.net/yangbodong22011/article/details/49721691)

## Wrapper classes


| primitive type | wrappered class | 
| -------- | -------- | 
| boolean  | Boolean     | 
| byte     | Byte
| int      |Integer
| double   |Double
| float    |Float
| long     |Long
| short    |Short
| char     |Character

::::info
primitive type必須要包成object(wappered class)才能使用一些好用的方法
像是ArrayList,Hashmap就只能放object
::::

### autoboxing/autounboxing:
在 J2SE 5.0 之後提供了自動裝箱的功能
```
Integer num=5;    //直接宣告不需要寫出new一個object
```

```=java=
public class TestThis {
    public static void main(String[] args) {
      int original_num=10;
      Integer boxed_num=original_num;    //auto-boxing
      System.out.println(boxed_num+5);    //auto-unboxing


      Integer boxed_num2=5;    //auto-boxing
      int original_num2=boxed_num2;    //auto-unboxing
      System.out.println(original_num2);

    }
}

```
::::danger
### Auto-boxing/Auto-unboxing的使用風險:
```=java
Integer integerObject = null;
int i = integerObject;  // 會拋出NullPointerException
```
integerObject=null 
auto_unboxing成primitive type時，變成primitive type沒有賦值的error。

::::

```=java=
Integer a = 1000;
Integer b = 1000;

Integer c=50;
Integer d=50;

System.out.println(a == b);  // 輸出 false
System.out.println(c == d);  // 輸出 true

```
a&b根據我們所知道，個別創立新物件，address不同，所以印出false
但c&d會印出true???
::::success
對於介於 -128 至 127之間的整數，Java 會自動將其緩存(caching)，所以當我們創建該範圍內的 Integer 物件時，Java 會直接從緩存中取得物件，而非創建新的物件。
::::
::::warning
**tips:**
用.equals()可以比較物件的value，not address
::::

::::success
既然都有了wrapper class，那為什麼java不就不要有primitive type data，都用wrapper class就好？

這是因為基本型別（Primitive Type）的效能優於封裝類別（Wrapper Class）。基本型別直接儲存值，而封裝類別則儲存一個物件，該物件包含了實際的值。因此，存取基本型別通常比存取封裝類別更快，且佔用的記憶體空間也較小。

::::


