Java プログラミング

[java] クラスパスとパッケージを理解するために行ったこと

投稿日:2021年2月15日 更新日:

本記事ではjavaでコンパイルする際に利用するクラスパスとパッケージについてを理解するために行ったことを備忘録としてまとめていきます。

[java] クラスパスとパッケージを理解するために行ったこと

  • 環境
  • 実施したこと
    • コンパイルとビルド
    • 分割コンパイルとビルド(クラスパスについて)
    • パッケージ化とビルド

環境

  • win10
  • jdk11※事前にパスは通しておく

実施したこと

用意するフォルダ構成とファイルは以下の通りです。

C:\Users\yuya\javatest>dir
 C:\Users\yuya\javatest のディレクトリ
2021/02/15  01:49    <DIR>          .
2021/02/15  01:49    <DIR>          ..
2021/02/15  01:48               229 SampleMain.java
  • javatest(プロジェクトのフォルダ)
    • SampleMain.java
public class SampleMain {
    public static void main(String[] args){
        System.out.println("SampleMain Loaded");
    }
}

コンパイルとビルド

SampleMain.javaをjavacコマンドでコンパイルします。

C:\Users\yuya\javatest>javac SampleMain.java
C:\Users\yuya\javatest>dir
 C:\Users\yuya\javatest のディレクトリ
2021/02/15  01:50    <DIR>          .
2021/02/15  01:50    <DIR>          ..
2021/02/15  01:50               469 SampleMain.class
2021/02/15  01:48               229 SampleMain.java

SampleMain.classが生成されるのでこれをjavaコマンドで実行します。

C:\Users\yuya\javatest>java SampleMain
SampleMain Loaded

分割コンパイルとビルド(クラスパスについて)

先ほど作成したclassファイルは削除して、分割コンパイル用に`Sample.java`ファイルを追加します。

C:\Users\yuya\javatest>dir
 C:\Users\yuya\javatest のディレクトリ
2021/02/15  12:16    <DIR>          .
2021/02/15  12:16    <DIR>          ..
2021/02/15  12:15               151 Sample.java
2021/02/15  01:54               212 SampleMain.java

Sample.java

public class Sample {
    public Sample(){}//コンストラクタ
    public void print(){
        System.out.println("Sample Loaded");
    }
}

SampleMain.java

public class SampleMain {
    public static void main(String[] args){
        System.out.println("SampleMain Loaded");
        Sample sample = new Sample();
        sample.print();
    }
}

これで準備完了なのでコンパイルしてビルドします。

C:\Users\yuya\javatest>dir
 C:\Users\yuya\javatest のディレクトリ
2021/02/15  12:57    <DIR>          .
2021/02/15  12:57    <DIR>          ..
2021/02/15  12:50               151 Sample.java
2021/02/15  12:52               194 SampleMain.java
C:\Users\yuya\javatest>javac SampleMain.java
C:\Users\yuya\javatest>dir
 C:\Users\yuya\javatest のディレクトリ
2021/02/15  12:57    <DIR>          .
2021/02/15  12:57    <DIR>          ..
2021/02/15  12:57               395 Sample.class
2021/02/15  12:50               151 Sample.java
2021/02/15  12:57               486 SampleMain.class
2021/02/15  12:52               194 SampleMain.java

SampleMain.javaをコンパイルしただけなのに、なぜかSample.classも生成されたのは謎ですが、(恐らくコンパイラがSampleMainの中でSampleクラスがあるのを見てコンパイルしてるのかと思います。)
SampleMain.class、Sample.classが生成されて分割コンパイルが完了したので実行します。

C:\Users\yuya\javatest>java SampleMain
SampleMain Loaded
Sample Loaded

問題なく実行できてますね。
ここで以下二つの実験を行い、クラスパスを理解していきます。  

1. Sample.classファイルを別のフォルダに移動してSampleMain.classを実行する

2. Sample.javaファイルを別のフォルダに移動してSampleMain.javaをコンパイルする  

実験1. Sample.classファイルを別のフォルダに移動してSampleMain.classを実行する

以下のディレクトリ構成にして実行します。

C:\Users\yuya\javatest>tree /f
C:.
│  Sample.java
│  SampleMain.class
│  SampleMain.java
│
└─sub
        Sample.class

この状態でSampleMainを実行します

C:\Users\yuya\javatest>java SampleMain
SampleMain Loaded
Exception in thread "main" java.lang.NoClassDefFoundError: Sample
        at SampleMain.main(SampleMain.java:4)
Caused by: java.lang.ClassNotFoundException: Sample
        at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:583)
        at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
        ... 1 more

classファイルがあるのはカレントディレクトリ(SampleMain.class)とsubディレクトリ(Sample.class)ですが、SampleMainクラスを読み込み中に、Sampleクラスが見つからないエラーとなりました。


よって、全てのclassファイルが見つかる状態でなければSampleMain.classファイルの実行に失敗することがわかりました。


解決するには、Sampleクラスを見つかる状態にしてあげます。
javacコマンドはデフォルトでクラスの読み込み先が実行したディレクトリ(カレントディレクトリ)のみとなるので、


javacコマンドに、classファイルが置いてある場所を全て伝えるように変更します。

伝える方法がクラスパスです。


クラスパスの指定方法はJavacコマンドに-classpathオプション、または-cpオプションで指定を行います。

指定方法は以下の通りです。

C:\Users\yuya\javatest>java -classpath .;./sub SampleMain
SampleMain Loaded
Sample Loaded

カレントディレクトリとサブディレクトリの二つを指定する方法は「.;./sub」とします。「;」これで複数指定が出来ます。


