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

別々の巻物に書かれたクラスでも、同じパッケージにそろえれば、ひとつの戦士チームとして自然に連携できます。

Javaでは、クラスごとにファイルを分けてプログラムを書くことがよくあります。

たとえば、サイヤ人戦士の情報を表すクラスを SaiyanWarrior.java に書き、プログラムの開始地点になるクラスを Sample3.java に書くような形です。

ファイルを分けると、クラスごとの役割がはっきりします。
SaiyanWarrior.java には戦士の情報を管理する処理を書く。
Sample3.java には main メソッドを書いて、プログラムを開始する。

このように役割を分けると、プログラムは読みやすくなります。

ただし、Javaでは、ただファイルを分けるだけではなく、関連するクラスを同じパッケージにまとめることも大切です。

ドラゴンボール風にたとえると、サイヤ人戦士の名簿、出撃開始の指令書、気の技の記録が、それぞれ別々の巻物に書かれているとします。

巻物は別でも、すべて同じ戦士管理本部の棚に置かれていれば、同じチームの資料として扱いやすくなります。

Javaでも同じです。

SaiyanWarrior クラスと Sample3 クラスが別々のファイルに書かれていても、どちらも同じ pa パッケージに属していれば、同じグループのクラスとして自然に連携できます。

今回のポイントは、次の感覚です。

考え方内容
ファイルクラスを書く作業単位
パッケージ関連するクラスをまとめる整理単位
同じ package 文同じパッケージの仲間であることを示す
同じフォルダパッケージ名に対応した保存場所

つまり、ファイルは別でも、package 文が同じなら同じパッケージの仲間になる ということです。

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

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

たとえば、次の2つのファイルがあるとします。

ファイル名書かれているクラス役割
SaiyanWarrior.javaSaiyanWarrior クラスサイヤ人戦士の情報を管理する
Sample3.javaSample3 クラスmain メソッドを持ち、処理を開始する

この2つのファイルの先頭に、どちらも次のように書きます。

package pa;

すると、SaiyanWarrior クラスも Sample3 クラスも、どちらも pa パッケージに属するクラスになります。

クラスファイル所属パッケージ
SaiyanWarriorSaiyanWarrior.javapa
Sample3Sample3.javapa

ドラゴンボール風にたとえると、SaiyanWarrior.java は戦士名簿の巻物、Sample3.java は出撃開始の指令書です。

巻物は別々です。
しかし、どちらにも「pa の棚に置く」という札が付いています。

そのため、別々の巻物でも、同じ棚に属する仲間として扱えるわけです。

ファイルが別でも同じ仲間にできる

初心者のうちは、別ファイルに書いたクラスは、まったく別の場所にあるクラスだと感じやすいです。

しかし、Javaでは、ファイルが別かどうかと、パッケージが同じかどうかは別の考え方です。

見方意味
ファイルが別コードを書く場所が分かれている
パッケージが同じクラスの所属グループが同じ
同じフォルダに保存パッケージ名に対応した場所に置いている

つまり、SaiyanWarrior.java と Sample3.java が別ファイルでも、どちらにも package pa; と書かれていれば、同じ pa パッケージのクラスです。

ここをしっかり分けて考えると、パッケージの理解がかなり楽になります。

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

ドラゴンボール風に言えば、巻物が2本に分かれていても、どちらも同じ戦士管理本部の棚に置かれている状態です。

ファイルの違いは「どの巻物に書かれているか」の違いです。
パッケージの違いは「どの棚に所属しているか」の違いです。

この2つを分けて考えることが、今回の大きなポイントです。

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

クラスをファイルごとに分けるだけでも、ある程度は整理できます。

しかし、関連するクラスを同じパッケージにまとめると、さらに全体の見通しがよくなります。

たとえば、ドラゴンボール風の学習プログラムで考えると、次のようなクラスが出てきます。

クラス役割
SaiyanWarriorサイヤ人戦士の情報を管理する
KiTechnique気の技を管理する
BattleMission任務情報を管理する
BattleManager戦闘の進行を管理する
Sample3処理を開始する

これらが関連する学習用のクラスなら、同じ pa パッケージにまとめることで、ひとつのまとまりとして把握しやすくなります。

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

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

ドラゴンボール風にたとえると、ファイル分割は巻物を分けることです。
パッケージは、その巻物を同じ棚に分類することです。

つまり、ファイル分割とパッケージ整理は、どちらもクラスを見やすくするための工夫ですが、見ている視点が違います。

