読者です 読者をやめる 読者になる 読者になる

忘備録

日々の調べ物をまとめる。アウトプットする。基本自分用。

javaのクラスパスとかパッケージについて

オラクル認定資格教科書 Javaプログラマ Gold SE 7 スピードマスター問題集 (EXAMPRESS)

資格取ろうと勉強中なのですが、クラスパスについて理解していなかった
という衝撃の事実に気づかされました。

恥ずかしい。。。

環境

OS

OS X 10.10.5

実行環境

$ java -version
java version "1.8.0_60"
Java(TM) SE Runtime Environment (build 1.8.0_60-b27)
Java HotSpot(TM) 64-Bit Server VM (build 25.60-b23, mixed mode)

コンパイラ

$ javac -version
javac 1.8.0_60

要点

  1. パッケージと同じ構造を持ったディレクトリにクラスファイルを配置する
  2. クラスパスに指定するパスはパッケージのルート
  3. パッケージに属しているクラスを実行するときはパッケージを含めて指定する

/root1/pack1/Test1.java

package pack1;

import pack2.Test2;

public class Test1 {
    public static void main(String[] args) {
        Test2 t2 = new Test2();
        t2. printHoge();
    }
}

/root2/pack2/Test2.java

package pack2;

public class Test2 {
    public void printHoge() {
        System.out.println("hoge");
    }
}

コンパイル

#カレントディレクトリはpack1
$ pwd
/root1/pack1
#-classpathオプションでクラスパスを指定
#例ではTest1.javaとTest2.javaのパッケージのルートディレクトリを指定している
#クラスパスを複数指定する場合は「:(コロン)」で区切る
$ javac -classpath /root2/:.. Test1.java
#確認
$ ls
Test1.class Test1.java
$ ls /root2/pack2
Test2.class Test2.java
#ソースはTest1.javaを指定しているが、Test1の中でTest2を呼んでいるため、
#Test2のクラスパスの指定が必要。Test1のコンパイルと同時にTest2.javaもコンパイルされる

実行

#パッケージ指定されているクラスを実行する場合はパッケージ名を修飾する必要がある
$ java -classpath /root2/:.. pack1.Test1
hoge

おまけ

ちなみに、パッケージのルートディレクトリがカレントディレクトリの場合、クラスパスの指定は必要ない。
これはクラスパスのデフォルトがカレントディレクトリだからである。

例えば、先ほどのソースファイルが以下のような配置である場合
/root/pack1/Test1.java
/root/pack2/Test2.java

#カレントディレクトリ確認
$ pwd
/root
#コンパイル
$ javac pack1/Test1.java
#実行
$ java pack1.Test1
hoge

のように、クラスパスを明示的に指定をせずコンパイル・実行ができる

参考

http://homepage1.nifty.com/algafield/pkg-cp.html

Javaアプリケーション メモ(Hishidama's Java-Application Memo)