[toc] https://docs.oracle.com/javase/tutorial/java/javaOO/objectcreation.html https://docs.oracle.com/javase/tutorial/java/javaOO/usingobject.html # instance (實例), 或稱Object (物件) ## 建立物件 Class提供了建立物件的藍圖, 因此, 你可以從class建立object. 寫法: ```java new ClassName(); ``` 如下面的範例,我建立了一個"Point"的類別 並且用new建立三個Point object Example: ```java= class Point { public int x; public int y; } public class Main { public static void main(String[] args) { new Point(); //建立了object Point p1 = new Point(); // 建立了object, p1參考它 Point p2 = new Point(); // 建立了object, p2參考它 System.out.println(p1 == p2); // false } } ``` ### 比較物件 - `a == b` 比較兩者是不是同一個物件。 - `a.equals(b)` 如果類別有@Override equals方法, 那就是用他寫的方法, 否則預設是`==` - `Objects.equals(a, b)` 等同於 ```java (a == b) || (a != null && a.equals(b)) ``` **什麼時候用什麼?** 比較是不是同個物件, 用`a == b` 比較內容值, 並且確定`a != null`, 用`a.equals(b)` 比較內容值, 並且不確定`a != null`, 用`Objects.equals(a, b)` 上面範例, 因為是不同的Point instance, 使用==比較會是false。 但是因為我也沒有@Override equals, 所以用.equals還是一樣。 ## 使用物件內的成員 你建立了物件, 你可能想要使用它, 像是讀寫field的值, 或是呼叫一些方法。 --- ### 在class內使用class的field 可以直接用名子存取。 ``` fieldName ``` ### 在class外使用class的field ``` objectReference.fieldName ``` Example: ```java class Point public int x; public int y; public void print() { System.out.println("(" + x + ", " + y + ")"); // 可以直接讀取到 x 跟 y field. } } public class Main { public static void main(String[] args) { Point p1 = new Point(); p1.x = 100; // objectReference.fieldname p1.y = 200; int x = p1.x; // objectReference.fieldname int y = p1.y; System.out.println("(" + x + ", " + y + ")"); } } ``` --- ### 在class內使用class的method ``` methodName(argumentList); ``` ### 在class外使用class的method ``` objectReference.methodName(argumentList); ``` Example: ```java class Point { public int x; public int y; public void set(int nextX, int nextY) { x = nextX; y = nextY; } public void setAndPrint(int nextX, int nextY) { set(nextX, nextY); // methodName(argumentList); print(); // methodName(argumentList); } public void print() { System.out.println("(" + x + ", " + y + ")"); } } public class Main { public static void main(String[] args) { Point p = new Point(); // objectReference.methodName(argumentList); p.print(); // (0, 0) p.set(300,400); p.print(); // (300, 400) p.setAndPrint(500, 600) // (500, 600) } } ``` ## Reference 宣告 Class變數 的時候, 變數其實會是一個參考。 建立實例的時候, 會將物件存在Heap中, 並且在Stack建立該實例的參考。 把物件`=`到 Class變數 的時候, Class變數 會"參考"該物件。 --- 範例程式: ``` Object o; o = new Object(); Object a = o; ``` 逐步解釋: ``` Object o; ``` 此時: Stack: o -> (null) ``` o = new Object(); ``` 此時: Stack: o -> (0x1000) Heap: 0x1000 -> (剛剛建立的實例) 這時候o就會是剛剛建立的實例了 ``` Object a = o; ``` 此時: Stack: o -> (0x1000), a -> (0x1000) Heap: 0x1000 -> (剛剛建立的實例) 這時候o跟a就會是剛剛建立的實例了 --- 如果我們不讓任何變數是指向該實例,會怎麼樣? ``` new Object(); ``` 此時: Stack: ??? Heap: 0x1001 -> (剛剛建立的實例) 0x1000這個物件為"unreachable", 如果沒有及時使用, 稍後會被GC釋放。 JVM會自動清除沒有被引用的物件, 此程序稱為: Garbage Collection (GC) GC 原理, 優化方法, 間隔... 非常高深。 如果有興趣我再來講JVM。 反著講, 因為沒有辦法手動釋放物件, 如果一堆變數存一堆實例, 一直存在陣列/變數內 不釋放的話, 最後在new實例的時候會有OutofMemoryError。 如果是不經意的存太多不要的實例, 我們稱之為: Memory Leak. 這**可能**就是為什麼有些軟體因為GC的頻率愈來愈高, 因此感覺越跑越卡, 最後OOM。