Java入門|同じパッケージにクラスをまとめる

クラスを同じパッケージにそろえると、別ファイルでもひとつのチームのように扱える

前回は、クラスをパッケージに含める基本を見てきました。そこでつかみたい感覚は、クラスに所属先を持たせると、大きなプログラムでも整理しやすくなるということでしたね。

今回はそこから一歩進んで、別々のファイルに書かれたクラスを、同じパッケージにまとめる考え方を見ていきます。Javaの開発では、クラスごとにファイルを分けることがよくありますが、ただ分けるだけではなく、関連するクラスどうしを同じパッケージにそろえることがとても大切です。

たとえば、ドラゴンボールの世界をイメージして、戦士を表すクラスと、その戦士を使って処理を進めるクラスがあったとします。この2つが別ファイルに分かれていても、同じパッケージに入っていれば、自然に連携しながら使えるようになります。今回はそのしくみを、できるだけやさしく整理しながら見ていきましょう。

同じパッケージにまとめるとはどういうことか

Javaでは、クラスを別々のファイルに書いていても、同じ package 文を指定すれば、同じパッケージに属するクラスとして扱えます。

たとえば、戦士を表す Fighter クラスを別ファイルに書き、プログラムの開始地点になる Sample3 クラスを別ファイルに書いたとします。この2つのファイルの先頭に、どちらも

package pa;

と書いてあれば、両方とも pa パッケージの仲間として整理されます。

ここで大事なのは、ファイルが別でも、所属先が同じなら、関連するクラスどうしとして扱いやすいという点です。
ファイルは作業の単位、パッケージは整理の単位、と考えるとわかりやすいです。

なぜ同じパッケージにまとめるのか

クラスをファイルごとに分けるだけでも整理しやすくなりますが、さらに同じ役割や近い役割を持つクラスを同じパッケージにまとめると、全体の見通しがぐっとよくなります。

たとえば、ドラゴンボール風のプログラムで考えると、

  • 戦士の情報を持つクラス
  • 技の情報を持つクラス
  • バトルの開始を行うクラス

のように、関連するクラスがいくつも登場します。これらを同じパッケージにまとめておけば、同じグループとして把握しやすくなります。

表にすると、こんな違いがあります。

整理のしかた特徴
ファイルだけ分けるクラス単位では見やすくなる
パッケージもそろえる関連クラスのまとまりまで見えやすくなる

つまり、ファイル分割はクラスを探しやすくする工夫、パッケージはクラス同士の関係を整理する工夫、と考えると理解しやすいです。

今回の学習で押さえたいポイント

今回は、異なるファイルに書かれたクラスを同じパッケージに含めるのがテーマです。
ここで押さえたいポイントは次の3つです。

ポイント内容
ファイルは別でもよいクラスは別ファイルに書ける
package 文が同じなら同じパッケージになる同じ所属先として整理される
同じパッケージのクラスは使いやすい特別に難しい書き方をしなくても連携しやすい

この感覚がつかめると、Javaのクラス整理がかなりわかりやすくなってきます。

ドラゴンボール風の例で考える

今回は、戦士を表すクラスとして Fighter を考えます。
この Fighter クラスは、別ファイルに書かれていて、pa パッケージに含まれているものとします。

その Fighter クラスには、たとえば次のような役割を持たせるとわかりやすいです。

  • 戦士名を管理する
  • 戦闘力を管理する
  • 初期状態を表示する
  • 情報を設定するために setFighter メソッドを持つ
  • 状態を表示するために show メソッドを持つ

そして、Sample3 クラスは、その Fighter クラスを使って処理を始める役割を持ちます。

ここで大切なのは、Fighter クラスと Sample3 クラスは別ファイルに書かれていても、どちらも pa パッケージに属しているという点です。
この状態なら、Sample3 から Fighter を自然に利用できます。

サンプルプログラム:同じ pa パッケージ

このコードは、同じ pa パッケージに含まれている Fighter クラスを使う形にしています。

ファイル名:Sample3.java

package pa;

class Sample3 {
    public static void main(String[] args) {
        Fighter fighter1 = new Fighter();
        fighter1.show();
    }
}

ファイル名:Fighter.java

package pa;

// 戦士クラス
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 + "です。");
    }
}

このプログラムの意味

この Sample3.java では、main メソッドの中で Fighter 型のオブジェクトを作成し、その内容を表示しています。

Fighter fighter1 = new Fighter();
fighter1.show();

この2行は、これまで学んできたオブジェクトの使い方とほとんど同じです。
違うのは、Fighter クラスが別ファイルにあり、なおかつ同じ pa パッケージに属しているという点です。

