
Java超|パッケージを階層に分ける
パッケージを階層に分ければ、Javaクラスの住所がもっと見やすくなる。大きな戦士管理本部でも、棚を分ければ迷わずクラスを探せます。
Javaでプログラムを作っていると、最初のうちはクラスの数が少ないため、1つか2つのパッケージだけでも十分に整理できます。
たとえば、pa パッケージに学習用のクラスをまとめたり、pb パッケージに実行用のクラスを置いたりするだけでも、基本的な構成は分かりやすいです。
しかし、学習が進んでプログラムの規模が大きくなると、クラスの数が増え、役割も細かく分かれていきます。
ドラゴンボール風にたとえると、最初はサイヤ人戦士の名簿だけを管理していればよかったものが、だんだん次のような巻物が増えていくイメージです。
| 巻物の種類 | Javaでのクラスのイメージ |
|---|---|
| サイヤ人戦士の名簿 | SaiyanWarrior クラス |
| 気の技の記録 | KiTechnique クラス |
| 任務の指令書 | BattleMission クラス |
| 戦闘装備の台帳 | BattleArmor クラス |
| 戦闘記録 | BattleManager クラス |
| 補助処理の巻物 | SupportTool クラス |
これらをすべて1つのパッケージに入れてしまうと、どこに何があるのか探しにくくなります。
そこで役立つのが、パッケージを階層に分ける という考え方です。
Javaでは、パッケージの中にさらに細かい分類を作れます。
たとえば、pa という大きなパッケージの下に sub という分類を作ると、パッケージ名は次のようになります。
package pa.sub;これは、pa の中をさらに sub という単位で細かく整理している形です。
ドラゴンボール風に言えば、pa という戦士管理本部の大きな棚の中に、sub という補助巻物専用の小さな棚を作るようなものです。
このように階層化すると、クラスの役割が見えやすくなり、大きなプログラムでも整理しやすくなります。
パッケージを階層に分けるとは何か
Javaのパッケージは、1段だけの分類ではありません。
必要に応じて、パッケージ名をピリオドでつなぎ、階層構造として表せます。
たとえば、次のような形です。
| パッケージ名 | 意味 |
|---|---|
| pa | 大きな分類 |
| pa.sub | pa の下にある sub という細かい分類 |
| pa.battle | pa の下にある battle という戦闘処理用の分類 |
| pa.training | pa の下にある training という修行管理用の分類 |
pa.sub と書くことで、pa の中をさらに sub で分類していることを表します。
ただし、ここで大切なのは、pa と pa.sub は別々のパッケージとして扱われる という点です。
名前だけ見ると、pa.sub は pa の一部のように感じます。
しかし、Javaのコード上では、pa と pa.sub は独立した別のパッケージです。
| 書き方 | Javaでの扱い |
|---|---|
| pa | pa パッケージ |
| pa.sub | pa.sub パッケージ |
| pa.SaiyanWarrior | pa パッケージの SaiyanWarrior クラス |
| pa.sub.SaiyanWarrior | pa.sub パッケージの SaiyanWarrior クラス |
ドラゴンボール風にたとえると、pa は戦士管理本部の大きな棚です。
pa.sub は、その中にある補助任務専用の棚です。
見た目には親子関係があるように見えますが、Javaのパッケージとしては、それぞれ別の棚として扱います。
サブパッケージとは何か
パッケージの下の階層に作るパッケージを、サブパッケージ と呼びます。
たとえば、pa.sub の場合、sub が pa の下にあるサブパッケージです。
| 用語 | 例 | 意味 |
|---|---|---|
| パッケージ | pa | 大きな分類 |
| サブパッケージ | pa.sub | pa の下にある細かい分類 |
| ピリオド | . | 階層を表す区切り |
ドラゴンボール風にたとえると、戦士管理本部の棚をさらに細かく分けるようなものです。
| Javaのパッケージ | ドラゴンボール風のイメージ |
|---|---|
| pa | 戦士管理本部の基本棚 |
| pa.sub | pa の中にある補助任務用の小棚 |
| pa.character | 戦士情報用の小棚 |
| pa.battle | 戦闘処理用の小棚 |
| pa.training | 修行記録用の小棚 |
| pa.item | 装備や道具用の小棚 |
サブパッケージを使うと、似た役割のクラスをさらに細かく整理できます。
クラスが少ないうちは、pa だけでも十分です。
しかし、クラスが増えてくると、pa の中にすべてを入れるよりも、pa.sub や pa.battle のように分けたほうが見通しがよくなります。
なぜパッケージを階層化するのか
小さなプログラムなら、1つのパッケージにすべてのクラスを入れても、それほど困らないことがあります。
しかし、プログラムが大きくなると、クラスの数が増え、役割も細かくなります。
ドラゴンボール風の学習プログラムを考えると、次のようなクラスが出てきそうです。
| クラス | 役割 |
|---|---|
| SaiyanWarrior | サイヤ人戦士を表す |
| KiTechnique | 気の技を表す |
| BattleMission | 任務を表す |
| BattleManager | 戦闘の進行を管理する |
| TrainingMenu | 修行内容を管理する |
| SupportTool | 補助処理を行う |
これらをすべて同じ pa パッケージに入れると、クラスが増えたときに探しにくくなります。
そこで、役割ごとにサブパッケージへ分けます。
| パッケージ | 入れるクラスの例 |
|---|---|
| pa.character | サイヤ人戦士、ナメック星戦士、支援戦士など |
| pa.battle | 戦闘処理、気の技の処理など |
| pa.training | 修行メニュー、訓練記録など |
| pa.item | 戦闘装備、防具、道具など |
| pa.sub | 補助的なクラス、細かい機能のクラス |
このように分けると、どこに何があるのかが見えやすくなります。
| 状況 | 階層化しない場合 | 階層化した場合 |
|---|---|---|
| クラス数が増えたとき | 1つの場所に集まりすぎる | 役割ごとに整理できる |
| 修正するとき | 探すのに時間がかかる | 関係する場所を見つけやすい |
| 複数人で開発するとき | 担当範囲が分かりにくい | 機能ごとに分担しやすい |
| 同名クラスがあるとき | 衝突しやすい | パッケージ名で区別できる |
パッケージの階層化は、大きなプログラムを見やすく保つための大切な工夫です。
図:パッケージを階層に分けるイメージ

