
Java入門|パッケージを階層に分ける
パッケージを階層で整理すると、クラスの役割が見えやすくなり、大きなプログラムもすっきり管理できる
Javaでプログラムを作っていると、最初のうちはクラスの数も少ないので、1つか2つのパッケージだけでも十分に整理できます。ですが、学習が進んでプログラムの規模が大きくなってくると、クラスの数が増え、役割も細かく分かれていきます。そうなると、同じパッケージの中に何でも入れてしまう方法では、少しずつ見通しが悪くなってきます。
そんなときに役立つのが、パッケージを階層に分けるという考え方です。Javaでは、パッケージの中にさらに下位のパッケージを作ることができます。これを使うと、似た役割のクラスをグループごとに細かく整理できるので、プログラム全体の構造がとても見やすくなります。
今回は、このしくみをサブパッケージという考え方とあわせて見ていきます。ドラゴンボールの世界をイメージしたクラスを使いながら、フォルダ構成、package文の書き方、コンパイル方法、実行方法まで、順番にわかりやすく確認していきましょう。
パッケージを階層に分けるとは
Javaのパッケージは、1段だけの分類ではありません。
必要に応じて、さらに下の階層を作れます。
たとえば、pa というパッケージがあるとします。
その下に sub という分類を作ると、パッケージ名は pa.sub になります。
このように、ピリオドでつないで表すことで、Javaではパッケージの階層を表現できます。
たとえばイメージとしては、こんな感じです。
| 書き方 | 意味 |
|---|---|
| pa | 大きな分類 |
| pa.sub | pa の中をさらに細かく分けた分類 |
つまり、パッケージを階層に分けるというのは、クラスをより細かく整理するための方法です。
サブパッケージとは何か
パッケージの下の階層に作るパッケージを、サブパッケージと呼びます。
つまり、pa.sub の sub の部分がサブパッケージです。
この仕組みを使うと、たとえば次のように役割で分けられます。
| パッケージ | 入れるクラスの例 |
|---|---|
| pa | 基本となる共通クラス |
| pa.sub | 補助的なクラス、細かい機能のクラス |
| pb | 実行用クラスや別の機能グループ |
| pc | さらに別の機能グループ |
クラスが増えてくると、こうした整理はとても大切になります。
どのクラスがどの機能に属しているのかが、名前を見るだけでもわかりやすくなるからです。
なぜ階層化が必要なのか
小さなプログラムでは、パッケージが1つでも十分なことがあります。
でも、機能が増えてくると、同じパッケージの中にたくさんのクラスが集まりすぎてしまいます。
たとえば、ドラゴンボール風のプログラムを考えると、こんなクラスが出てきそうです。
- 戦士を表すクラス
- 技を表すクラス
- 修行を表すクラス
- バトルを表すクラス
- 補助処理を行うクラス
- 実行を開始するクラス
これらを全部1つのパッケージに入れると、あとから見返したときにかなり探しづらくなります。
そこで、似た役割のものをサブパッケージに分けていくと、整理しやすくなります。
| 状態 | 階層化しない場合 | 階層化した場合 |
|---|---|---|
| クラス数が増えたとき | ごちゃごちゃしやすい | 役割ごとに整理しやすい |
| 修正するとき | 探すのに時間がかかる | 関係する場所を見つけやすい |
| 複数人で開発するとき | 担当範囲が見えにくい | 機能ごとに分担しやすい |
このように、サブパッケージは大きなプログラムを見やすくするための大切な工夫です。
package文の書き方
サブパッケージを使うときは、package文に階層をそのまま書きます。
package pa.sub;この書き方によって、そのファイルのクラスは pa.sub パッケージに属することになります。
ここで大事なのは、pa と pa.sub は別のパッケージとして扱われるということです。
名前がつながっているので、何となく同じグループに見えますが、Javaのコード上では独立した別のパッケージです。
フォルダ構成との対応
パッケージを階層に分けたときは、フォルダ構成もそれに対応させます。
package pa.sub; と書くなら、フォルダも pa の下に sub を作ります。
今回の例では、作業中ディレクトリの構成は次のようになります。

