在 封裝物件操作流程 的範例中,你在CashCard
類別上定義了store()
等方法,你「希望」使用者如下撰寫程式,這樣才可以執行stroe()
等方法中的相關條件檢查流程:
CashCard card1 = new CashCard("A001", 500, 0);
card1.store(scanner.nextInt());
老實說,就目前的Java程式碼來說,你的希望完全就是一廂情願,因為CashCard
使用者還是可以如下撰寫程式,跳過你的相關條件檢查:
CashCard card1 = new CashCard("A001", 500, 0);
card1.balance += scanner.nextInt();
card1.bonus += 100;
問題在哪?因為你沒有封裝CashCard
中不想讓使用者直接存取的私有資料,使用者撰寫程式時,就有了自由存取類別私有資料的選擇,如果有些資料是類別所私有,在Java中可以使用private
關鍵字定義:
package cc.openhome;
class CashCard {
private String number;
private int balance;
private int bonus;
...略
void store(int money) {
if(money > 0) {
this.balance += money;
if(money >= 1000) {
this.bonus++;
}
}
else {
System.out.println("儲值是負的?你是來亂的嗎?");
}
}
int getBalance() {
return balance;
}
int getBonus() {
return bonus;
}
String getNumber() {
return number;
}
}
在這個例子,你不想讓使用者直接存取number
、balance
與bonus
,所以使用private
宣告,如此一來,編譯器會讓使用者在直接存取number
、balance
與bonus
時編譯失敗,如果你沒有提供方法存取private
成員,那使用者就不能存取,在CashCard
的例子中,如果想修改balance
或bouns
,就一定得透過store()
、charge()
、exchange()
等方法,也就一定得經過你定義的流程。
如果沒辦法直接取得number
、balance
與bonus
,那這段程式碼怎麼辦?
for(CashCard card : cards) {
System.out.printf("(%s, %d, %d)%n",
card.number, card.balance, card.bonus); // 編譯錯誤
}
除非你願意提供取值方法(Getter),讓使用者可以取得number
、balance
與bonus
的值,否則使用者一定無法取得,基於你的意願,CashCard
類別上定義了getNumber()
、getBalance()
與getBonus()
等取值方法,所以你可以如下修改程式:
for(CashCard card : cards) {
System.out.printf("(%s, %d, %d)%n",
card.getNumber(), card.getBalance(), card.getBonus());
}
在Java命名規範中,取值方法的名稱形式是固定的,也就是以get
開頭。
所以你封裝了什麼,封裝了類別私有資料,讓使用者無法直接存取,而必須透過你提供的操作方法,經過你定義的流程才有可能存取私有資料,事實上,使用者也無從得知你的類別中有哪些私有資料,使用者不會知道物件的內部細節。
在這邊對封裝作個小小結論,封裝目的主要就是隱藏物件細節,將物件當作黑箱進行操作。就如先前的範例,使用者會呼叫建構式,但不知道建構式的細節,使用者會呼叫方法,但不知道方法的流程,使用者也不會知道有哪些私有資料,要操作物件,一律得透過你提供的方法呼叫。
private
也可以用在方法或建構式宣告上,私有方法或建構式通常是類別內部某個共用的演算流程,外界不用知道私有方法的存在。private
也可以用在內部類別宣告,內部類別會在之後說明。