この図が示していること
この図では、すべてのクラスを pa パッケージに入れた場合と、pa の下にサブパッケージを作って整理した場合を比較しています。
左側では、pa の棚に多くのクラスが集まっており、探しにくい状態です。
右側では、pa.character、pa.battle、pa.training、pa.item、pa.sub のように、役割ごとに棚を分けています。
| 整理方法 | 特徴 |
|---|---|
| 1つのパッケージにまとめる | 小さいプログラムでは分かりやすい |
| サブパッケージに分ける | クラスが増えても役割ごとに探しやすい |
この図から分かることは、パッケージを階層に分けると、クラスの住所が細かくなり、大きなプログラムでも見通しを保ちやすいということです。
package文の書き方
サブパッケージを使うときは、package 文に階層をそのまま書きます。
たとえば、pa の下に sub というサブパッケージを作る場合は、次のように書きます。
package pa.sub;この1行によって、そのファイル内のクラスは pa.sub パッケージに属します。
| package 文 | 所属するパッケージ |
|---|---|
| package pa; | pa パッケージ |
| package pa.sub; | pa.sub パッケージ |
| package pa.battle; | pa.battle パッケージ |
| package pa.training; | pa.training パッケージ |
ここで大切なのは、package 文はソースファイルの先頭に書くということです。
package pa.sub;
class Sample7
{
}package 文の前にクラス定義を書くことはできません。
また、クラス定義の途中に package 文を書くこともできません。
ドラゴンボール風にたとえると、巻物の一番上に「この巻物は pa.sub の棚に置く」と札を付けるようなものです。
package文とフォルダ構成は対応する
パッケージを階層に分けた場合、フォルダ構成もそれに対応させます。
package pa.sub; と書いた場合、ファイルは pa フォルダの下にある sub フォルダに保存します。
作業中フォルダを C:\Java\13 とすると、構成は次のようになります。
C:\Java\13
└─ pa
└─ sub
└─ Sample7.java
| package 文 | 保存場所 |
|---|---|
| package pa; | pa フォルダ |
| package pa.sub; | pa\sub フォルダ |
pa.sub というパッケージ名は、フォルダ構成では pa\sub に対応します。
| パッケージ名の部分 | フォルダ |
|---|---|
| pa | pa フォルダ |
| sub | pa の下の sub フォルダ |
この対応がずれると、Javaがクラスの場所を正しく見つけにくくなります。
ドラゴンボール風に言えば、巻物の札には pa.sub と書いてあるのに、実際には pa の棚だけに置いてしまうようなものです。
sub の棚まで用意して、そこに置く必要があります。
今回のサンプルで使う構成
今回は、pa.sub パッケージの中に Sample7.java を置きます。
Sample7.java の中には、ドラゴンボール風にアレンジした次の2つのクラスを書きます。
| クラス名 | 役割 |
|---|---|
| SaiyanWarrior | サイヤ人戦士の名前と流派を管理する |
| Sample7 | main メソッドを持ち、処理を開始する |
SaiyanWarrior は、サイヤ人戦士の情報を表すクラスです。
| SaiyanWarrior の要素 | 内容 |
|---|---|
| name | サイヤ人戦士の名前 |
| style | 流派 |
| setWarrior() | 名前と流派を設定する |
| show() | 現在の情報を表示する |
Sample7 は、SaiyanWarrior オブジェクトを作成して、show() を呼び出す実行用のクラスです。
| Sample7 の役割 | 内容 |
|---|---|
| main メソッドを持つ | プログラムの開始地点 |
| SaiyanWarrior を作る | サイヤ人戦士オブジェクトを作成する |
| show() を呼ぶ | サイヤ人戦士の情報を表示する |
どちらのクラスも、同じ Sample7.java の中にあり、先頭に package pa.sub; があるため、pa.sub パッケージに属します。
ファイル名:Sample7.java
package pa.sub;
// サイヤ人戦士クラス
class SaiyanWarrior
{
private String name;
private String style;
public SaiyanWarrior()
{
name = "未登録";
style = "流派未設定";
System.out.println("サイヤ人戦士を準備しました。");
}
public void setWarrior(String n, String s)
{
name = n;
style = s;
System.out.println("戦士名を" + name + "、流派を" + style + "にしました。");
}
public void show()
{
System.out.println("戦士名は" + name + "です。");
System.out.println("流派は" + style + "です。");
}
}
class Sample7
{
public static void main(String[] args)
{
SaiyanWarrior warrior1 = new SaiyanWarrior();
warrior1.show();
}
}実行結果
サイヤ人戦士を準備しました。
戦士名は未登録です。
流派は流派未設定です。このプログラムでは、SaiyanWarrior オブジェクトを作成し、show() を呼び出しています。
コンストラクタでは、name に 未登録、style に 流派未設定 を設定しています。
public SaiyanWarrior()
{
name = "未登録";
style = "流派未設定";
System.out.println("サイヤ人戦士を準備しました。");
}そのため、show() を呼び出すと、初期状態の戦士情報が表示されます。
public void show()
{
System.out.println("戦士名は" + name + "です。");
System.out.println("流派は" + style + "です。");
}package pa.sub; が表していること
Sample7.java の先頭には、次の1行があります。
package pa.sub;この1行によって、Sample7.java に書かれている SaiyanWarrior クラスと Sample7 クラスは、どちらも pa.sub パッケージに属します。
| クラス | 所属パッケージ | 役割 |
|---|---|---|
| SaiyanWarrior | pa.sub | サイヤ人戦士の情報を管理する |
| Sample7 | pa.sub | main メソッドで処理を開始する |
同じ pa.sub パッケージ内にあるため、Sample7 から SaiyanWarrior をそのまま使えます。
SaiyanWarrior warrior1 = new SaiyanWarrior();ここでは、pa.sub.SaiyanWarrior と書いていません。
同じパッケージ内にあるため、クラス名だけで自然に使えます。
ドラゴンボール風にたとえると、Sample7 の任務指令書と SaiyanWarrior の戦士名簿は、どちらも pa.sub の棚にあるため、同じ棚の巻物として扱いやすいということです。
図:package pa.sub; とフォルダ構成の関係

