Javaのパッケージについて整理しました


# はじめに
現在、私が進行しているJavaの勉強会でまとめた内容です。
内容に不正確な点があれば、ご指摘いただけるとありがたいです。

韓国人として、日本語とコンピュータの勉強を同時に行うために、ここに文章を書いています
翻訳ツールの助けを借りて書いた文章なので、誤りがあるかもしれません

https://github.com/whiteship/live-study/issues/7

# 整理すること 
- package キーワード  
- import キーワード  
- クラスパス  
- CLASSPATH 環境変数  
- -classpath オプション  
- アクセス修飾子  

# Packageとは？

`package com.example.myapp`

- クラスを管理するフォルダのような概念です

Javaの公式チュートリアルでは、次のように説明されています。

> You and other programmers can easily determine that these types are related.
You and other programmers know where to find types that can provide graphics-related functions.
The names of your types won't conflict with the type names in other packages because the package creates a new namespace.
You can allow types within the package to have unrestricted access to one another yet still restrict access for types outside the package.

- あなたや他のプログラマーは、これらの型が関連していることを簡単に理解できます。  
- あなたや他のプログラマーは、グラフィック関連の機能を提供する型がどこにあるのかを把握できます。  
- パッケージが新しい名前空間を作成するため、自分の型名が他のパッケージの型名と衝突することはありません。  
- パッケージ内の型同士は制限なくアクセスできますが、パッケージ外の型へのアクセスは制限することが可能です

## FQCN (Fully Qualified Name)

「FQCN」は「Fully Qualified Name」の略で、プログラミングにおいて完全な識別子を意味します。

- オブジェクト、クラス、メソッドを正確に識別するために使用する完全なパスを指します

https://en.wikipedia.org/wiki/Fully_qualified_name

---- 
### クラスを例にしたFQCN

- Javaのクラスは**パッケージに属しています**。  
- クラス名だけでは、どのパッケージに属しているクラスなのかを判別できないため、パッケージを含めた完全なパス（FQCN）を使用します

**クラス名** : `ArrayList`  
**FQCN** : `java.util.ArrayList`

### メソッドを例にしたFQCN

- 重複を防ぎ、メソッド呼び出しを明確に区別するためにFQCNを使用します

**メソッド名** : whoAreYou  
**FQCN** : Person.whoAreYou(String, int)

## パッケージ宣言

- パッケージはコンパイルの過程で、コンパイラによって自動的にファイルシステム上のフォルダとして生成されます

```java
package 上位パッケージ.下位パッケージ;
public class ClassName{ ... }
```

- コンパイラはクラスファイルを `上位パッケージ/下位パッケージ` ディレクトリ構造内に生成します

# Import（インポート）
- 他のパッケージに定義されたクラスを現在のクラスで使用するために使用されます

### パッケージを指定する方法
- `import`文を使用して、特定のパッケージのクラスを取り込むことができます
- `import`文を明示的に記述すると、コードを書く際にクラス名からパッケージ名を省略できます

```java
import java.util.ArrayList;

public class Example {
    ArrayList<String> list = new ArrayList<>();
}
```

- `import`文の役割は、コンパイラにコード内で使用されるクラスの情報を提供することです
    - 上記のコードでは、`import java.util.ArrayList;` を使用して、該当パスの `ArrayList` を参照するようコンパイラに指示しています

```java
public class Example {
    java.util.ArrayList<String> list = new java.util.ArrayList<>();
}
```
- `import`文を省略してパッケージ名を明示的に記述しても動作します

```java
import java.util.*;

public class Example {
    ArrayList<String> list = new ArrayList<>();
}
````
- **ワイルドカード**を使用すると、`import java.util.*;` のように `*` を記述することで、該当パッケージ内のすべてのクラスを取り込むことができます

```java
import static java.lang.System.out;

public class Example {
    public static void main(String[] args) {
        out.println("Hello, World!");
    }
}
```

- **静的インポート**を使用することで、クラスの静的メンバーを直接利用することができます

## Importの注意事項
- `import`文はクラス宣言部の前に記述する必要があります

```java
public class Example {
    // クラス宣言部の開始
    java.util.ArrayList<String> list = new java.util.ArrayList<>();
}

