QA@IT

javaパッケージの働きとコンパイルについての質問です。

3997 PV

javaプログラムのパッケージについての質問です。

例えば、「MSパッケージ内のGundamクラスからshowメソッドを呼び出し、"俺達がガンダムだ!"」と表示させたい場合。

MSフォルダを作成し、パッケージMSを宣言したGundamクラスを作成。

package MS;

public class Gundam{

public void show(){

System.out.println("俺達がガンダムだ!");
}

}

メインクラスで、使いたいパッケージをインポートし、呼び出すメインプログラムを作成。

// MSパッケージのインポート宣言
import MS.Gundam;

class GundamMain{

public static void main(String[] args){

     // Gundamクラスのインスタンス化
Gundam sub = new Gundam();

     // showメソッドの呼び出し
sub.show();

}

}

フォルダ構成としては、私はCドライブ内に「WORK」フォルダを作成し、その中で上記のプログラムとMSフォルダを作成しています。

コンパイル方法としては、

まずCドライブ内のWORKフォルダを参考にするので、

cd C:\WOKK 
dir

と入力し、WOKKフォルダ内のjavaソースファイル一覧を表示した後、

javac MS/*.java

javac GundamMain.java

java GundamMain

と入力すれば、MSパッケージ内のGundamクラスからshowメソッドが呼び出され、

"俺達がガンダムだ!"と表示されます。ここまでは理解しています。

ここからが本題なのですが。

Gundamというフォルダの中に、「Zaku,Gufu,Dom」という3つのフォルダがあり、更に、

Zakuフォルダの中には「shaaフォルダ」があり、shaaフォルダの中には「NTフォルダ」があり、
NTフォルダ内には、

Packaei NT;

public class Gerugugu{

public void show(){

    System.out.println("私にも敵が見える!");
}

}

というGeruguguクラスがあります。

Gufuフォルダの中には「Raruフォルダ」があり、Raruフォルダ内には、
Package Raru;

public class Ranba{

public void show(){

    System.out.println("ザクとは違うのだよ!ザクとは!");
}

}

というRanbaクラスがあります。

Domフォルダの中には「Gaiaフォルダ」があり、Gaiaフォルダ内の以下のプログラムから、上記2つのクラスを呼び出したい時に、

// インポート宣言
import NT.Gerugugu;

import Raru.Ranba;

class Gaia{

public static void main(String[] args){

    // Geruguguクラスのインスタンス化

   Gerugugu sub1 = new Gerugugu();

    // Ranbaクラスのインスタンス化
    Ranba sub2 = new Ranba();

   // showメソッドの呼び出し

   sub1.show();

   sub2.show();
}

}

というところまで書きました。そこで質問なのですが。

①各クラスのコードの記述の仕方はこれであっているでしょうか?

②コンパイルと実行の仕方はどうするのでしょうか?

これまで私は上記にも書きましたが、WOKRフォルダ内にjavaソースファイルを記述していたので、
単純な、

コンパイル:javac Class01.java

実行:java Class01

というようなコンパイル方法しか知らないのです。ネットで調べましたが、ピンと来るものがなかったので、
質問した次第であります。どなたかよろしくお願い致します。

  • 新しい質問の前に、まずは過去のあなたの解決済みの質問に対してベストアンサーをつけましょう。 -

回答

とりあえず回答を読む前に、質問のコメントに書いたように解決している過去の質問に関してベストアンサーをつけてください。
(一覧で未解決に見えるので、回答する上でとてもわかりにくくなりますのでお願いします。)

javac コンパイラは、コンパイルしようとしているクラスが利用しているとわかるものは自動的にコンパイルしてくれます(というか参照クラスのメソッドなどがわからないと正しいかどうか判断できないので)。

というわけで最初の例ですが、

work/GundamMain.java
work/MS/Gundam.java

で、GundamMain.javaがGundamクラスを利用していることをjavacは検知できるので、

cd c:\work
javac GundamMain.java
java GundamMain

で実行できます(Gundam.javaもコンパイルされます)。


①各クラスのコードの記述の仕方はこれであっているでしょうか?

構成をどのように考えているか次第です。
間違っているとも言えませんが、ディレクトリ構成的には望んでいる形ではないでしょう。

②コンパイルと実行の仕方はどうするのでしょうか?

とりあえずこのディレクトリ構成とソースのままで実行する事を考えた場合、

import NT.Gerugugu => NT/Gerugugu.class が必要
import Raru.Ranba  => Raru/Ranba.class が必要

となりますので、そういう関係になる場所でjavacを実行する必要があります。

C:\Gundam>cd Zaku\shaa\

C:\Gundam\Zaku\shaa>javac NT\Gerugugu.java

C:\Gundam\Zaku\shaa>cd ..\..\Gufu

C:\Gundam\Gufu>javac Raru\Ranba.java

C:\Gundam\Gufu>

C:\Gundam\Dom>javac -cp c:\Gundam\Gufu;c:\Gundam\Zaku\shaa; Gaia.java

C:\Gundam\Dom>java -cp c:\Gundam\Gufu;c:\Gundam\Zaku\shaa; Gaia
私にも敵が見える!
ザクとは違うのだよ!ザクとは!

cpとはクラスパスの事です。
これだけでは何が起きてるのかわからないと思いますが、簡単に説明します。
細かい部分は説明しませんので概要と思ってください。

javaではpackageはそのままディレクトリ構成に反映されます。
例えば Gerugugu.javaは NTパッケージですので、javacを起動するディレクトリにある NTというディレクトリの下にないといけません。
現状それが満たされるのは、shaaディレクトリです。
shaaディレクトリで NT\Gerugugu.java をビルドすれば、NTパッケージのGerugug.classとしてコンパイルできます。
Ranbaクラスも同様に、Raruパッケージなので、「RaruディレクトリのRanba.java」となるようにコンパイルする必要があります。

Gaia.javaに関しては、NT\Geruguguクラス、Raru\Ranbaクラスを必要とします。
最初の例のように、Domディレクトリの下にNTディレクトリ、Raruディレクトリがあって以下の様になっていればよかったのですが残念ながらそういうディレクトリ構成になっていません。

DOM/Gaia.java
DOM/NT/Gerugugu.java
DOM/Raru/Ranba.java

離れたところにあるクラスやライブラリを使ってほしいときにクラスパスを指定して「ここもみて」とjavacやjavaに伝えることができます。
これによってコンパイルなどの際に近くに見当たらなければクラスパスから探すようになり
「c:\Gundam\Gufu」から「RaruパッケージのRanbaクラス」、「c:\Gundam\Zaku\shaa」から「NTパッケージのGeruguguクラス」を見つけてくれます。
※ このとき 「c:\Gundam\Gufu\Raru」ディレクトリを指定しないのも「packageはそのままディレクトリ構成に反映される」事が関係しています。

という事で、一つの解決方法としてはこういう方法があります。


さて、
今回でいえばせっかくすべてGundamディレクトリの中に収めているので別の解決方法もあります。

まずそれぞれのパッケージを変更します。

Ranba.java

package Gufu.Raru;

以下変更なしなので省略

Gerugugu.java

package Zaku.shaa.NT;

以下変更なしなので省略

Gaia.java はパッケージを追加と、importを変更

package Dom;

import Zaku.shaa.NT.Gerugugu;
import Gufu.Raru.Ranba;

以下変更なしなので省略

そして、Gundamディレクトリでコンパイルします

C:\Gundam>javac Dom\Gaia.java

実行はディレクトリではなく importの時の様に、Package.ClassName で指定します。

C:\Gundam>java Dom.Gaia
私にも敵が見える!
ザクとは違うのだよ!ザクとは!

C:\Gundam>java Dom\Gaia はエラーになります)

パッケージ構成を、Gundamディレクトリからみた形になっています。
そのためGundamディレクトリからクラスパスを指定せずにコンパイル・実行することができました。

最後の例に加え、3つのjavaファイルの package(とimport)の最初にGundamを付けていた場合は、C:\ でコンパイルできます。

C:\>javac Gundam\Dom\Gaia.java

c:\>java Gundam.Dom.Gaia

どれが正しいという事はなく、どこのディレクトリをパッケージのルートとしたいのかによって変わってきます。
パッケージの構成も設計の一環となります。

というわけで、
① は状況により、あっているかあっていないかはどちらかといえばあなたが望んでいる構成になっているかどうか次第です。
② は上に示した通りです。

編集 履歴 (1)
  • flied_onion様、回答ありがとう御座います。今までコンパイルと実行を特に深く考えず行ってきていたので、とても勉強になりました。重ねて感謝申し上げます。 -
ウォッチ

この質問への回答やコメントをメールでお知らせします。