[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。