---
# System prepended metadata

title: NCKU_Java_C3
tags: [NCKU_PD2]

---

## static && final
### static
:::success
static關鍵字用於表示一個成員變數或者方法屬於類別本身，而不是類別的instance-level。這意味著，不論我們創建多少個類別的object，靜態變數都只有一份資料，所有objectobject共享該靜態變數。
:::
:::info
static :一開始就畫記憶體位，全部只有一份(class level)
non static:執行到才畫記憶體位址。
加上static後，只會在記憶體存在一份，所有的物件共用這一份。(class level
:::
```=java=
public class MyClass {
    private int nonStaticVariable;

    public static void staticMethod() {
        System.out.println(nonStaticVariable);  // 這行會導致編譯錯誤
    }
}

```
:::danger
=>class level(static)不能存取instance level(non-static)的method
=>instance level 可以存取class level (static)的method
:::


:question: 當staticMethod被調用時，nonStaticVariable可能還未被初始化？為什麼說"可能”呢？有什麼情況會已被初始化了呢？
```
ans:在調用之前已經有該class的物件被new出來，並透過物件的屬性調用
```
:::warning
### extra:
Java 的變數依照其存活時間長短分成下列四種:
**1. 類別變數 (Class Variables):**
* 在class 宣告static的變數，存活時間最長, 編譯時即配置記憶體存放於static區
* 有預設值


**2. 實體變數(Instant Variables):**
* 物件的屬性，沒有宣告static
* 於物件建立時產生, 存放於 heap 區, 只要物件未消滅皆可存取.
* 有預設值

**3. 方法變數 (Method Variables):** 
* method的參數、method內定義的變數
* 放在stack
* 無預設值
* ==屬於local variables==

**4. 區塊變數 (Local Variables):**
* 即 if, switch, for, while, do-while 等流程控制語法大括弧內所定義之變數
* 放在stack，只能在該語法區塊內存取，
```=java
for(int i =0...){
    dosomething
}

for(int i =1...){
    dosomething
}
```
* 無預設值
* ==屬於local variables==
::::
### final
:::success
final關鍵字用於表示一個變數是read-only的，如果一個變數被final修飾，那麼它只能被賦值一次，賦值後其值就不能再被改變。
:::
```=java
public static void main(String[] args) {
       final int X=5;
       X=10;    //error
    }
```
::::success
如果一個方法被final修飾，那麼它不能被子類別重寫（能被子類別繼承）。
::::
```=java
class Animal{
    final void makesound(){
        System.out.println("Some generic sound");
    }
    public void eat(){
        System.out.println("eat");
    }
}
class Dog extends Animal{
    
    public void makesound(){    //error
        System.out.println("Dog sound");
    }
}
```
:::success
如果一個類別被final修飾，那麼它不能被繼承。
:::
```=java
final class Animal{
    void makesound(){
        System.out.println("Some generic sound");
    }
    public void eat(){
        System.out.println("eat");
    }
}
class Dog extends Animal{    //error
    ....

}
```
## object(物件)
==java所有的物件都繼承自java.lang.Object (所有的class都繼承自java.lang.Object)==
### .equals()
:::success
在Java中，如果想要比較兩個物件是否完全相等，我們需要覆寫或實作 equals() 方法，而非使用 == 運算符號。
:::
:::warning
'= ='比較的是兩個物件的記憶體位值
'.equals()'比較的是兩個物件的內容

但,.equals()如果沒有經過覆寫，則會使用java.lang.Object(父類別)的.equals()，就跟'= ='一樣。
:::
```=java=
code
```
:::warning
**tips:**
我們在String中可以直接使用.equals()比較內容是因為在String class中已經對.equals()覆寫了。
![image](https://hackmd.io/_uploads/HyX-2wcZ0.png)
:::
[來源](https://blog.csdn.net/wwwwwwwl/article/details/75187869?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-1-75187869-blog-110070231.235^v43^pc_blog_bottom_relevance_base8&spm=1001.2101.3001.4242.2&utm_relevant_index=4)
### getclass()
::::success
這個方法用來取得該物件的 Class 物件，該 Class 物件代表了該物件的實際類別（class）
::::
```=java=
public static void main(String[] args) {
        String str = "Hello, world!";
        Class<?> strClass = str.getClass();
        System.out.println("The class of str is " + strClass.getName());
    }
//Class<?> 表示的是一個未知類型的 Class object。
```
```
output:
The class of str is java.lang.String

```
### clone()
:::success
在Java中，Object類別提供了一個clone()方法，可以用來創建並返回該物件的一個副本。這個方法預設提供的是shallow copy，稱之為淺層拷貝
:::
#### shallow 

如果是一個物件內的元素使用.clone()的話，則會複製該物件內元素的reference(ref 也是一種value)
```
review:在一個物件的屬性
    String name="zhang"; //'name'為'zhang'這個物件的reference
```
會被複製的便是'name'，但兩個name都指向同個物件"zhang"
物件"zhang"並沒有被複製。

![image](https://hackmd.io/_uploads/r1DsgxnZA.png)


[來源](https://blog.csdn.net/weixin_34334744/article/details/94113476?spm=1001.2101.3001.6650.2&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-2-94113476-blog-107779427.235%5Ev43%5Epc_blog_bottom_relevance_base8&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-2-94113476-blog-107779427.235%5Ev43%5Epc_blog_bottom_relevance_base8&utm_relevant_index=5)
```=java=
public class ShallowCopyExample {
    public static void main(String[] args) {
        // 建立原始二維陣列
        int[][] original = {{1, 2, 3}, {4, 5, 6}};

        // 創建原始陣列的淺拷貝
        int[][] copied = original.clone();

        // 輸出原始陣列和複製陣列的第一個元素
        System.out.println("Before modification:");
        System.out.println("original[0][0] = " + original[0][0]);
        System.out.println("copied[0][0] = " + copied[0][0]);

        // 修改複製陣列的第一個元素
        copied[0][0] = 100;

        // 再次輸出原始陣列和複製陣列的第一個元素
        System.out.println("After modification:");
        System.out.println("original[0][0] = " + original[0][0]);
        System.out.println("copied[0][0] = " + copied[0][0]);
    }
}
```
```
output:
Before modification:
original[0][0] = 1
copied[0][0] = 1
After modification:
original[0][0] = 100
copied[0][0] = 100       
```
:::info
'original' 跟'copied' 都指向{{1,2,3},{4,5,6}}這個二維陣列物件(同個address)
那從original去修改跟從copied去修改，都會造成共同的物件改變。
:::
:::danger
shallow並沒有new新的物件出來
再說一次，
String name="zhang";
int[][] original = {{1, 2, 3}, {4, 5, 6}};
等號右邊才是物件，左邊為ref
:::
#### deep copy

如果要連reference指向的物件都複製一份，稱為deep copy(深層拷貝)
要實現deep copy，就需要:
* 覆寫某個class 繼承自Object的.clone()方法
* 或是不覆寫，手動創立一個新物件
==共同點都是有新物件產生!!!==
![image](https://hackmd.io/_uploads/rJkbzlnZA.png)

```=java=
public class MyClass implements Cloneable {
    private int[] array;

    public MyClass(int[] array) {
        this.array = array;
    }

    // Getter for array
    public int[] getArray() {
        return array;
    }

    @Override
    public MyClass clone() {
        int[] clonedArray = array.clone(); // This line creates a copy of the array. It is a primitive-type array and clone() can returned a array like deep-copy
        return new MyClass(clonedArray); // new了一個新的物件，屬性相同，reference不同
    }
}

```
```=java=
public class DeepCopyExample {
    public static void main(String[] args) {
        // 建立原始二維陣列
        int[][] original = {{1, 2, 3}, {4, 5, 6}};

        // 創建原始陣列的深層拷貝
        int[][] copied = new int[original.length][];
        for (int i = 0; i < original.length; i++) {
            copied[i] = original[i].clone();
        }

        // 輸出原始陣列和複製陣列的第一個元素
        System.out.println("Before modification:");
        System.out.println("original[0][0] = " + original[0][0]);
        System.out.println("copied[0][0] = " + copied[0][0]);

        // 修改複製陣列的第一個元素
        copied[0][0] = 100;

        // 再次輸出原始陣列和複製陣列的第一個元素
        System.out.println("After modification:");
        System.out.println("original[0][0] = " + original[0][0]);
        System.out.println("copied[0][0] = " + copied[0][0]);
    }
}

```
```
output:
Before modification:
original[0][0] = 1
copied[0][0] = 1
After modification:
original[0][0] = 1
copied[0][0] = 100
```
:::info
因為兩個是分開的物件，所以改變不會互相影響。
:::


---




如果一個物件的元素是primitive type，則.clone()會複製它們的值並產生新物件。
```
int array[]={2,3,4};
int array2[]=array.clone();
System.out.println(array==array2);//false

```
:::success
<aside>
在Java中，物件元素是primitive type的clone()操作，會進行deep copy（深層拷貝），創建一個新的物件並複製所有的元素。

然而，對於Object[]陣列的clone()，則是shallow copy（淺層拷貝）。這是因為Object[]陣列的元素是reference型態，clone僅僅會複製這些reference，而不會複製reference所指向的物件。因此，原陣列和複製後的陣列中的元素會指向同一個物件。

</aside>
:::

:::danger
在使用.clone()的類別需要implements Cloneable:

    public class MyClass implements Cloneable {}

否則會有CloneNotSupportedException

Cloneable介面在Java中是一種標記性介面(marker interface)，它不包含任何方法，只是表明這個class的object可以被clone.
:::
:question: 在Java中，如果一個method被定義為private，請問它還可以被子類別override嗎
```
ans:不行，private在只能在同一個class存取，子類別無法override or inherit
```
:question: 那如果在子類別中定義了一樣的method name (argument也一樣)，會怎麼樣呢？
```
ans:不會報錯，會視作子類別的新方法，看new的物件是哪個class，就用哪邊的方法。
```