> For the complete documentation index, see [llms.txt](https://yubin551.gitbook.io/java-note/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://yubin551.gitbook.io/java-note/object_oriented_programming/encapsulation.md).

# 封裝

> 介紹封裝的概念。

物件導向最基本的原則，把真實世界的某個事物包成物件，裡面的資訊不對外公開，只公開某些特定方法讓別人使用，內部的實做及資料都隱藏起來，不讓人直接使用，也不需要讓別人直接使用。也就是所謂的 資訊隱藏（Information Hiding）

設想一個例子，

提款機，你不知道它裡面還有多少錢，也不知道內部的運做，不知道哪家公司生產的機器，但你還是會去使用他提供的方法：查詢餘額、提款。 因為他只開放這兩個方法給一般人使用，你要使用這兩個方法需要帶入的參數是提款卡及密碼，就可以完成你的需求。

```java
class 提款機{
    private int 剩餘現金;
    private boolean 身分確認(提款卡、密碼){
        ...
    }
    private void 吐鈔(){
        ...
    }
    public void 提款(提款卡、密碼){
        if(身分確認(提款卡、密碼) == true)
            吐鈔();
    }
    public void 查詢餘額(提款卡、密碼){
        ...
    }
}
```

當然實際上更為複雜且嚴密(而且我對提款機不熟)，但在怎麼複雜，使用上一般使用者只要知道使用哪些公開的方法就好(雖然不熟但我會領錢、查餘額)，剩下的就是設計這個類別的設計師要負責的工作。

## 常用修飾子 private 、 public

### private 私有

private是資訊隱藏會普遍使用的修飾子，開放全限最低，只有自己類別的成員能夠存取。

### public 公開

與private相反，public是任何人都可以調用，通常用來表示這個方法可以供一般人呼叫，一個public的方法內可以呼叫多個private的方法來實作需要的功能。

> 其他修飾子請參考『存取修飾子』章節。

物件導向是將『資料及其方法』包裝成物件，而資料、方法的劃分都是設計師決定的，但要記得物件的核心是資料，而不是方法。 (data是主角)

封裝的概念是將資訊隱藏，只透過某些公開的方法讓外界存取使用。

## Getter、Setter

為了資訊隱藏，我們常把重要資料設為private，要供別人(甚至自己)存取的時候，通常會利用getter()及setter()這種透過公開方法間接的存取。

來看個例子，學生的類別有姓名年齡3個欄位，提供兩個setter兩個getter：

```java
class Student{
    private String firstName;
    private String lastName;
    private int age = -1;

    public void setName(String first,String last){
        if( first == null || last == null || first.length()==0 || last.length()==0 ){
            System.out.println("ERROR: name輸入錯誤，名字姓氏不得為空");
        }else{
            firstName = first;
            lastName = last;
        }
    }
    public void setAge(int a){
        if(a < 0){
            System.out.println("ERROR: age輸入錯誤，年齡不可能為負數");
        }else{
            age = a;
        }
    }
    public String getName(){
        if( firstName==null || lastName==null)
            return "unset";
        else
            return firstName + lastName;
    }
    public int getAge(){
        return age;
    }
}// end of class Student
```

這是常見的設計方法，資料成員的部份我都設為private，而公開了setName(.)及setAge(.)讓別人呼叫來設定name及age的值，這就是透過公開方法間接的設定隱藏的欄位，好處是我這樣寫可以在設定欄位前先做一些前處理(以上述程式來說就是檢查參數的合法性)。

在getter的部份，也公開了兩個方法可以讓別人存取到內部隱藏的成員，以getName()來說，可以在回傳出去前多做一步處理(這裡是把名跟姓串起來)，這樣的設計方式是常見且容易維護的。

測試程式：

```java
class Test {
    public static void main(String[] args) {

        Student s1 = new Student();
        s1.setName("小木","");
        s1.setAge(-500);
        System.out.println(s1.getName());
        System.out.println(s1.getAge());

        Student s2 = new Student();
        s2.setName("Tina", "Lee");
        s2.setAge(18);
        System.out.println(s2.getName());
        System.out.println(s2.getAge());

    }// end of main(String[])
}// end of class Test
```

執行結果：

```java
ERROR: name輸入錯誤，名字姓氏不得為空
ERROR: age輸入錯誤，年齡不可能為負數
unset
-1
TinaLee
18
```

可以看到物件s1因為亂帶參數，所以用setter在設定前被先檢查出來，可以進一步增加程式的穩定性。