つまり、
- pa はフォルダ pa
- sub は pa の下のフォルダ sub
に対応しています。
この対応関係がずれてしまうと、Javaはクラスの位置を正しく認識できません。
そのため、package文とフォルダ構成は必ずそろえる必要があります。
サンプルプログラムで見てみよう
クラス名はドラゴンボールをイメージして Fighter にし、情報設定用のメソッドは setFighter にしています。
ファイル名:Sample7.java
package pa.sub;
// 戦士クラス
class Fighter {
private String name;
private int power;
public Fighter() {
name = "未設定";
power = 0;
System.out.println("戦士を準備しました。");
}
public void setFighter(String n, int p) {
name = n;
power = p;
System.out.println("戦士名を" + name + "に、戦闘力を" + power + "にしました。");
}
public void show() {
System.out.println("戦士名は" + name + "です。");
System.out.println("戦闘力は" + power + "です。");
}
}
class Sample7 {
public static void main(String[] args) {
Fighter fighter1 = new Fighter();
fighter1.show();
}
}このプログラムのポイント
このサンプルで注目したいのは、先頭の
package pa.sub;という部分です。
この1行によって、FighterクラスとSample7クラスは、どちらも pa.sub パッケージに含まれます。
今回の役割を整理すると、次のようになります。
| クラス名 | 役割 |
|---|---|
| Fighter | 戦士名と戦闘力を管理する |
| Sample7 | mainメソッドを持ち、処理を開始する |
同じ pa.sub パッケージに属しているので、Sample7 から Fighter をそのまま使えます。
実行結果
このプログラムを実行すると、たとえば次のように表示されます。
戦士を準備しました。
戦士名は未設定です。
戦闘力は0です。コンストラクタで初期状態を作り、そのあと show メソッドで内容を表示している流れです。
とてもシンプルですが、サブパッケージの使い方を確認するにはちょうどよい例です。
コンパイルの方法
サブパッケージを使う場合も、作業中ディレクトリからコンパイルします。
今回なら、Sample7.java は pa\sub の中にあるので、次のように入力します。
PS C:\Java\13>javac pa\sub\Sample7.java指定するパスが少し長くなっていますね。
これは、パッケージが階層化されているぶん、フォルダ構成も深くなっているからです。
実行の方法
実行するときは、mainメソッドを持つ Sample7 クラスを、サブパッケージまで含めて指定します。
PS C:\Java\13>java pa.sub.Sample7ここで pa.Sample7 としてはいけません。
正しくは pa.sub.Sample7 です。
サブパッケージまで含めた完全な名前で指定することが大切です。
これまでのパッケージとの違い
使い方の流れそのものは、これまでのパッケージと大きくは変わりません。
違うのは、階層が1段増えていることです。
| 項目 | 通常のパッケージ | サブパッケージ |
|---|---|---|
| package文 | package pa; | package pa.sub; |
| 保存先 | pa フォルダ | pa\sub フォルダ |
| 実行時の指定 | java pa.SampleX | java pa.sub.Sample7 |
つまり、考え方は同じで、指定する名前が少し長くなるだけです。
その代わり、クラスの整理はぐっとしやすくなります。
pa と pa.sub は別パッケージ
ここはとても大事なので、しっかり押さえておきたいポイントです。
pa と pa.sub は、名前が似ていても別々のパッケージです。
たとえば、
- pa にある Fighter クラス
- pa.sub にある Fighter クラス
は、同じ Fighter という名前でも別のクラスとして扱われます。
表にするとこうなります。
| 記述 | 意味 |
|---|---|
| pa.Fighter | pa パッケージの Fighter クラス |
| pa.sub.Fighter | pa.sub パッケージの Fighter クラス |
このように、サブパッケージは上位パッケージの一部のように見えても、Javaでは独立した名前空間です。
サブパッケージを使うメリット
サブパッケージを使うと、プログラム全体の整理がかなりしやすくなります。
| メリット | 内容 |
|---|---|
| 機能ごとに整理しやすい | 似た役割のクラスをまとめられる |
| 見通しがよくなる | どこに何があるか把握しやすい |
| クラス数が増えても管理しやすい | 大規模開発に向いている |
| 名前の衝突を避けやすい | 同名クラスでも区別できる |
たとえば、ドラゴンボール風のプログラムなら、こんな分け方もできます。
- pa.character
- pa.battle
- pa.training
- pa.item
こうしておくと、役割ごとにクラスが整理されるので、とてもわかりやすくなります。
図で整理すると理解しやすい

この図では、左側にフォルダ構成、右側にパッケージ構成を配置します。
左側では、13 フォルダの下に pa、その下に sub があり、その中に Sample7.java が保存されている様子を表します。
右側では、それに対応する pa.sub パッケージの中に、FighterクラスとSample7クラスが入っている様子を示します。
この2つを対応させて見ることで、package文とフォルダ構成の関係がつかみやすくなります。
つまずきやすいポイント
サブパッケージでは、次のようなところで混乱しやすいです。
| つまずきやすい点 | 気をつけたいこと |
|---|---|
| pa.sub は pa の一部だから同じ扱いだと思う | Javaでは別パッケージとして扱う |
| フォルダを pa だけ作ってしまう | pa の下に sub も必要 |
| 実行時に pa.Sample7 と書いてしまう | 正しくは pa.sub.Sample7 |
| package文と保存場所がずれる | package pa.sub; なら pa\sub に保存する |
このあたりを意識しておくと、かなりスムーズに理解できます。
修飾子やアクセスの考え方にもつながる
サブパッケージを理解すると、あとで学ぶアクセス修飾子の意味も見えやすくなります。
たとえば、同じパッケージだけで使えるのか、別パッケージからも使えるのか、といった話を考えるときに、pa と pa.sub が別パッケージだとわかっていることがとても重要です。
つまり、サブパッケージはただの見た目の分類ではなく、Javaのコードのまとまりをきちんと理解するための土台にもなります。
ここで押さえたいこと
今回の内容で、特に大切なのは次の点です。
| 大事なポイント | 内容 |
|---|---|
| パッケージは階層化できる | ピリオドでつないで表す |
| サブパッケージは機能ごとの整理に便利 | クラス数が増えても見やすい |
| package文とフォルダ構成は対応する | pa.sub なら pa\sub |
| 実行時はサブパッケージも含めて指定する | java pa.sub.Sample7 |
| pa と pa.sub は別のパッケージ | 名前が似ていても同一ではない |
パッケージを階層に分ける考え方は、Javaで少し大きめのプログラムを扱うときにとても重要です。
クラスを役割ごとにきれいに整理できるようになると、コードを読むのも直すのもずっと楽になります。
ここまで理解できると、Javaのパッケージ機能をかなり実践的に使えるようになってきます。