同じパッケージにまとめると何が便利なのか

同じパッケージに属しているクラス同士は、自然に連携しやすくなります。

今回の例では、Sample3 クラスから SaiyanWarrior クラスを使います。

Sample3.java と SaiyanWarrior.java は別ファイルです。
しかし、どちらも pa パッケージに属しています。

そのため、Sample3.java の中では、次のように SaiyanWarrior をそのまま使えます。

SaiyanWarrior warrior1 = new SaiyanWarrior();

ここで pa.SaiyanWarrior のように毎回パッケージ名を付けなくても、同じパッケージ内なので自然に扱えます。

状況クラスの使いやすさ
同じパッケージ内クラス名をそのまま使いやすい
別パッケージimport やパッケージ名を意識する場面が増える

ドラゴンボール風にたとえると、同じチームの棚にある巻物同士なので、必要な巻物をすぐ参照できるようなものです。

同じ本部の棚にある資料なら、毎回「どこの棚の巻物か」を細かく指定しなくても扱いやすい、という感覚です。

図:別ファイルでも同じ pa パッケージの仲間になる

この図が示していること

この図では、Sample3.java と SaiyanWarrior.java が別々のファイルでありながら、どちらも pa パッケージに属していることを表しています。

左側には pa フォルダがあり、その中に Sample3.java と SaiyanWarrior.java の2つの巻物があります。

どちらの巻物にも package pa; と書かれています。
そのため、右側では Sample3 クラスと SaiyanWarrior クラスが、pa パッケージの仲間として整理されています。

分かること内容
ファイルは別でよいSample3.java と SaiyanWarrior.java は別々のファイル
パッケージは同じにできるどちらも package pa; によって pa パッケージに属する

つまり、ファイルの違いは作業上の分割であり、パッケージはクラスの所属を表すものです。

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

今回の中心は、異なるファイルに書かれたクラスを、同じパッケージに含めることです。

押さえたいポイントは次の3つです。

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

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

特に大切なのは、次の考え方です。

別々のファイルに分けることと、別々のパッケージに分けることは同じではありません。

別々のファイルに書かれていても、同じ package pa; を書けば、同じ pa パッケージの仲間になります。

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

今回は、サイヤ人戦士を表すクラスとして SaiyanWarrior クラスを使います。

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

SaiyanWarrior クラスが持つもの内容
nameサイヤ人戦士の名前
style流派
setWarrior()戦士名と流派を設定する
show()現在の戦士情報を表示する

一方、Sample3 クラスは、SaiyanWarrior クラスを使って処理を開始するクラスです。

Sample3 クラスの役割内容
main メソッドを持つプログラムの開始地点になる
SaiyanWarrior オブジェクトを作るサイヤ人戦士を準備する
show() を呼ぶ戦士情報を表示する

ここで大切なのは、SaiyanWarrior クラスと Sample3 クラスが別ファイルに書かれていることです。

しかし、どちらも先頭に package pa; を書くため、同じ pa パッケージに属します。

ファイル名:Sample3.java

package pa;

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

ファイル名:SaiyanWarrior.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 + "です。");
    }
}

実行結果

サイヤ人戦士を作成しました。
戦士名は未登録です。
流派は流派未設定です。

2つのファイルに同じ package pa; を書く意味

Sample3.java の先頭には、次のように書かれています。

package pa;

SaiyanWarrior.java の先頭にも、同じように書かれています。

package pa;

この2つの package 文によって、Sample3 クラスと SaiyanWarrior クラスは同じ pa パッケージの仲間になります。

ファイル先頭の package 文所属パッケージ
Sample3.javapackage pa;pa
SaiyanWarrior.javapackage pa;pa

ここで、ファイルが別々であることは問題ではありません。

Javaでは、同じ package 文を書いて、対応するフォルダに置けば、同じパッケージのクラスとして扱えます。

ドラゴンボール風にたとえると、Sample3.java は出撃開始の指令書、SaiyanWarrior.java は戦士名簿です。

巻物は別でも、どちらにも pa の棚に置く札が付いているため、同じ棚の仲間として扱えます。

Sample3 クラスが SaiyanWarrior クラスを使う流れ

Sample3 クラスの main メソッドでは、次の2行が中心です。

SaiyanWarrior warrior1 = new SaiyanWarrior();
warrior1.show();

1行目では、SaiyanWarrior クラスから warrior1 オブジェクトを作成しています。

