前言
在 物件導向 的文章中有介紹一個類別的基本構成,而當我們使用一個類別建立起一個非靜態的類別時,總是使用建構子來建構「物件實例」,然後儲存在一個「物件參考變數」中;但有時候我們只是想要執行一下這個類別的功能,而後續就再也不使用它了,那麼我還需要管理這個「物件參考變數」嗎?
一、複習:建立一個物件實例
首先,複習一下語法:
父類別(介面)名稱 | 物件參考變數 | = | new 自己/子類別建構子(); |
(i) | (ii) | (iii) |
(i):宣告物件參考變數的型別
(ii):物件參考變數的名字
(iii):建立物件實例
使用 new 關鍵字在記憶體堆區塊(Heap)開闢足夠大的空間建立 自己/子類別 的物件實例。
範例 1:
建立 StudentClass 類別,使用封裝。完成後編譯這個類別 "javac StudentClass.java"
public class SchoolClass {
private String name;
private String className;
private int no;
private int studentNumber;
SchoolClass(){}
SchoolClass(String name, String className, int no, int studentNumber){
setName(name);
setClassName(className);
setNo(no);
setStudentNumber(studentNumber);
}
public void setName(String name){
this.name = name;
}
public void setClassName(String className){
this.className = className;
}
public void setNo(int no){
this.no = no;
}
public void setStudentNumber(int studentNumber){
this.studentNumber = studentNumber;
}
public String getName(){
return this.name;
}
public String getClassName(){
return this.className;
}
public int getNo(){
return this.no;
}
public int getStudentNumber(){
return this.studentNumber;
}
public String toString(){
return "姓名:" + getName() + "\n" +
"學號:" + getStudentNumber() + "\n" +
"班級:" + getClassName() + "\n" +
"座號:" + getNo();
}
}
建立 TestAnon1 類別,測試 SchoolClass 類別。
xxxxxxxxxx
class TestAnon1 {
public static void main(String[] args){
SchoolClass sc = new SchoolClass();
sc.setName("王小名");
sc.setClassName("二年三班");
sc.setNo(9);
sc.setStudentNumber(1060072);
System.out.println(sc);
SchoolClass sc2 = new SchoolClass("李小四", "三年十班", 17, 1050332);
System.out.println(sc2);
}
}

▼ Stack 指向 Heap 空間示意圖
name | className |
no | studentNumber |
SchoolClass() | |
SchoolClass(String name, String className, int no, int studentNumber) |
|
public void setName(String name) | |
getName() | |
setClassName(String className) | |
getClassName() | |
setNo(int no) | |
getNo() | |
setStudentNumber(int studentNumber) | |
getStudentNumber() |
name | className |
no | studentNumber |
SchoolClass() | |
SchoolClass(String name, String className, int no, int studentNumber) |
|
public void setName(String name) | |
getName() | |
setClassName(String className) | |
getClassName() | |
setNo(int no) | |
getNo() | |
setStudentNumber(int studentNumber) | |
getStudentNumber() |
二、匿名物件
上個範例中,(i)(ii)宣告物件參考變數時,會在 Stack 區塊建立兩個變數 sc 和 sc2;(iii)建立物件實例時,會在 Heap 區塊建立兩個物件實例。
如果我們不宣告物件參考變數,那麼就不會在 Stack 區塊建立變數,只使用(iii)建立物件實例的話,那麼在 Heap 區的物件實例就沒有參考變數,所以沒有參考變數指向的物件實例就叫做「匿名物件」。
匿名物件的語法:
匿名物件的小知識:
- 使用方式並無任何差別。
- 因為沒有任何物件參考變數指向這個物件實例,所以只能在剛建立時使用它,屬於「一次性」的使用。
- 匿名物件等於把物件參考變數指向 null。例如上個範例中 sc = null。
範例 2:
繼續使用範例1的 StudentClass 類別,我們另寫一個類別 TestAnon2 測試匿名類別。
System.out.println(sc2);
把 sc2 直接替換成"="右邊的 new SchoolClass("李小四", "三年十班", 17, 1050332),上下兩個語法的結果是相同的。
xxxxxxxxxx
class TestAnon2 {
public static void main(String[] args){
System.out.println( new SchoolClass("李小四", "三年十班", 17, 1050332) );
}
}
▼ Stack 沒有物件參考變數, Heap 空間只有一個物件實例。
name | className |
no | studentNumber |
SchoolClass() | |
SchoolClass(String name, String className, int no, int studentNumber) |
|
public void setName(String name) | |
getName() | |
setClassName(String className) | |
getClassName() | |
setNo(int no) | |
getNo() | |
setStudentNumber(int studentNumber) | |
getStudentNumber() |
三、匿名物件與 this 關鍵字
this 是一個參考,它指向自身的物件實例。

我們在 SchoolClass 類別中新增兩個方法,並設定回傳值為 SchoolClass。這種做法可以一次調用許多方法,一次完成所有工作。
xxxxxxxxxx
public class SchoolClass {
private String name;
private String className;
private int no;
private int studentNumber;
SchoolClass(){}
SchoolClass(String name, String className, int no, int studentNumber){
setName(name);
setClassName(className);
setNo(no);
setStudentNumber(studentNumber);
}
public void setName(String name){
this.name = name;
}
public void setClassName(String className){
this.className = className;
}
public void setNo(int no){
this.no = no;
}
public void setStudentNumber(int studentNumber){
this.studentNumber = studentNumber;
}
public String getName(){
return this.name;
}
public String getClassName(){
return this.className;
}
public int getNo(){
return this.no;
}
public int getStudentNumber(){
return this.studentNumber;
}
public String toString(){
return "姓名:" + getName() + "\n" +
"學號:" + getStudentNumber() + "\n" +
"班級:" + getClassName() + "\n" +
"座號:" + getNo();
}
public SchoolClass ranked(String ranking){
System.out.println("頒發 「" + ranking + "」 給" + getName() + ", 恭喜您!");
return this;
}
public SchoolClass award(int awardMoney){
int scholarship = 0;
switch(awardMoney){
case 1:
scholarship = 500;
break;
case 2:
scholarship = 300;
break;
case 3:
scholarship = 200;
break;
case 4:
case 5:
scholarship = 50;
break;
}
System.out.println(getName() + "得到了 " + scholarship + " 元獎金!");
return this;
}
public void noShow(){}
}
調用修改過後的 SchoolClass 類別,使用匿名類別。
xxxxxxxxxx
class TestAnon3 {
public static void main(String[] args){
new SchoolClass("李小四", "三年十班", 17, 1050332).ranked("段考第一名").award(1).noShow();
}
}

四、總結
如果只要使用一次,就使用「匿名類別」,這樣不需要管理物件參考變數,而且使用完畢後,即可等待 JVM 回收釋放記憶體。
沒有留言:
張貼留言