Java超|パッケージのしくみと使い方

パッケージは、Javaのクラスに住所を持たせるしくみ。戦士の巻物を棚ごとに整理すれば、大きなプログラムも迷わず管理できます。

Javaのプログラムが小さいうちは、クラスの数もそれほど多くありません。
そのため、どのクラスがどこにあるのかをあまり意識しなくても、学習を進めやすいです。

しかし、プログラムが大きくなってくると、使うクラスの数がどんどん増えていきます。

ドラゴンボール風にたとえると、最初は数人の戦士だけを管理すればよかったものが、だんだんサイヤ人戦士、ナメック星の治療戦士、修行メニュー係、戦闘任務係、気の技管理係、戦闘装備係など、多くの役割が増えていくようなものです。

クラスが増えると、次のような問題が起こりやすくなります。

困りごと内容
クラスが多すぎるどこに何があるのか探しにくくなる
同じ名前のクラスが出てくるどちらのクラスを使うのか分かりにくくなる
複数人で開発するクラスの配置が混乱しやすくなる
再利用しにくい関連するクラスのまとまりが見えにくくなる

たとえば、別々の人が SaiyanWarrior という名前のクラスを作ったとします。
片方は戦士のプロフィールを表すクラスで、もう片方は戦闘任務で使う一時データを表すクラスかもしれません。

名前だけを見ると、どちらを使いたいのか分かりにくくなります。

そこで登場するのが パッケージ です。

パッケージは、クラスをグループ分けして整理するためのしくみです。
イメージとしては、クラスをしまっておく整理棚や、クラスの住所のようなものです。

Javaのしくみドラゴンボール風のイメージ
クラス戦士や任務書などの巻物
パッケージ巻物を分類して置く棚
package 文この巻物がどの棚に属するかを示す札
パッケージ名.クラス名住所つきでクラスを指定する形

パッケージを使うと、クラスがどのまとまりに属しているのかをはっきり示せます。

この記事では、pa というパッケージを使いながら、パッケージの基本、保存場所、コンパイル方法、実行方法を順番に見ていきます。

パッケージとは何か

パッケージとは、Javaのクラスを分類して整理するためのしくみです。

クラスが少ないうちは、同じ場所に並べておいてもそれほど困りません。
しかし、クラスが増えてくると、機能ごとに分けて管理したほうが分かりやすくなります。

ドラゴンボール風にたとえると、すべての巻物を机の上にそのまま置くのではなく、次のように棚を分けて整理するイメージです。

入れるもの
戦士管理の棚SaiyanWarrior クラス
任務管理の棚BattleMission クラス
装備管理の棚BattleArmor クラス
戦闘管理の棚BattleManager クラス
技管理の棚KiTechnique クラス

Javaでは、この「棚」にあたるものがパッケージです。

たとえば、pa というパッケージを作ると、その中にクラスをまとめられます。

package pa;

このようにソースファイルの先頭に書くことで、そのファイル内のクラスは pa パッケージに属するクラスとして扱われます。

書き方意味
package pa;このファイル内のクラスは pa パッケージに属する
package パッケージ名;所属するパッケージを指定する

ここで大切なのは、package 文はファイルの先頭に書くという点です。

クラス定義の途中に書くものではありません。
最初に package pa; と書いて、このファイルのクラスがどのパッケージに属するのかをはっきり示します。

パッケージはクラスの住所のようなもの

パッケージは、クラスの住所と考えると分かりやすいです。

同じ名前の人がいても、住所が違えば区別できます。
それと同じように、同じ名前のクラスがあっても、パッケージが違えば区別できます。

たとえば、ドラゴンボール風に考えると、同じ SaiyanWarrior という名前の巻物があったとしても、所属する棚が違えば意味を分けられます。

パッケージクラス名意味のイメージ
paSaiyanWarrior学習用のサイヤ人戦士クラス
missionSaiyanWarrior任務管理用の戦士データ
battleSaiyanWarrior戦闘処理用の戦士情報