SaiyanWarrior warrior1 = new SaiyanWarrior();

2行目では、その warrior1 オブジェクトの show() を呼び出しています。

warrior1.show();

処理の流れを整理すると、次のようになります。

順番処理内容
1new SaiyanWarrior()サイヤ人戦士オブジェクトを作成する
2コンストラクタが動くname と style に初期値を入れる
3warrior1.show()現在の戦士情報を表示する

SaiyanWarrior クラスは別ファイルにあります。
しかし、同じ pa パッケージに属しているため、Sample3 から自然に使えます。

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()戦士名と流派を表示する

今回の Sample3.java では setWarrior() は呼び出していません。
そのため、show() では初期値である未登録と流派未設定が表示されます。

フォルダの配置

同じ pa パッケージにまとめる場合、Sample3.java と SaiyanWarrior.java は、どちらも pa フォルダの中に保存します。

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

C:\Java\13
        └─ pa
           ├─ Sample3.java
           └─ SaiyanWarrior.java
場所内容
C:\Java\13作業中のフォルダ
papa パッケージに対応するフォルダ
pa\Sample3.javaSample3 クラスを書くファイル
pa\SaiyanWarrior.javaSaiyanWarrior クラスを書くファイル

ここで大切なのは、どちらのファイルも pa フォルダの中に置くことです。

なぜなら、どちらのファイルにも package pa; と書かれているからです。

ドラゴンボール風にたとえると、どちらの巻物にも「pa の棚に所属する」と書かれているので、実際にも pa の棚に置く必要があります。

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

この図が示していること

この図では、Sample3.java と SaiyanWarrior.java を同じ pa パッケージに置いたときの、コンパイルと実行の流れを表しています。

左側では、pa フォルダの中に2つのソースファイルがあります。

ソースファイル内容
Sample3.javamain メソッドを持つ実行用クラス
SaiyanWarrior.javaサイヤ人戦士情報を管理するクラス

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

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

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

ソースファイルclass ファイル
Sample3.javaSample3.class
SaiyanWarrior.javaSaiyanWarrior.class

実行するときは、Sample3 が pa パッケージに属しているため、次のように指定します。

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

この図から分かることは、同じパッケージにある別ファイルのクラスでも、コンパイル後は同じ pa フォルダ内の class ファイルとして連携して動くということです。

コンパイルのしかた

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

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

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

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

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

Sample3.java の中では SaiyanWarrior クラスを使っています。

SaiyanWarrior warrior1 = new SaiyanWarrior();

同じ pa パッケージ内に SaiyanWarrior.java が正しく存在していれば、必要に応じて SaiyanWarrior クラスも一緒にコンパイルされます。

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

C:\Java\13
        └─ pa
           ├─ Sample3.java
           ├─ SaiyanWarrior.java
           ├─ Sample3.class
           └─ SaiyanWarrior.class
ソースファイルコンパイル後のファイル
Sample3.javaSample3.class
SaiyanWarrior.javaSaiyanWarrior.class

.java ファイルは人が読むソースファイルです。
.class ファイルは Java が実行できる形に変換されたファイルです。

ドラゴンボール風にたとえると、.java ファイルは人が読める巻物です。
.class ファイルは Java が実行できる戦闘用の符号札のようなものです。

実行のしかた

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

この例では、main メソッドを持っているのは Sample3 クラスです。

ただし、Sample3 クラスは pa パッケージに属しています。

そのため、実行するときは、クラス名だけではなく、パッケージ名も含めて指定します。

PS C:\Java\13>java pa.Sample3
実行コマンド意味
java pa.Sample3pa パッケージに属する Sample3 クラスを実行する

ここで java Sample3 ではなく、java pa.Sample3 と書く点が大切です。

Sample3 は pa パッケージの中にあるクラスです。
そのため、実行時にも pa.Sample3 のように、住所つきで指定します。

ドラゴンボール風にたとえると、ただ「Sample3 の巻物を探す」のではなく、「pa の棚にある Sample3 の巻物を探す」ように指定しているわけです。

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

同じパッケージに属しているクラス同士は、利用するときにパッケージ名を強く意識しなくてもよい場面が多いです。

今回の Sample3.java でも、SaiyanWarrior をそのまま書いて使えています。

SaiyanWarrior warrior1 = new SaiyanWarrior();

これは、Sample3 も SaiyanWarrior も同じ pa パッケージにいるからです。

