為什麼要這麼做呢?理由其實很簡單,為了防止物件遭不當的使用,例如
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 修改如下
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; } } /* 《程式語言教學誌》的範例程式 http://pydoing.blogspot.com/ 檔名:Encrypt.java 功能:示範 Java 程式 作者:張凱慶 時間:西元 2011 年 4 月 */
由於 cArray 已經宣告為 private ,因此 EncryptDemo 中也要改成 getArray() 才能進行測試
// 測試 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(); } } /* 《程式語言教學誌》的範例程式 http://pydoing.blogspot.com/ 檔名: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 則留言:
您好,從頭學習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());
重新編譯之後,才能正確存取呢?
謝謝您的熱心指 導 :)
這部份寫錯了,已修改,感謝指正 :)
您好,#82. for (i = 0; i < n; i++) {
為何不是用getN()?
而RUN起來竟也沒有error!
謝謝指導!
這裡寫成 getN() 會比較好唷!倒是 n 或 getN() 在 Encrypt 類別裡會是同義的, Encrypt 類別外才只能由 getN() 來存取 n 。
張貼留言