クラス名だけでは SaiyanWarrior です。
しかし、pa.SaiyanWarrior のようにパッケージ名を含めれば、どこに属する SaiyanWarrior なのかをはっきり示せます。

指定方法見え方
SaiyanWarriorクラス名だけ
pa.SaiyanWarriorpa パッケージに属する SaiyanWarrior
battle.SaiyanWarriorbattle パッケージに属する SaiyanWarrior

このように、パッケージを使うと、クラスの置き場所や所属が明確になります。

図:パッケージはクラスの住所になる

この図が示していること

この図では、パッケージを使わない場合と、パッケージを使ってクラスを整理する場合を比較しています。

左側では、複数のクラスが同じ場所に置かれているため、どこに何があるのか分かりにくくなっています。

右側では、pa、mission、battle のように棚が分かれており、それぞれの役割ごとにクラスが整理されています。

整理方法特徴
パッケージなしクラスが増えると探しにくい
パッケージありクラスの所属や役割が分かりやすい

この図から分かることは、パッケージはクラスの住所や整理棚として働き、大きなプログラムでも見通しをよくしてくれるということです。

パッケージが必要になる理由

パッケージは、単に見た目をきれいにするためだけのものではありません。

クラスが増えたときに、プログラム全体を整理しやすくするために重要です。

状況パッケージがない場合パッケージがある場合
クラス数が多いどこに何があるか把握しにくい分類して整理しやすい
同名クラスがある区別しにくいパッケージ名で区別できる
複数人で開発するクラスの配置が混乱しやすいグループごとに分担しやすい
再利用したいまとまりが見えにくい機能ごとにまとめやすい
大規模化するすべてが同じ場所に集まりやすい役割ごとに管理しやすい

ドラゴンボール風にたとえると、戦士名簿、任務書、戦闘装備台帳、気の技の巻物を全部同じ棚に放り込むと、探すのが大変になります。

しかし、棚に名前をつけて分類しておけば、必要な巻物を見つけやすくなります。

パッケージは、Javaのクラスをこのように整理するためのしくみです。

パッケージに含める書き方

クラスをパッケージに含めたいときは、ソースファイルの先頭に package 文を書きます。

今回は、pa というパッケージ名を使います。

package pa;

この1行を書くことで、そのファイル内に書かれているクラスは pa パッケージに属します。

たとえば、1つのファイルの中に SaiyanWarrior クラスと Sample2 クラスを書いた場合、どちらも pa パッケージに属します。

書く場所内容
ファイルの先頭package pa;
その後クラス定義を書く
結果ファイル内のクラスが pa パッケージに属する

ドラゴンボール風にたとえると、巻物の一番上に「この巻物は pa の棚に置く」と札を貼るようなものです。

ファイル名:Sample2.java

package pa;

// サイヤ人戦士クラス
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 Sample2
{
    public static void main(String[] args)
    {
        SaiyanWarrior warrior1 = new SaiyanWarrior();
        warrior1.setWarrior("蒼月", "亀仙流");
        warrior1.show();
    }
}

実行結果

サイヤ人戦士を準備しました。
戦士名を蒼月、流派を亀仙流に設定しました。
戦士名は蒼月です。
流派は亀仙流です。

package pa; が表していること

このプログラムでは、ファイルの先頭に次の1行があります。

package pa;

この1行によって、Sample2.java に書かれているクラスは pa パッケージに属します。

このファイルには、SaiyanWarrior クラスと Sample2 クラスがあります。

クラス所属するパッケージ役割
SaiyanWarriorpaサイヤ人戦士の情報を持つ
Sample2pamain メソッドを持ち、処理を開始する

SaiyanWarrior クラスも Sample2 クラスも、同じ pa パッケージの中にあります。

そのため、Sample2 クラスの main メソッドでは、SaiyanWarrior をそのまま使えます。

SaiyanWarrior warrior1 = new SaiyanWarrior();

ここで pa.SaiyanWarrior と書かなくても使えているのは、SaiyanWarrior と Sample2 が同じ pa パッケージに属しているからです。