つまり、Sample3.java だけを見るとシンプルですが、その裏では

  • Fighter クラスは別ファイルに書かれている
  • それでも同じ pa パッケージの仲間である
  • だから Sample3 からそのまま使える

というしくみが働いています。

実行したときのイメージ

Fighter クラスのコンストラクタで初期値を設定してあり、show メソッドでその状態を表示するようにしておけば、実行結果はたとえば次のような内容になります。

戦士を準備しました。
戦士名は未設定です。
戦闘力は0です。

フォルダの配置はどうなるか

同じパッケージにまとめるときは、ファイルどうしが別でも、保存場所はパッケージ名に対応したフォルダの中になります。
今回はパッケージ名が pa なので、作業中ディレクトリの下に pa フォルダを作り、その中にクラスファイルやソースファイルを置きます。

イメージとしては次のようになります。

ここでのポイントは、別ファイルに分かれていても、同じ pa フォルダの中に置くことです。
なぜなら、どちらも pa パッケージに属しているからです。

コンパイルのしかた

コンパイルは、作業中ディレクトリから行います。
たとえば作業中ディレクトリが C:\Java\13 なら、次のように入力します。

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

このとき、Sample3.java の中で Fighter クラスを使っているので、同じパッケージ内にそのクラスが正しく存在していれば、必要な形でコンパイルが進みます。

コンパイル後は、pa フォルダの中に class ファイルが作成されます。イメージは次のようになります。

このように、異なるファイルに書かれたクラスでも、同じパッケージに属していれば、関連したクラスとして一緒に扱っていけます。

実行のしかた

実行するときは、main メソッドを持っている Sample3 クラスを指定します。
ただし、パッケージに属しているので、クラス名だけではなく、パッケージ名もつけて実行します。

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

ここで pa.Sample3 と書くのは、Sample3 が pa パッケージに属しているからです。
この書き方をすることで、Javaは pa の中の Sample3 クラスを見つけて実行できます。

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

同じパッケージに属しているクラスどうしは、利用するときにパッケージを強く意識しなくてもよい場面が多くあります。
今回の Sample3.java でも、Fighter をそのまま書いて使えています。

これは、Sample3 も Fighter も同じ pa パッケージにいるからです。
同じグループの中にいる仲間のクラスは、比較的自然に連携できる、というイメージで考えるとわかりやすいです。

もし別のパッケージにあるクラスを使う場合には、もう少し意識することが増えます。
そのため、まずは同じパッケージ内のクラス利用をしっかり理解しておくことが、次の学習につながります。

ファイルが違っても同じ仲間にできる

ここで改めて大切なのは、ファイルが違うことと、パッケージが同じことは両立できるという点です。

初心者のうちは、

  • 別ファイルにある
  • だから別グループだろう

と感じやすいのですが、Javaではそうではありません。
ファイルは分かれていても、package pa; と書かれていれば、同じ pa パッケージの仲間です。

この関係を表にすると、次のようになります。

クラス書かれている場所所属
Fighter クラスFighter.javapa パッケージ
Sample3 クラスSample3.javapa パッケージ

つまり、ファイルの違いは作業の分担や整理のためのもの、パッケージの同一性はクラス同士のまとまりを示すもの、ということです。

図で整理すると見えやすい

この図では、Fighter.java と Sample3.java が別々のファイルとして描かれています。
両方とも同じ所属先にあることがひと目でわかります。

同じパッケージ内のクラスをそのまま利用できる関係を表現しています。

学習の最初につまずきやすいところ

この内容では、次のような点で混乱しやすいです。

つまずきやすい点理解のポイント
ファイルが違うと別扱いに思えるpackage 文が同じなら同じパッケージ
保存場所がわからなくなる同じパッケージなら同じ名前のフォルダに置く
実行方法で迷うjava パッケージ名.クラス名 の形で実行する
利用方法が変わると思う同じパッケージ内ならかなり自然に使える

特に、ファイルの分割パッケージの整理は別の考え方だと意識すると、頭の中が整理しやすくなります。

この学習が次につながる理由

同じパッケージにクラスをまとめられるようになると、Javaのプログラム構成がかなり見通しよくなります。
そしてこの理解は、この先の

  • 別パッケージのクラスを使う
  • import を使う
  • サブパッケージでさらに整理する

といった学習にもつながっていきます。

まずは、別ファイルでも、同じ package 文を書けば同じパッケージの仲間になるという基本をしっかり押さえることが大切です。
ここがわかると、Javaのクラス整理が一段とわかりやすくなってきます。