-classpathや-cpを省略する技もあります。それは、クラスパスを環境変数に登録する方法です。環境変数にCLASSPATHを「.;./sub」と登録することでオプションの省略が可能です。

実験2. Sample.javaファイルを別のフォルダに移動してSampleMain.javaをコンパイルする

以下のディレクトリ構成にします。

C:\Users\yuya\javatest>tree /f
C:.
│  SampleMain.java
│
└─sub
        Sample.java

SampleMain.javaをコンパイルします。

C:\Users\yuya\javatest>javac SampleMain.java
SampleMain.java:4: エラー: シンボルを見つけられません
        Sample sample = new Sample();
        ^
  シンボル:   クラス Sample
  場所: クラス SampleMain
SampleMain.java:4: エラー: シンボルを見つけられません
        Sample sample = new Sample();
                            ^
  シンボル:   クラス Sample
  場所: クラス SampleMain
エラー2個

すると実験1と同様にSample.javaが見つからないというエラーでコンパイルに失敗します。


これもクラスパスがカレントディレクトリになっているので失敗しているというわけです。クラスパスはコンパイル時とビルド時で使用します。この場合のクラスパスは、コンパイルするためのファイルのありかがどこにあるかを示すものになります。


なので以下のように実行してあげればいいわけです。

C:\Users\yuya\javatest>tree /f
C:.
│  SampleMain.java
│
└─sub
        Sample.java
C:\Users\yuya\javatest>javac -classpath .;./sub SampleMain.java
C:\Users\yuya\javatest>tree /f
C:.
│  SampleMain.class
│  SampleMain.java
│
└─sub
        Sample.class
        Sample.java

このようにコンパイルが可能となるわけです。その後の実行は実験1で行ったように実行が可能です。

C:\Users\yuya\javatest>java -classpath .;./sub SampleMain
SampleMain Loaded
Sample Loaded

ここまででクラスパスについてが理解できたはずです。クラスパスを指定することで、コンパイルを行ったりコンパイルしたclassファイルを実行してきました。次の章ではパッケージを絡めたクラスパスの関係を理解していきます。

パッケージ化とビルド

パッケージ化したファイルを読み込むことで、クラスパスの指定方法が少し変わってくることを理解していきます。ちなみにパッケージとは自分のファイルがどこにあるかを指定する方法です。

C:\Users\yuya\javatest>tree /f
C:.
│  SampleMain.java
│
└─sub
        Sample.java

SampleMain.java

public class SampleMain {
    public static void main(String[] args){
        System.out.println("SampleMain Loaded");
        sub.Sample sample = new sub.Sample();//ここを変更
        sample.print();
    }
}

今までならコンパイル時、subフォルダをclasspathに指定して、コンパイラに場所を教えてあげる必要があったが、パッケージを使っているため、それで場所を教えてあげることが出来るようになる。ちなみに、パッケージのディレクトリ指定はルートディレクトリからの指定方法となる。なので、以下の通りコンパイルして実行することが可能となる。

C:\Users\yuya\javatest>tree /f
フォルダー パスの一覧:  ボリューム Windows-SSD
ボリューム シリアル番号は 528E-0B8D です
C:.
│  SampleMain.java
│
└─sub
        Sample.java
C:\Users\yuya\javatest>javac SampleMain.java
C:\Users\yuya\javatest>tree /f
フォルダー パスの一覧:  ボリューム Windows-SSD
ボリューム シリアル番号は 528E-0B8D です
C:.
│  SampleMain.class
│  SampleMain.java
│
└─sub
        Sample.class
        Sample.java
C:\Users\yuya\javatest>java SampleMain
SampleMain Loaded
Sample Loaded

なのでSample.classを以下のように移動して実行はできない

C:\Users\yuya\javatest>tree /f
C:.
│  SampleMain.class
│  SampleMain.java
│
├─classes
│  └─sub
│          Sample.class
│
└─sub
        Sample.java
C:\Users\yuya\javatest>java SampleMain
SampleMain Loaded
Exception in thread "main" java.lang.NoClassDefFoundError: sub/Sample
        at SampleMain.main(SampleMain.java:4)
Caused by: java.lang.ClassNotFoundException: sub.Sample
        at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:583)
        at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
        ... 1 more

Sample.classが見つからなくなって実行できなくなります。ですがこの場合はclasspathオプションの指定方法を以下のように指定することで実行が可能となります。

C:\Users\yuya\javatest>java -classpath .;./classes SampleMain
SampleMain Loaded
Sample Loaded

パッケージをクラスパスに指定する場合は、subディレクトリが置いてあるルートディレクトリを指定するということです。

ちなみに、パッケージがdir.sub;だった場合は、dirが置いてある場所をclassパスとしてあげればいいということです。


以上。

-Java, プログラミング

執筆者:


comment

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

関連記事

「WordPress」にTwitterのツイートを表示したい

ExcelVBAのメソッドにログを簡単に追加する方法

ExcelVBAのメソッドにログを簡単に追加する方法 ExcelVBAでログにより、解析を行いたいときがあるが、既存のExcelファイルではログが付与されていないことが多い。また、ExcelVBAでは …

ExcelVBAでソースコード一括出力 & クラス一括開放

ExcelVBAでソースコードを一括出力するには、VBAから実行することでソースコードを出力することが可能。 VBAソースコード一括出力() ExcelVBAではクラスを一括で開放することがUI上から …

アーカイブ

カテゴリー

プロフィール

34歳男性、一児の父親兼、iOSアプリ・Webサーバーアプリのプログラマーをしております。何事にも真剣に慎重に石橋をたたいて渡ろうとするのですが、時折たたくのを忘れてわたるというよく言えば勢いの良い、悪く言えば詰めが甘く娘にも甘いタイプの人です。
プロフィール詳細