この図が示していること
この図では、package pa.sub; とフォルダ構成の対応を表しています。
左側では、C:\Java\13 の下に pa フォルダがあり、その下に sub フォルダがあります。
Sample7.java は、その sub フォルダの中に保存されています。
中央には package pa.sub; があり、右側には pa.sub パッケージに属する SaiyanWarrior クラスと Sample7 クラスがあります。
| 要素 | 対応 |
|---|---|
| package pa.sub; | pa.sub パッケージに属する |
| pa フォルダ | pa に対応する |
| sub フォルダ | sub に対応する |
| Sample7.java | pa\sub の中に保存する |
この図から分かることは、パッケージ名のピリオドが、フォルダ構成では階層として表れるということです。
コンパイルの方法
サブパッケージを使う場合も、コンパイルは作業中フォルダから行います。
今回のフォルダ構成は次のとおりです。
C:\Java\13
└─ pa
└─ sub
└─ Sample7.java
作業中フォルダが C:\Java\13 の場合、次のように入力します。
PS C:\Java\13>javac pa\sub\Sample7.java| コマンド | 意味 |
|---|---|
| javac pa\sub\Sample7.java | pa\sub フォルダ内の Sample7.java をコンパイルする |
パッケージが pa.sub なので、ファイルの場所は pa\sub\Sample7.java になります。
コンパイルが成功すると、Sample7.java の中にあるクラスに対応して、class ファイルが作成されます。
C:\Java\13
└─ pa
└─ sub
├─ Sample7.java
├─ SaiyanWarrior.class
└─ Sample7.class
| ソース内のクラス | 作成される class ファイル |
|---|---|
| SaiyanWarrior | SaiyanWarrior.class |
| Sample7 | Sample7.class |
1つのソースファイルの中に複数のクラスがある場合、コンパイル後はクラスごとに .class ファイルが作成されます。
実行の方法
実行するときは、main メソッドを持つクラスを指定します。
今回、main メソッドを持っているのは Sample7 クラスです。
ただし、Sample7 は pa.sub パッケージに属しています。
そのため、実行時にはサブパッケージまで含めて指定します。
PS C:\Java\13>java pa.sub.Sample7| 実行コマンド | 意味 |
|---|---|
| java pa.sub.Sample7 | pa.sub パッケージの Sample7 クラスを実行する |
ここで java pa.Sample7 と書いてはいけません。
Sample7 は pa パッケージではなく、pa.sub パッケージに属しているからです。
| 間違いやすい実行 | 理由 |
|---|---|
| java Sample7 | パッケージ名がない |
| java pa.Sample7 | sub が抜けている |
| java pa.sub.Sample7 | 正しい |
ドラゴンボール風にたとえると、Sample7 の巻物は pa の棚ではなく、pa の中の sub の棚に置かれています。
そのため、実行時にも pa.sub.Sample7 と、正しい住所で指定する必要があります。
通常のパッケージとの違い
サブパッケージを使っても、考え方そのものは通常のパッケージと大きく変わりません。
違うのは、階層が1段深くなることです。
| 項目 | 通常のパッケージ | サブパッケージ |
|---|---|---|
| package 文 | package pa; | package pa.sub; |
| 保存先 | pa フォルダ | pa\sub フォルダ |
| コンパイル | javac pa\SampleX.java | javac pa\sub\Sample7.java |
| 実行 | java pa.SampleX | java pa.sub.Sample7 |
| クラスの完全名 | pa.SampleX | pa.sub.Sample7 |
つまり、指定する名前やフォルダが少し長くなるだけです。
その代わり、クラスの役割を細かく整理できるようになります。
paとpa.subは別パッケージ
ここは特に大切です。
pa と pa.sub は、名前が似ていても別々のパッケージです。
| パッケージ | Javaでの扱い |
|---|---|
| pa | pa パッケージ |
| pa.sub | pa.sub パッケージ |
たとえば、次の2つのクラスがあったとします。
| クラスの完全名 | 意味 |
|---|---|
| pa.SaiyanWarrior | pa パッケージの SaiyanWarrior クラス |
| pa.sub.SaiyanWarrior | pa.sub パッケージの SaiyanWarrior クラス |
どちらも SaiyanWarrior というクラス名ですが、所属するパッケージが違うため、Javaでは別のクラスとして扱います。
ドラゴンボール風にたとえると、同じ SaiyanWarrior という名前の巻物でも、pa の棚にあるものと、pa.sub の棚にあるものは別の巻物です。
また、pa と pa.sub が別パッケージであることは、アクセス修飾子を学ぶときにも重要になります。
たとえば、無指定のクラスやメンバは、基本的に同じパッケージ内から使えます。
しかし、pa と pa.sub は別パッケージなので、名前が似ていても同じパッケージ扱いにはなりません。
サブパッケージを使うメリット
サブパッケージを使うと、プログラム全体の構造が整理しやすくなります。
| メリット | 内容 |
|---|---|
| 機能ごとに整理しやすい | 似た役割のクラスをまとめられる |
| 見通しがよくなる | どこに何があるか把握しやすい |
| クラス数が増えても管理しやすい | 大規模開発に向いている |
| 名前の衝突を避けやすい | 同名クラスでもパッケージ名で区別できる |
| 担当範囲を分けやすい | チーム開発で作業しやすい |
ドラゴンボール風のプログラムなら、次のような分け方もできます。
| パッケージ | 役割 |
|---|---|
| pa.character | サイヤ人戦士やナメック星戦士のクラス |
| pa.battle | 戦闘処理のクラス |
| pa.training | 修行メニューのクラス |
| pa.item | 戦闘装備や道具のクラス |
| pa.support | 補助処理のクラス |
このように整理すると、クラスが増えても全体の構造が見えやすくなります。
図:コンパイルと実行の流れ

