介紹
面向對象最基本的特征,把真實世界的某些物體包成對象,裡面的資訊不對外公開,隻公開某些特定方法讓别人使用,内部的屬性與邏輯都隐藏起來,不讓人直接使用,也不需要讓别人直接使用,就是所謂的
封裝
設想一個例子,
提款機
,你不知道它裡面還有多少錢,也不知道内部的運做,不知道哪家公司生産的機器,但你還是會去使用他提供的方法:
查詢餘額
、
提款
。因為他隻開放這兩個方法給一般人使用,你要使用這兩個方法需要帶入的參數是提款卡及密碼,就可以完成你的需求
class ATM {
private BigDecimal 剩餘金額;
private boolean 身份驗證(Object 提款卡, String 密碼) {
// 驗證邏輯
// 通過 傳回 true
}
private void 吐鈔() {
// 哒哒哒哒哒哒
}
public void 提款(Object 提款卡, String 密碼) {
if (身份驗證(提款卡, 密碼) == true)
吐鈔();
}
public BigDecimal 查詢餘額(Object 提款卡, String 密碼) {
// 查詢資料庫餘額 0
if (身份驗證(提款卡, 密碼) == true)
return 剩餘金額;
else
return BigDecimal.ZERO;
}
}
當然實際上更為複雜且嚴密(而且我對提款機不熟),但在怎麼複雜,使用上一般使用者隻要知道使用哪些公開的方法就好(雖然不熟但我會領錢、查餘額),剩下的就是設計這個類别的設計師要負責的工作
常用修飾符 private 、 public
private 私有
private
是屬性隐藏會普遍使用的修修飾符,開放權限最低,隻有目前類中能夠存取
public 公開
與
private
相反,
public
是任何人都可以調用,通常用來表示這個方法可以供大家通路,一個
public
的方法内可以調用多個 private 的方法來實作需要的功能
Getter 與 Setter
為了屬性隐藏,我們常把重要屬性設為
private
,要供别人(甚至自己)存取的時候,通常會利用
getter()
及
setter()
這種對外公開方法間接的存取。
來看個例子,學生類的屬性有姓名、年齡,提供
setter
getter
方法
public class Student {
private String name;
private int age = -1;
public void setName(String name) {
if (name == null || name.trim().length() == 0) {
System.out.println("ERROR: 名字不能為空!");
} else {
this.name = name;
}
}
public void setAge(int a) {
if (a < 0) {
System.out.println("ERROR: 年齡不能為負數!");
} else {
this.age = a;
}
}
public String getName() {
return name == null ? "無名氏" : this.name;
}
public int getAge() {
return age;
}
@Override
public String toString() {
return "Student{" +
"名字:'" + this.getName() + '\'' +
", 年齡:" + this.getAge() +
'}';
}
}
這是常見的設計方法,成員屬性的部份都設為 private,而公開了
setName()
setAge()
讓别人調用來設定
name
age
的值,這就是通過公開方法間接的設定隐藏的屬性值,好處是我這樣寫可以在設定屬性值前先做一些前處理(以上述代碼來說就是檢查參數的合法性)。
在
getter
的部份,也公開了兩個方法可以讓别人存取到内部隐藏的屬性,以
getName()
來說,可以在回傳出去前多做一步處理(這裡簡單空判斷) ,這樣的設計方式是常見且容易維護的。
測試代碼
public class TestStudent {
public static void main(String[] args) {
Student s1 = new Student();
s1.setName("源十天狗");
System.out.println("s1設定年齡為-500");
s1.setAge(-500);
System.out.println("列印s1:==>"+ s1.toString());
Student s2 = new Student();
System.out.println("s2不設定名字");
s2.setName(null);
s2.setAge(18);
System.out.println("列印s2:==>"+ s2.toString());
}
}
輸出
s1設定年齡為-500
ERROR: 年齡不能為負數!
列印s1:==>Student{名字:'源氏舔狗', 年齡:-1}
s2不設定名字
ERROR: 名字不能為空!
列印s2:==>Student{名字:'無名氏', 年齡:18}
可以看到對象 s1 因為亂傳參數,是以在
setter
被設定前被先檢查出來,可以進一步增加程式的穩定性