## 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之內訪問
::::

[來源](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)。基本型別直接儲存值,而封裝類別則儲存一個物件,該物件包含了實際的值。因此,存取基本型別通常比存取封裝類別更快,且佔用的記憶體空間也較小。
::::