この図が示していること
この図では、pa.sub パッケージを使ったときのコンパイルと実行の流れを表しています。
左側には、pa\sub フォルダの中に Sample7.java が保存されています。
Sample7.java の先頭には package pa.sub; が書かれています。
中央では、次のコマンドでコンパイルしています。
javac pa\sub\Sample7.javaコンパイル後には、pa\sub フォルダの中に SaiyanWarrior.class と Sample7.class が作成されます。
| クラス | class ファイル |
|---|---|
| SaiyanWarrior | SaiyanWarrior.class |
| Sample7 | Sample7.class |
実行するときは、main メソッドを持つ Sample7 を、サブパッケージまで含めて指定します。
java pa.sub.Sample7この図から分かることは、サブパッケージを使う場合、コンパイルではフォルダ階層を指定し、実行ではパッケージ名をピリオドでつないで指定するということです。
つまずきやすいポイント
サブパッケージを使うときは、次のようなところで混乱しやすいです。
| つまずきやすい点 | 気をつけたいこと |
|---|---|
| pa.sub は pa と同じパッケージだと思う | Javaでは pa と pa.sub は別パッケージ |
| pa フォルダだけ作ってしまう | package pa.sub; なら pa\sub が必要 |
| 実行時に java pa.Sample7 と書いてしまう | 正しくは java pa.sub.Sample7 |
| package 文と保存場所がずれる | package pa.sub; なら pa\sub に保存する |
| pa.sub.Sample7 と書く意味が分からない | pa.sub パッケージの Sample7 クラスという意味 |
特に大切なのは、package 文、保存場所、実行時の指定を一致させることです。
| 項目 | 今回の例 |
|---|---|
| package 文 | package pa.sub; |
| 保存場所 | pa\sub\Sample7.java |
| コンパイル | javac pa\sub\Sample7.java |
| 実行 | java pa.sub.Sample7 |
この4つがつながると、サブパッケージの基本がかなり分かりやすくなります。
アクセス修飾子の学習にもつながる
サブパッケージを理解すると、あとで学ぶアクセス修飾子の意味も見えやすくなります。
たとえば、Javaでは、無指定のクラスやメンバは、基本的に同じパッケージ内から利用できます。
ここで、pa と pa.sub を同じパッケージだと思っていると、アクセス範囲の理解で混乱しやすくなります。
| 関係 | 同じパッケージか |
|---|---|
| pa 内のクラス同士 | 同じパッケージ |
| pa.sub 内のクラス同士 | 同じパッケージ |
| pa と pa.sub | 別パッケージ |
pa と pa.sub は名前がつながっています。
しかし、Javaでは別パッケージです。
ドラゴンボール風にたとえると、同じ本部内に見えても、pa の棚と pa.sub の棚は管理区画が違うということです。
そのため、アクセスできる範囲を考えるときにも、別の棚として扱う必要があります。
パッケージを階層に分けるときの大事な感覚
パッケージを階層に分けるときは、次の感覚を持つと分かりやすくなります。
| 考え方 | 内容 |
|---|---|
| ピリオドは階層を表す | pa.sub のように書く |
| フォルダも階層にする | pa\sub のように配置する |
| サブパッケージは別パッケージ | pa と pa.sub は同じではない |
| 実行時は完全な名前を書く | java pa.sub.Sample7 |
| 役割ごとに整理できる | クラス数が増えても見通しがよくなる |
ドラゴンボール風に言えば、pa は大きな本部の棚、pa.sub はその中の補助任務専用の棚です。
Sample7.java の先頭に package pa.sub; と書くなら、実際の保存場所も pa\sub にします。
そして実行するときは、pa.sub.Sample7 と住所を最後まで指定します。
この流れが分かると、Javaのパッケージ階層はかなり自然に理解できます。