// 誤った位置にあるimport文
import java.util.ArrayList;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3815412/52624a82-349a-0ec2-eaae-b72e4c9b49e4.png)

これを違反すると、次のようなコンパイルエラーが発生します。

- `java.lang` パッケージ内のクラスはデフォルトで自動的にインポートされるため、別途 `import` 文を記述する必要はありません

```java
public class Main {
    public static void main(String[] args) {
        System.out.println("Hello World");
    }
}
```

https://docs.oracle.com/en/java/javase/23/docs/api/java.base/java/lang/package-summary.html?utm_source=chatgpt.com

- 次のドキュメントで `java.lang` に含まれる内容を確認できます

- `Object` およびそれを継承したラッパークラス (`Integer`, `Boolean`, `Double` など)  
- `Throwable` およびそれを継承した `Error` と `Exception`  
- `Reflection` や `Thread` のようなランタイム関連機能  


# CLASSPATH
- Javaがクラスファイル (.class) を探すためのパスを指定する環境変数です
- Javaコンパイラ (`javac`) と実行プログラム (`java`) は、このパスを参照して必要なクラスを検索します
- もし `CLASSPATH` を別途指定しない場合、JVMは現在のディレクトリを基準にクラスを検索します

```java
java -cp パス/クラスファイルディレクトリ;外部ライブラリ.jar クラス名
```
- 実行またはコンパイル時に、`-classpath` または -`cp` オプションを使用して直接パスを指定することができます

https://docs.oracle.com/javase/tutorial/essential/environment/paths.html


## CLASSPATHを直接管理することを推奨しない理由
- 外部ライブラリを追加する際に、手動で `CLASSPATH` を指定すると、毎回パスを修正する必要があります
- ローカルのJavaプログラムを他の環境（別の開発者、配布サーバー、学校などの異なるコンピュータ環境）で実行しようとする場合、`CLASSPATH` を同一に設定する必要があります
- 複数のライブラリが異なるバージョンの同じ依存関係を使用している場合、衝突が発生し、パス管理が非常に困難になります


### MAVENやGRADLEを使用して解決しよう

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3815412/0477e08b-9cfd-eb1b-9d25-599752b7f68b.png)
現在私が進めているプロジェクトのパスは次の通りです。

私は多くのライブラリを使用しています。

もし私の同僚の開発環境でこのプロジェクトを実行しようとする場合、

```java
/Users/gimdonghyeon/Documents/github/haroya-di-framework    
```
このパスにすべてを一致させる必要があります。  
それだけでなく、ライブラリのパスもすべて一致させる必要があります。

そのため、私は現在次のようにGRADLEを使用して管理しています。  
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3815412/2a06ce0d-dcad-a2e7-677e-b97a6aa652ae.png)

Mavenの依存関係は以下のパスに保存されます。
- macOS/Linux: `~/.m2/repository`
- Windows: `C:\Users\<ユーザー名>\.m2\repository`

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3815412/3b067073-175b-4362-47f9-4d215536dc07.png)

Mavenリポジトリを使用することで、開発者は同じ環境を保証され、ソースコードのみに集中することができます。

# アクセス修飾子

| アクセス修飾子 | 同一クラス | 同一パッケージ | サブクラス（別パッケージ） | 別パッケージ |
|---------------|------------|----------------|--------------------------|--------------|
| `public`      | ✅         | ✅             | ✅                       | ✅           |
| `protected`   | ✅         | ✅             | ✅                       | ❌           |
| `default`     | ✅         | ✅             | ❌                       | ❌           |
| `private`     | ✅         | ❌             | ❌                       | ❌           |

- **`public`**: **すべてのクラス**からアクセス可能です
- **`protected`**: **同じパッケージ内のクラス**および**継承したクラス**からアクセス可能です
- **`private`**: **該当クラス内でのみアクセス可能**で、外部からアクセスすることはできません
- **`default` (package-private)**: **明示的にアクセス修飾子を指定しない場合**にデフォルトで適用され、**同じパッケージ内でのみアクセス可能**です

詳しくは私の他の記事をご参照ください。

https://docs.oracle.com/javase/specs/jls/se23/html/jls-6.html#jls-6.6