Java 入門指南
單元 9 - 封裝與建構子
物件導向程式設計 (object-oriented programming) 有三大基本特性,分別是封裝 (encapsulation) 、繼承 (inheritance) 及多型 (polymorphism)
Inheritance
Polymorphism
繼承的目的是讓類別 (class) 具有像是親屬的垂直關係(父母子女),子類別 (subclass) 可以擁有父類別 (superclass) 的屬性 (field) 及方法 (method) ,多型像是親屬的平行關係(兄弟姊妹),多個子類別繼承自單一父類別之時,這些子類別就可以用父類別代替,父類別如同家族裡的「姓」,子類別則是「名」。
繼承的英文原文 inherit ,中文意思泛指從什麼得到什麼,生物學上的遺傳也是用這個詞。
至於封裝的意思就是把屬性封在類別中,這還牽涉到程式設計中另一個重要的概念 資訊隱藏 (information hiding) ,主要就是不讓外界隨意存取類別的屬性,也就是說,只讓類別的屬性給同個類別的方法存取。
這就需要用到 private 修飾詞 (modifier) 了,當屬性宣告為 private 的時候,該屬性就只能由同一個類別存取,我們將 ClassDemo01 類別的屬性 a 封裝,改寫成 ClassDemo03 類別,程式如下
/*
* 檔名:ClassDemo03.java
* 作者:張凱慶
* 網站:http://kaiching.org
*/
package classdemo03;
public class ClassDemo03 {
private int a;
// setter 方法
public void setA(int p1) {
a = p1;
}
// getter 方法
public int getA() {
return a;
}
public int doSomething(int p1) {
return a + p1;
}
public static void main(String[] args) {
ClassDemo03 d = new ClassDemo03();
// 利用 setter 設定屬性
d.setA(11);
System.out.println();
// 利用 getter 印出屬性 a
System.out.println(d.getA());
System.out.println(d.doSomething(1));
System.out.println();
}
}
首先,屬性宣告為 private ,這樣屬性就只限類別 中可存取
private int a;
權限修飾詞有三個,分別是 public 、 private 及 protected ,加上不宣告權限修飾詞的形式,共有四種不同的權限。
接著如果要讓外界可以存取已封裝的屬性,就要另外設置 public 的 getter 與 setter 方法
// setter 方法
public void setA(int p1) {
a = p1;
}
// getter 方法
public int getA() {
return a;
}
執行結果如下
11 |
12 |
留意設定屬性 a 已經改成在建立物件後呼叫 setter 方法
// 利用 setter 設定屬性
d.setA(11);
這是 setter 方法的用途沒錯,不過如果我們想要建立物件的同時設定好屬性,就需要自訂建構子 (constructor) ,所謂建構子是一種特別的方法 (method) ,特別的地方是在建構子是建立物件 (object) 時所執行的方法。
記不記得建立 ClassDemo01 時,需要用 new 關鍵字 (keyword) , new 後面接的是附上小括弧的類別 (class) 名稱
ClassDemo01 d = new ClassDemo01();
完整的 ClassDemo01.java ,請參考單元 8 。
類別名稱加上小括弧,其實就是呼叫建構子來建立物件,如果沒有自行定義建構子,編譯器會自動替我們補上一個。下面我們給 ClassDemo01 增加建構子當作例子,新類別寫在 ClassDemo04 中,如下
/*
* 檔名:ClassDemo04.java
* 作者:張凱慶
* 網站:http://kaiching.org
*/
package classdemo04;
public class ClassDemo04 {
private int a;
// 這裡定義建構子
public ClassDemo04(int p1) {
setA(p1);
}
public void setA(int p1) {
a = p1;
}
public int getA() {
return a;
}
public int doSomething(int p1) {
return a + p1;
}
public static void main(String[] args) {
ClassDemo04 d = new ClassDemo04(12);
System.out.println();
System.out.println(d.getA());
System.out.println(d.doSomething(1));
System.out.println();
}
}
建構子的定義如下
// 這裡定義建構子
public ClassDemo04(int p1) {
setA(p1);
}
此例 ClassDemo04() 有一個 int 參數 (parameter) p1 ,然後直接以 p1 設定屬性 (field) a 。注意建構子沒有回傳值 (return value) ,這是因為建構子就是用來建立物件,因此預設回傳物件本身。
由於建構子有參數,因此呼叫建構子建立物件時也需要提供參數
ClassDemo04 d = new ClassDemo04(10);
建構子也可以多載 (overload) ,就是可以自行定義各種參數版本的建構子,其中包括沒有參數的版本,編譯器 (compiler) 預設的建構子也是沒有沒有參數的版本。
執行結果如下
12 |
13 |
下面我們介紹個小技巧,建構子或方法的參數識別字 (identifier) 也可以跟屬性一樣,這時候存取屬性就要利用 this 關鍵字了,我們將 ClassDemo04 改成用 this 存取屬性,如下
/*
* 檔名:ClassDemo05.java
* 作者:張凱慶
* 網站:http://kaiching.org
*/
package classdemo05;
public class ClassDemo05 {
private int a;
public ClassDemo05(int a) {
setA(a);
}
public void setA(int a) {
// 利用 this 存取屬性
this.a = a;
}
public int getA() {
return a;
}
public int doSomething(int a) {
// 參數跟屬性使用相同的識別字
return this.a + a;
}
public static void main(String[] args) {
ClassDemo05 d = new ClassDemo05(13);
System.out.println();
System.out.println(d.getA());
System.out.println(d.doSomething(9));
System.out.println();
}
}
setter 部分改成用參數 a 設定屬性 a ,屬性前要用 this 加小數點存取
public void setA(int a) {
// 利用 this 存取屬性
this.a = a;
}
doSomething() 的地方也是
public int doSomething(int a) {
// 參數跟屬性使用相同的識別字
return this.a + a;
}
執行結果如下
13 |
22 |
基本的類別定義包含屬性、方法及建構子,接下來我們繼續討論物件導向程式設計的其他兩項特性。
相關教學影片
中英文術語對照 | |
---|---|
class | 類別 |
compiler | 編譯器 |
constructor | 建構子 |
encapsulation | 封裝 |
field | 屬性 |
information hiding | 資訊隱藏 |
identifier | 識別字 |
inheritance | 繼承 |
keyword | 關鍵字 |
method | 方法 |
modifier | 修飾詞 |
object | 物件 |
object-oriented programming | 物件導向程式設計 |
overload | 多載 |
parameter | 參數 |
polymorphism | 多型 |
return value | 回傳值 |
subclass | 子類別 |
superclass | 父類別 |
重點整理 |
---|
1. 物件導向程式設計的三大特性為封裝、繼承與多型。 |
2. 封裝是限制成員只能在類別中存取,也就是把成員宣告為 private 。 |
3. 建構子是建立物件時所執行的特別方法。 |
4. 關鍵字 this 用在方法中存取屬性。 |
問題與討論 |
---|
1. 物件導向程式設計有哪些特性? |
2. 封裝的作用是什麼? Java 中要怎麼進行封裝? |
3. 建構子是什麼?為什麼要建構子? |
練習 |
---|
1. 1. 建立一個新專案 Exercise0901 ,替 Exercise0805 類別設計建構子,將屬性 result 的初值放在建構子中設定。 |
2. 建立一個新專案 Exercise0902 ,替 Exercise0806 類別設計建構子。 |
3. 建立一個新專案 Exercise0903 ,替 Exercise0807 類別設計建構子。 |