Java 入門指南 - getter 與 setter

屬性 (field) 需要有效的封裝 (encapsulation) 到物件 (object) 裡頭,因此類別 (class) 定義屬性時,應該宣告 (declare) 為 private ,也就是私有的,只限定義他的類別可以存取,然後另外定義宣告為 public 的 getter 與 setter 方法 (method) ,利用 setter 設定屬性,另外用 getter 取得屬性值




為什麼要這麼做呢?理由其實很簡單,為了防止物件遭不當的使用,例如
Encrypt t = new Encrypt();
t.cArray = {'a'}; // 重新將 cArray 設定為另一個陣列


Encrypt 型態的變數 t 先以沒有參數版本的建構子 (constructor) 建立新物件,然後突然將 cArray 重新設定為對另一個陣列的參考,這樣一來,原先的對換表格就不見了說,往後加入編碼與解碼的方法,使用錯誤的表格,就會造成難以回復的結果。雖然這是我們刻意弄的例子,自己寫程式真實情況常常會有打錯字之類的,例如原本要將 a 設定為 1 ,結果按成 0
t.a = 0; // 把 a 設定錯誤


當然,我們自己開發程式可以自己小心點就好,但是,假如我們的類別準備提供給別的程式設計師或開發團隊使用的話,別人就不見得會這麼小心了。因此,物件導向程式設計 (object-oriented programming) 中提供封裝的意義即在此,類別的屬性應該宣告為 private
private char[] cArray = new char[26];
private int a;
private int b;
private int n;   
private char c; 
private int diff;


六個屬性就需要六個宣告為 public 的 getter 方法
public int getA() {
    return a;
}
 
public int getB() {
    return b;
}
     
public int getN() {
    return n;
}
     
public char getC() {
    return c;
}
     
public int getDif() {
    return diff;
}
 
public char[] getArray() {
    return cArray;
}


注意,建構子不需要回傳值型態,方法定義時需要標明回傳值型態,如果沒有回傳值,就須標上 void ,如另外六個 setter 方法
public void setA(int arg) {
    a = arg;
}
     
public void setB(int arg) {
    b = arg;
}
     
public void setN(int arg) {
    n = arg;
}
     
public void setC(char arg) {
    c = arg;
}
     
public void setDif(int arg) {
    dif = arg;
}
 
public void setArray() {
    int i, d, ci, m;
    char r;
    for (i = 0; i < n; i++) {
        ci = getC();
        d = ci * getA() + getB();
        m = d % getN();
        r = (char) (m + getDif());
        cArray[i] = r;
        c++;
    }       
}


我們在 setter 中直接設定屬性值,由於參數名稱全都採用 arg ,因此這裡可以用屬性名稱,不需要用到 this 。其中包含我們之前就介紹過 setArray() ,它也是 setter 方法之一,原先直接使用屬性名稱,這裡全部改成 getter 。


有關檢查 a 是否為奇數的部份,也可以寫進 setter 之中,但是我們把這部份寫在建構子裡,當然,這兩種方式都是可行的,讀者可自行選擇想要用哪一種方式。


因此原本建構子所用的 this 就改成呼叫 setter 囉!完整的 Encrypt 修改如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
public class Encrypt {
    private char[] cArray = new char[26];
    private int a;
    private int b;
    private int n;   
    private char c; 
    private int diff;
     
    public Encrypt(int a, int b, int n, char c, int dif) {
        setA(a);
        setB(b);
        setN(n);
        setC(c);
        setDif(dif);
        setArray();
    }
     
    public Encrypt(int a, int b) {
        this(a, b, 26, 'a', 97);
    }
     
    public Encrypt() {
        int ta = 0;
        int tb = 0;
         
        while (ta % 2 == 0) {
            ta = (int) (Math.random() * 10);
            tb = (int) (Math.random() * 10);
        }
         
        setA(ta);
        setB(tb);
        setN(26);
        setC('a');
        setDif(97);
        setArray();
    }
     
    public void setA(int arg) {
        a = arg;
    }
     
    public int getA() {
        return a;
    }
     
    public void setB(int arg) {
        b = arg;
    }
     
    public int getB() {
        return b;
    }
     
    public void setN(int arg) {
        n = arg;
    }
     
    public int getN() {
        return n;
    }
     
    public void setC(char arg) {
        c = arg;
    }
     
    public char getC() {
        return c;
    }
     
    public void setDif(int arg) {
        diff = arg;
    }
     
    public int getDif() {
        return diff;
    }
 
    public void setArray() {
        int i, d, ci, m;
        char r;
        for (i = 0; i < n; i++) {
            ci = getC();
            d = ci * getA() + getB();
            m = d % getN();
            r = (char) (m + getDif());
            cArray[i] = r;
            c++;
        }       
    }
     
    public char[] getArray() {
        return cArray;
    }
}
 
/* 《程式語言教學誌》的範例程式
    檔名:Encrypt.java
    功能:示範 Java 程式
    作者:張凱慶
    時間:西元 2011 年 4 月 */


由於 cArray 已經宣告為 private ,因此 EncryptDemo 中也要改成 getArray() 才能進行測試
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 測試 Encrypt 的類別
public class EncryptDemo {
    public static void main(String[] args) {
        System.out.println();
        for (int i = 0; i < 16; i++) {
            Encrypt t = new Encrypt();
            System.out.println(t.getArray());
        }
        System.out.println();
    }
}
 
/* 《程式語言教學誌》的範例程式
    檔名:EncryptDemo.java
    功能:示範 Java 程式
    作者:張凱慶
    時間:西元 2011 年 4 月 */


請自行編譯測試,記得 Encrypt 與 EncryptDemo 都要重新編譯。接下來,我們替 Encrypt 加入編碼的功能吧!


中英文術語對照
屬性field
封裝encapsulation
物件object
類別class
宣告declare
方法method
建構子constructor
物件導向程式設計object-oriented programming


您可以繼續參考
軟體開發


相關目錄
回 Java 入門指南
回 Java 教材目錄
回首頁


參考資料
The JavaTM Tutorials: Getting Started
The JavaTM Tutorials: Learning the Java Language
The JavaTM Tutorials: Essential Classes
The Java Language Specification, Third Edition


本文於 2013 年 1 月訂正
本文於 2013 年 2 月修正

4 則留言:

aorta 提到...

您好,從頭學習java的新手,從你這邊受益良多
想跟您請教一下,在這邊將 Encrypt中加入了getter及setter之後,如果沒有對EncryptDemo做修改的話,

原本的
7 System.out.println(t.cArray);
會去存取到已經被設為private的cArray
所以在執行的時候就會得到錯誤訊息
cArray has private access in Encrypt

是不是應該也要將EncryptDemo中的段落修改成
7 System.out.println(t.getArray());

重新編譯之後,才能正確存取呢?
謝謝您的熱心指 導 :)

Kaiching Chang 提到...

這部份寫錯了,已修改,感謝指正 :)

symis 提到...

您好,#82. for (i = 0; i < n; i++) {
為何不是用getN()?
而RUN起來竟也沒有error!
謝謝指導!

Kaiching Chang 提到...

這裡寫成 getN() 會比較好唷!倒是 n 或 getN() 在 Encrypt 類別裡會是同義的, Encrypt 類別外才只能由 getN() 來存取 n 。