# 修飾外部類別

> 存取修飾子用於修飾方法時與修飾外部類別時有不同的限制，特別拿出來討論。

假設我們有一個Human類別(Human.java)，定義如下：

```java
package tina;
class Human{
    // code...
}// end of class Human
```

這個Human類別放在套件tina底下，且類別的修飾子為(no modifier，預設)，那這個類別只有處於**相同套件**的類別存取的到。

```java
package tina;
class HumanTest{
    public static void main(String[] args){
        Human h1 = new Human();
    }// end of main(String[])
}//end of HumanTest
```

這個 HumanTest.java位於套件tina中，可以直接存取到Human這個類別。

但若位在不同套件，就存取不到。

```java
package run;
class Test{
    public static void main(String[] args){
        Human h1 = new Human();  // compile error: Human cannot be resolved to a type
    }// end of main(String[])
}// end of class Test
```

馬上跳出**編譯錯誤**的訊息，因為Test類別看不到Human，不知道這是什麼東西。

若要讓不同套件的Test類別要做存取的話，Human必需用public作修飾。

```java
package tina;
public class Human{
    // code...
}// end of class Human
```

利用public修飾的類別，就算為在不同套件也可以存取的到，只需要import或利用完整類別路徑作存取。 Test.java程式如下：

```java
package run;
import tina.Human;
class Test{
    public static void main(String[] args){
        Human h1 = new Human();           // 有import就可以直接使用
        tina.Human h2 = new tina.Human(); // 利用完整類別路徑也行
    }// end of main(String[])
}// end of class Test
```

好的，討論完(no modifier)與public修飾子對於類別的影響，那剩下的protected跟private呢？

```java
// 保護
protected class Human{
    // code...
}
// 私有
private class Human{
    // code...
}
```

很遺憾，這兩個都會**編譯錯誤**，最外層的類別定義、與檔名同名的那個類別，不能用protected或private修飾。

### 但是為什麼？ why?

protected，用來修飾物件成員，表示可以讓同套件或不同套件但為子類別的類別存取。所以用來修飾類別的話，就是說可以讓同套件或不同套件但為子套件的類別存取。 有沒有覺得很奇怪XD 在Java裡面根本沒有『子套件』這個觀念，所以protected這個關鍵字用在這裡是毫無意義的。

private，用來修是物件成員，表示只有同類別能存取到。但你寫了一個類別檔，卻只有自己可以使用來創造物件？ 因此private也不能使用。

## 在一個檔案定義多個類別：

在一個.java檔中，我們可以定義多個class，方便我們完成所需要的功能。

以Human.java為例；

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

這樣是可以的，編譯後會產生Human.class及Animal.class兩個類別檔。

但現在我們要討論修飾子的部份，我們很清楚外部的的類別只能用(no modifier)或public修飾。

以Human.java來說：

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

這是OK的，Human修飾為public可以供不同套件的類別存取，Animal修飾為(no modifier)可以供相同套件的類別存取。

但若寫成這樣：

```java
class Human{
    // code...
}
public class Animal{  //編譯錯誤
    // code...
}
```

出現編譯錯誤的訊息：**The public type Animal must be defined in its own file**

也就是說，要用public修飾的外部類別，只能是『與檔名相同』的那個類別。

## 好，但是為什麼public只能修飾與檔名相同的外部類別呢？

很遺憾的告訴你，因為這是Java規定的。(兇手如下圖↓)

![](http://www.techweekeurope.co.uk/wp-content/uploads/2009/06/23/gosling_james.jpg)Gosling James (Java Founder)

在JLS (Java Language Specification，Java語言規範) [第7.6節](http://docs.oracle.com/javase/specs/jls/se7/html/jls-7.html#jls-7.6)提到，

> Top Level Type Declarations: (這裡的 Top Level Type就是本章節說的最外層類別)
>
> This restriction implies that there must be at most one such type per compilation unit. This restriction makes it easy for a Java compiler to find a named class within a package. In practice, many programmers choose to put each class or interface type in its own compilation unit, whether or not it is public or is referred to by code in other compilation units.

一個編譯單元(compilation unit，也就是一個 .java檔)最多只能有一個public的修飾，是為了讓Java編譯器更快速的找到套件中的那個類別。

在實務上，很多設計師會將他自己的類別或介面放到屬於那個類別或介面的編譯單元，這種在同一個 .java檔內定義多個外部類別的作法是少見且不建議的。


---

# 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/accessmodifier/modifyclass.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.