ドラゴンボール風にたとえると、同じ棚にある巻物同士なので、わざわざ遠くの棚を指定しなくても参照しやすい、というイメージです。

SaiyanWarrior クラスの役割

SaiyanWarrior クラスは、サイヤ人戦士の情報を管理するクラスです。

このクラスには、次の2つのフィールドがあります。

フィールド役割
nameサイヤ人戦士の名前
style流派

コンストラクタでは、初期値を設定しています。

public SaiyanWarrior()
{
    name = "未登録";
    style = "流派未設定";
    System.out.println("サイヤ人戦士を準備しました。");
}

この時点では、戦士名は未登録、流派は流派未設定です。

その後、setWarrior() で名前と流派を設定します。

public void setWarrior(String n, String s)
{
    name = n;
    style = s;
    System.out.println("戦士名を" + name + "、流派を" + style + "に設定しました。");
}

最後に show() で、現在の情報を表示します。

public void show()
{
    System.out.println("戦士名は" + name + "です。");
    System.out.println("流派は" + style + "です。");
}
メソッド役割
SaiyanWarrior()初期値を設定して、サイヤ人戦士を準備する
setWarrior()戦士名と流派を設定する
show()戦士名と流派を表示する

Sample2 クラスの役割

Sample2 クラスには、main メソッドがあります。

class Sample2
{
    public static void main(String[] args)
    {
        SaiyanWarrior warrior1 = new SaiyanWarrior();
        warrior1.setWarrior("蒼月", "亀仙流");
        warrior1.show();
    }
}

この main メソッドが、プログラムの開始地点です。

処理の流れは次のとおりです。

順番処理内容
1new SaiyanWarrior()サイヤ人戦士オブジェクトを作成する
2setWarrior("蒼月", "亀仙流")名前と流派を設定する
3show()設定した情報を表示する

Sample2 は、SaiyanWarrior オブジェクトを作り、その情報を設定して表示する役割を持っています。

ドラゴンボール風にたとえると、Sample2 は出撃開始の指令書です。
SaiyanWarrior という戦士を呼び出し、蒼月という名前と亀仙流という流派を与え、最後に戦士情報を確認しています。

保存するときのフォルダ構成

パッケージを使うときは、ソースコードの書き方だけでなく、フォルダの配置も大切です。

package pa; と書いた場合は、pa というフォルダの中に Sample2.java を保存します。

たとえば、作業中のフォルダが C:\Java\13 の場合、構成は次のようになります。

C:\Java\13
        └─ pa
           └─ Sample2.java
場所内容
C:\Java\13作業中のフォルダ
paパッケージ名と対応するフォルダ
pa\Sample2.javapa パッケージに属するソースファイル

ここがパッケージ学習でとても大切なところです。

package pa; と書いたなら、pa フォルダの中にソースファイルを置きます。

ドラゴンボール風にたとえると、巻物に「pa の棚に置く」と書いたなら、実際にも pa の棚へ置く必要があるということです。

図:パッケージ名とフォルダ構成の関係

この図が示していること

この図では、package pa; と pa フォルダの関係を表しています。

左側では、作業中フォルダ C:\Java\13 の中に pa フォルダがあります。
その中に Sample2.java が保存されています。

Sample2.java の先頭には package pa; と書かれています。

つまり、ソースコード上のパッケージ名 pa と、実際のフォルダ名 pa が対応しています。

要素意味
package pa;このファイル内のクラスは pa パッケージに属する
pa フォルダpa パッケージに対応する保存場所
SaiyanWarrior クラスpa パッケージに属するクラス
Sample2 クラスpa パッケージに属する実行用クラス

この図から分かることは、パッケージは単なる名前ではなく、フォルダ構成とも対応しているということです。

コンパイルのしかた

コンパイルは、pa フォルダの中に入って行うのではなく、作業中のフォルダから行います。

作業中のフォルダが C:\Java\13 の場合、次のように入力します。