クラス所属
Sample3pa
SaiyanWarriorpa

同じグループにいる仲間のクラスは、比較的自然に連携できます。

もし SaiyanWarrior が別のパッケージにある場合は、パッケージ名を付けたり、import を使ったりする必要が出てきます。

まずは、同じパッケージ内のクラス利用をしっかり理解しておくと、このあとの import の学習にもつながります。

ファイル分割とパッケージ整理は別の考え方

ここで、特に大切な整理をしておきます。

ファイル分割とパッケージ整理は、似ているようで別の考え方です。

考え方何を整理するか
ファイル分割クラスを書く場所を分けるSample3.java と SaiyanWarrior.java に分ける
パッケージ整理クラスの所属グループを決めるどちらも pa パッケージにする

ファイルが分かれているから別グループになるわけではありません。
同じ package pa; が書かれていれば、同じ pa パッケージのクラスです。

ドラゴンボール風にたとえると、巻物が別々だからといって、別の部隊に属するとは限りません。
同じ棚に置かれていれば、同じ部隊の資料として扱えます。

つまり、ファイルは作業単位、パッケージは整理単位です。

この違いを押さえておくと、ファイル分割とパッケージの関係がすっきり理解できます。

図:ファイル分割とパッケージ整理の違い

この図が示していること

この図では、ファイル分割とパッケージ整理の違いを表しています。

左側では、Sample3.java と SaiyanWarrior.java が別々のファイルとして分かれています。
これは、クラスを書く場所を分けている状態です。

右側では、Sample3 と SaiyanWarrior が同じ pa パッケージの棚に入っています。
これは、クラスの所属グループを同じにしている状態です。

見方内容
ファイル分割コードを書く場所を分ける
パッケージ整理クラスの所属グループを決める

この図から分かることは、ファイルが別でも、同じ package 文を書けば同じパッケージの仲間として扱えるということです。

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

同じパッケージにクラスをまとめる学習では、いくつか混乱しやすいポイントがあります。

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

特に大切なのは、作業中フォルダからコンパイルと実行を行うことです。

今回の構成では、作業中フォルダは C:\Java\13 です。

操作実行する場所コマンド
コンパイルC:\Java\13javac pa\Sample3.java
実行C:\Java\13java pa.Sample3

pa フォルダの中に入って java Sample3 と実行するのではなく、作業中フォルダから pa.Sample3 と指定するのがポイントです。

ドラゴンボール風にたとえると、pa の棚の中に直接入って探すのではなく、戦士管理本部の入口から「pa の棚にある Sample3」を指定して取り出すような感覚です。

同じパッケージにまとめると次の学習につながる

同じパッケージにクラスをまとめる考え方が分かると、この先の内容も理解しやすくなります。

次に学ぶ内容つながり
別パッケージのクラスを使う同じパッケージとの違いが分かる
import を使う別のパッケージのクラスを短い名前で使えるようにする
サブパッケージで整理するpa.sub のように階層的に整理できる
アクセス修飾子同じパッケージ内で見える範囲の理解につながる

まずは、別ファイルでも同じ package 文を書けば同じパッケージの仲間になる、という基本をしっかり押さえることが大切です。

ドラゴンボール風にたとえると、別々の巻物でも、同じ棚に置かれていれば同じチームの資料として扱える、という感覚です。

この感覚があると、import やアクセス修飾子を学ぶときにも理解がつながりやすくなります。

同じパッケージで大切な感覚

同じパッケージにクラスをまとめるときの中心は、とてもシンプルです。

ファイルは別でも、所属するパッケージが同じなら、同じチームのクラスとして扱える。

この感覚を持っておくと、Javaのクラス整理がぐっと分かりやすくなります。

大切な考え方内容
別ファイルでも同じ仲間にできるpackage pa; が同じなら pa パッケージ
同じフォルダに置くpa パッケージなら pa フォルダへ保存
同じパッケージ内では使いやすいSaiyanWarrior をそのまま利用できる
実行時はパッケージ名を付けるjava pa.Sample3
ファイルとパッケージは役割が違うファイルは作業単位、パッケージは整理単位

Javaのプログラムでは、クラスが増えるほど整理の力が大切になります。

SaiyanWarrior.java と Sample3.java を別々に書きながら、どちらも pa パッケージにそろえる。
この考え方が分かると、大きなプログラムを作るときにも、クラス同士の関係をきれいに整理できるようになります。