# 內部類別

> 了解一個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)後面會特別討論。)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://yubin551.gitbook.io/java-note/basic_java_programming/innerclass.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