PS C:\Java\13>javac pa\Sample2.java

これは、pa フォルダの中にある Sample2.java をコンパイルするという意味です。

コマンド意味
javac pa\Sample2.javapa フォルダ内の Sample2.java をコンパイルする

コンパイルが成功すると、pa フォルダの中に class ファイルが作成されます。

この Sample2.java には SaiyanWarrior クラスと Sample2 クラスが書かれているため、通常は次の class ファイルが作られます。

C:\Java\13
        └─ pa
           ├─ Sample2.java
           ├─ SaiyanWarrior.class
           └─ Sample2.class
ソース内のクラス作成される class ファイル
SaiyanWarriorSaiyanWarrior.class
Sample2Sample2.class

1つのソースファイルの中に複数のクラスを書いている場合、それぞれのクラスに対応する class ファイルが作られます。

実行のしかた

実行するときも、作業中のフォルダから行います。

ただし、パッケージを使っている場合は、クラス名だけではなく、パッケージ名も含めて指定します。

PS C:\Java\13>java pa.Sample2

ここで大切なのは、java Sample2 ではなく、java pa.Sample2 と書くことです。

実行方法結果
java Sample2pa パッケージを指定していないため正しく見つからない
java pa.Sample2pa パッケージ内の Sample2 を指定できる

Sample2 クラスは pa パッケージに属しています。
そのため、実行時には pa.Sample2 の形で指定します。

これは、ドラゴンボール風にたとえると、ただ「Sample2 の巻物を持ってきて」と言うのではなく、「pa の棚にある Sample2 の巻物を持ってきて」と住所つきで指定するようなものです。

パッケージなしとパッケージありの違い

パッケージを使うと、保存場所、コンパイル方法、実行方法が少し変わります。

項目パッケージなしパッケージあり
package 文書かないpackage pa; と書く
保存場所作業中のフォルダ直下pa フォルダ内
コンパイルjavac Sample2.javajavac pa\Sample2.java
実行java Sample2java pa.Sample2
クラスの指定クラス名だけパッケージ名.クラス名

見た目は少し複雑に感じるかもしれません。

しかし、これはクラスに住所がついたからです。
住所があることで、大きなプログラムでもクラスを整理しやすくなります。

同じパッケージのクラスは使いやすい

このサンプルでは、SaiyanWarrior クラスと Sample2 クラスがどちらも pa パッケージに含まれています。

同じパッケージに属しているクラス同士は、パッケージ名を毎回書かなくても使いやすいです。

main メソッドでは、次のように SaiyanWarrior をそのまま使っています。

SaiyanWarrior warrior1 = new SaiyanWarrior();
warrior1.setWarrior("蒼月", "亀仙流");
warrior1.show();

ここで pa.SaiyanWarrior と書かなくても使えているのは、SaiyanWarrior と Sample2 が同じ pa パッケージの中にあるからです。

関係書き方
同じ pa パッケージ内SaiyanWarrior と書ける
別のパッケージから使う場合pa.SaiyanWarrior のように指定が必要になることがある

ドラゴンボール風にたとえると、同じ本部の棚にある巻物同士は、比較的スムーズに参照できるという感覚です。

パッケージ名とフォルダ名が対応する理由

パッケージを学ぶときに、なぜフォルダ名まで合わせる必要があるのか疑問に感じることがあります。

これは、Javaがパッケージ名とフォルダ構成を対応づけてクラスを探すからです。

たとえば、次のように書いている場合です。

package pa;

このクラスは、pa パッケージに属するクラスとして扱われます。

そのため、実際の保存場所も pa フォルダにしておく必要があります。

package 文対応するフォルダ
package pa;pa フォルダ
package mission;mission フォルダ
package battle;battle フォルダ

この対応が崩れると、Javaがクラスの場所を正しく見つけられなくなります。

ドラゴンボール風にたとえると、巻物の札には「pa の棚」と書いてあるのに、実際には別の棚に置かれている状態です。
これでは、探す側が迷ってしまいます。

