> 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/basic_java_programming/innerclass.md).

# 內部類別

> 了解一個Java檔案中可以定義多個類別，內部類別的相關使用方式。

我們知道寫Java程式就是在設計類別，而類別定義寫在 .java檔案中。

## 外部類別 Outer Class

我們可以把多個類別定義在同一個檔案中，以Human.java為例；

```java
class Human{
    // code...
}
class Animal{
    // code...
}
```

編譯出的.class檔會有Human.class及Animal.class。這兩個類別皆屬於外部類別(outer class)，外部類別在使用上不常出現，因為一般作法會多寫一個Animal.java然後設定好相關的存取修飾子，這樣在一個檔案中寫多個外部類別的作法顯然有些雞肋。甚是會有同名的錯誤發生(如果別人也在他的程式裡寫一個Animal外部類別，那會編譯錯誤)。

## 巢狀類別 Nested Classes

巢狀的意思是，類別裡面又定義了類別。感覺像類別包著類別，程式看起來是這樣：

```java
class Outer{
    class Inner{
    }
    class Inner2{
    }
}
```

最外層的class被稱為外部類別(outer class)，裡面定義的稱為內部類別(inner class)。

## 如何使用？ How To Use?

假設有一個Human類別定義：

```java
package tina;

class Human {
    String name;
    public Human(String str) {
        name = str;
    }// end of constructor(String)
    class Wearing {
        String color;
        char size;
    }// end of class Wearing
}// end of class Human
```

這個Human的類別中還定義了一個Wearing類別，如果想利用這個Wearing來創造物件？

```java
public class HumanTest {
    public static void main(String[] args){
        Human tina = new Human("小婷");
        Human.Wearing wear = tina.new Wearing();
        wear.color="white";
        wear.size='s';
    }
}
```

可以看到主程式第二行，物件的宣告。

```java
外部類別.內部類別 物件名稱 = 外部物件.new 建構子();
```

慢慢來看這個敘述，跟以前宣告物件一樣，只是利用點運算子從外部類別『點』進内部類別。指定運算子後面，外部物件.new 內部類別建構子()。要初始化物件，要告訴他是哪個物件裡面的內部類別，然後一樣呼叫建構子。

好，現在我們已經可以創造內部類別的物件了，可惜這種方法不是常用的方法XD

## 透過公開方法設定內部類別：

> 以上面的程式為例，我既然將內部類別Wearing定義在外部類別Human中，為什麼還要讓別人可以存取呢。

假設我的Human裡面有個欄位wear是Wearing物件，我只開放某個方法可以讓別人設定這個wear的值，而不能讓別人直接存取或創造物件：

```java
class Human {

    private String name;    // 設為private私有，不讓別人直接存取到
    private Wearing wear;   // 這個wear是內部類別Wearing的物件，是Human的欄位

    public Human(String str) {  // public，公開此建構子
        name = str;
        wear = new Wearing();   // wear是物件，還是需要利用new初始化
    }

    private class Wearing {  // private，不讓別人利用此類別建立物件
        String color;
        char size;
    }

    public void setWear(String c, char s) {  // 開放此方法，別人只能透過這個方法設定wear
        wear.color = c;
        wear.size = s;
    }

    public String getWear() {  // 開放此方法，別人只能透過此方法取得wear的內容
        return name+" 穿的服裝顏色是：" + wear.color + " 尺寸是：" + wear.size;
    }

}// end of class Human
```

嗯，比較重點的方法還有存取修飾子的設定寫在註解上。

然後看看測試用類別Test.java會怎麼使用這個Human類別：

```java
class Test {
    public static void main(String[] args) {
        Human tina = new Human("小婷");
        tina.setWear("white", 's');
        System.out.println(tina.getWear());
    }// end of main(String[])
}// end of class Test
```

執行結果：

```java
小婷的服裝顏色：white，尺寸：s
```

這樣設計的好處除了防止別人亂用你的類別外，還可以確保內部的資料備正確的使用。

例如setWear()方法，可以確保設定wear的時候一定會帶入兩個參數，當然也可以進一步的做參數的檢查、轉換。getWear()方法是唯一公開讓別人讀取wear的方法，就可以在回傳前做一些特定的轉換。

這就是物件導向的精神『**封裝(Encapsulation)**』，保護程式的安全性、完整性。

(相關[存取修飾子](https://yubin551.gitbooks.io/java-note/content/AccessModifier.html)後面會特別討論。)