図:パッケージありのコンパイルと実行の流れ

この図が示していること

この図では、pa パッケージを使ったときのコンパイルと実行の流れを表しています。

左側には、pa フォルダの中に Sample2.java が保存されています。
このファイルの先頭には package pa; があり、SaiyanWarrior クラスと Sample2 クラスが含まれています。

中央では、次のコマンドでコンパイルしています。

PS C:\Java\13>javac pa\Sample2.java

コンパイル後には、pa フォルダの中に class ファイルが作られます。

クラス作成されるファイル
SaiyanWarriorSaiyanWarrior.class
Sample2Sample2.class

実行するときは、次のように指定します。

PS C:\Java\13>java pa.Sample2

この図から分かることは、パッケージを使う場合、コンパイルではフォルダ付きで指定し、実行ではパッケージ名.クラス名で指定するということです。

package を指定しないとどうなるのか

ソースファイルに package 文を書かない場合、そのクラスは名前のないパッケージに含まれます。

これまで package 文を書かなくてもプログラムを実行できていたのは、多くの場合、同じ名前のないパッケージの中でクラスを扱っていたからです。

package 文クラスの所属
書かない名前のないパッケージ
package pa; と書くpa パッケージ

小さな学習プログラムでは、名前のないパッケージでも動かせることがあります。

しかし、クラスが増えてくると、名前のないパッケージのままでは整理しにくくなります。

ドラゴンボール風にたとえると、すべての巻物が名前のない棚に置かれている状態です。
少ないうちは問題ありませんが、巻物が増えると探しにくくなります。

そこで、pa のように名前をつけたパッケージを使い、クラスをグループ分けしていきます。

学習の最初に押さえておきたいこと

パッケージの基本では、まず次の点を押さえておくと安心です。

覚えておきたいこと内容
package 文を書くファイルの先頭で所属パッケージを指定する
フォルダ名を合わせるパッケージ名と同じ名前のフォルダを作る
作業中フォルダからコンパイルするjavac pa\Sample2.java の形で指定する
実行時はパッケージ名も書くjava pa.Sample2 の形で指定する
同じパッケージのクラスは使いやすい同じグループ内で自然に利用できる

特に大切なのは、次の3つです。

大事なポイント
ファイルの先頭に package 文を書くpackage pa;
保存場所をパッケージ名と合わせるpa\Sample2.java
実行時にパッケージ名を含めるjava pa.Sample2

この3つがつながると、パッケージの基本がかなり分かりやすくなります。

パッケージを使うと次の学習が見えやすくなる

パッケージの基本を理解すると、次に学ぶ内容もつながって見えやすくなります。

次に学ぶ内容パッケージとの関係
名前空間同じ名前のクラスを区別する考え方につながる
サブパッケージパッケージをさらに階層的に整理する
インポート別パッケージのクラスを使いやすくする
クラスライブラリたくさんのクラスを整理して利用する考え方につながる

クラスが増えるほど、整理する工夫が必要になります。

パッケージは、その最初の一歩です。

ドラゴンボール風にたとえると、ただ巻物を増やすだけではなく、戦士管理、任務管理、装備管理、戦闘管理のように棚を分けていく感覚です。

パッケージで大切な感覚

パッケージは、難しいものに見えるかもしれません。

しかし、中心になる考え方はとてもシンプルです。

クラスをグループ分けして、どこに属しているかをはっきりさせる。

この感覚を押さえると、package 文、フォルダ構成、コンパイル、実行の流れがつながって見えてきます。

考え方内容
パッケージはクラスの住所pa.Sample2 のように場所つきで指定できる
package 文は所属を示すpackage pa; と書く
フォルダ名と対応するpa フォルダに保存する
実行時は住所つきで指定するjava pa.Sample2
大きなプログラムで役立つクラスを整理しやすくなる

パッケージを理解すると、Javaのクラスがただバラバラに置かれているのではなく、整理された住所を持って管理されていることが分かります。

これが見えると、大きなJavaプログラムの見通しがぐっとよくなります。