普段、javaで開発するときはeclipseを使い、ビルドも実行もeclipseに任せています。だけど、先日コマンドラインからコンパイル&実行をしなければならない環境に追い込まれ苦戦し、これはやばい、やばすぎると感じたので、少し色々と試して纏めてみることにしました。

■パターン1
・Sam3.java,Sam3_1,javaの二つのjavaファイルにぞれぞれクラスが一つずつ。
・Sam3.javaはC:\java\package\test\package3\下にあります。
(環境はwindows、ソース文字コードはUTF8)

package test.package3;

import test.package3_3.Sam3_1;

public class Sam3 {
public static void main(String[] args) {
// TODO 自動生成されたメソッド・スタブ
System.out.println("めいん3 start");
Sam3_1 sam3_1 = new Sam3_1();
sam3_1.showMessage1();
System.out.println("めいん3 end");
}
}

package test.package3_3;
public class Sam3_1 {
public void showMessage1(){
System.out.println("さぶ3_1 start");
System.out.println("さぶ3_1 end");
}
}

☆カレントディレクトリをC:\java\package\test\package3にして、コンパイル実行。

C:\java\package\test\package3>javac -encoding UTF8 Sam3.java
Sam3.java:3: エラー: パッケージtest.package3_3は存在しません
import test.package3_3.Sam3_1;
^
Sam3.java:14: エラー: シンボルを見つけられません
Sam3_1 sam3_1 = new Sam3_1();
^
シンボル: クラス Sam3_1
場所: クラス Sam3
Sam3.java:14: エラー: シンボルを見つけられません
Sam3_1 sam3_1 = new Sam3_1();
^
シンボル: クラス Sam3_1
場所: クラス Sam3
エラー3個

結果:コンパイルエラー


☆カレントディレクトリをC:\java\package\にして、コンパイル実行。

C:\java\package\test\package3>cd ../..

C:\java\package>javac -encoding UTF8 test\package3\Sam3.java

C:\java\package>dir test\package3
ドライブ C のボリューム ラベルがありません。
ボリューム シリアル番号は 8AB7-451F です

C:\java\package\test\package3 のディレクトリ

2013/03/03 14:27 <DIR> .
2013/03/03 14:27 <DIR> ..
2013/03/03 14:27 542 Sam3.class
2013/03/02 20:24 368 Sam3.java
2 個のファイル 910 バイト
2 個のディレクトリ 70,922,231,808 バイトの空き領域

C:\java\package>dir test\package3_3
ドライブ C のボリューム ラベルがありません。
ボリューム シリアル番号は 8AB7-451F です

C:\java\package\test\package3_3 のディレクトリ

2013/03/03 14:27 <DIR> .
2013/03/03 14:27 <DIR> ..
2013/03/03 14:27 451 Sam3_1.class
2013/03/02 20:24 170 Sam3_1.java
2 個のファイル 621 バイト
2 個のディレクトリ 70,922,231,808 バイトの空き領域

結果:コンパイル成功。Sam3.class,Sam3_1.classが生成される。

☆C:\java\package>javaで、Sam3のみ指定して実行。

C:\java\package>java Sam3
エラー: メイン・クラスSam3が見つからなかったかロードできませんでした

結果:エラー

☆C:\java\package\test\package3>で、Sam3のみ指定して実行。

C:\java\package>cd test\package3

C:\java\package\test\package3>java Sam3
Exception in thread "main" java.lang.NoClassDefFoundError: Sam3 (wrong name: test/package3/Sam3)
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(Unknown Source)
at java.security.SecureClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.access$100(Unknown Source)
at java.net.URLClassLoader$1.run(Unknown Source)
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.launcher.LauncherHelper.checkAndLoadMain(Unknown Source)

結果:エラー

☆C:\java\package>で、パッケージも考慮し 「test.package3.Sam3」を指定して実行。

C:\java\package\test\package3>cd ../..

C:\java\package>java test.package3.Sam3
めいん3 start
さぶ3_1 start
さぶ3_1 end
めいん3 end

結果:実行成功。


■パターン2
・Sam4.java,Sam3_1,javaの二つのjavaファイルにぞれぞれクラスが一つずつ。
・Sam4.javaはC:\java\package\test\package4\下にあります。
・Sam4.javaはlog4jを使っている(log4j.jarはC:\java\log4j\apache-log4j-1.2.17\log4j-1.2.17.jarにある)

package test.package4;

import org.apache.log4j.Logger;
import org.apache.log4j.xml.DOMConfigurator;
import test.package3_3.Sam3_1;

public class Sam4 {
static Logger logger = Logger.getLogger(Sam4.class);

public static void main(String[] args) {
System.out.println("めいん4 start");
DOMConfigurator.configure("log4j.xml");

logger.debug("Hello world.!!!!!");

Sam3_1 sam3_1 = new Sam3_1();
sam3_1.showMessage1();

System.out.println("めいん4 end");
}
}

☆カレントディレクトリC:\java\packageからSam4をパッケージ指定してコンパイル。

C:\java\package>javac -encoding UTF8 test\package4\Sam4.java
test\package4\Sam4.java:3: エラー: パッケージorg.apache.log4jは存在しません
import org.apache.log4j.Logger;
^
test\package4\Sam4.java:4: エラー: パッケージorg.apache.log4j.xmlは存在しません
import org.apache.log4j.xml.DOMConfigurator;
^
test\package4\Sam4.java:9: エラー: シンボルを見つけられません
static Logger logger = Logger.getLogger(Sam4.class);
^
シンボル: クラス Logger
場所: クラス Sam4
test\package4\Sam4.java:9: エラー: シンボルを見つけられません
static Logger logger = Logger.getLogger(Sam4.class);
^
シンボル: 変数 Logger
場所: クラス Sam4
test\package4\Sam4.java:18: エラー: シンボルを見つけられません
DOMConfigurator.configure("log4j.xml");
^
シンボル: 変数 DOMConfigurator
場所: クラス Sam4
エラー5個

結果:コンパイルエラー。log4j関連のクラスが見つけられないみたい。そりゃそうだ、パスを通してないからね。

☆コンパイル時にlog4j.jarのクラスパスを指定。

C:\java\package>javac -encoding UTF8 -classpath C:\java\log4j\apache-log4j-1.2.17\log4j-1.2.17.jar test\package4\Sam4.j
ava
test\package4\Sam4.java:6: エラー: パッケージtest.package3_3は存在しません
import test.package3_3.Sam3_1;
^
test\package4\Sam4.java:23: エラー: シンボルを見つけられません
Sam3_1 sam3_1 = new Sam3_1();
^
シンボル: クラス Sam3_1
場所: クラス Sam4
test\package4\Sam4.java:23: エラー: シンボルを見つけられません
Sam3_1 sam3_1 = new Sam3_1();
^
シンボル: クラス Sam3_1
場所: クラス Sam4
エラー3個

結果:log4jのエラーは消えたけど、今度はtest\package3_3\Sam3_1.javaが認識されずにエラーが出てる。おそらく、classpathにlog4.jarのパスだけを指定したから、今まで暗黙で認識されてたカレントディレクトリが認識されなくなってるんだな。

☆ということで、カレントディレクトリも一緒に指定してコンパイル。

C:\java\package>javac -encoding UTF8 -classpath .;C:\java\log4j\apache-log4j-1.2.17\log4j-1.2.17.jar test\package4\Sam4
.java

結果:成功

☆カレントディレクトリC:\java\packageから、test.package4.Sam4を指定して実行。

C:\java\package>java test.package4.Sam4
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/log4j/Logger
at test.package4.Sam4.<clinit>(Sam4.java:9)
Caused by: java.lang.ClassNotFoundException: org.apache.log4j.Logger
at java.net.URLClassLoader$1.run(Unknown Source)
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
... 1 more

結果:エラー。う、実行時もクラスパスを指定しないといけないのか・・・

☆log4jをクラスパスして実行。

C:\java\package>java -classpath C:\java\log4j\apache-log4j-1.2.17\log4j-1.2.17.jar test.package4.Sam4
エラー: メイン・クラスtest.package4.Sam4が見つからなかったかロードできませんでした

結果:エラー。はいはい、CD、CD。

C:\java\package>java -classpath .;C:\java\log4j\apache-log4j-1.2.17\log4j-1.2.17.jar test.package4.Sam4
めいん4 start
test.package4.Sam4 ppp 2013/55/03 DEBUG:0:test.package4.Sam4:Hello world.!!!!!
ppp 0 [main] /// 2013-03-03 14:55:15,565 DEBUG Sam4 - Hello world.!!!!!
さぶ3_1 start
さぶ3_1 end
めいん4 end

結果:ようやく成功。

☆コンパイル時、実行時に毎回クラスパスを指定するのは面倒なので、環境変数を扱うsetコマンドを使って、クラスパスを指定する。

C:\java\package>set CLASSPATH=.;C:\java\log4j\apache-log4j-1.2.17\log4j-1.2.17.jar

C:\java\package>set

CLASSPATH=.;C:\java\log4j\apache-log4j-1.2.17\log4j-1.2.17.jar


結果:カレントディレクトリとlog4,jarがクラスパスに追加された。

☆コンパイル&実行

C:\java\package>javac -encoding UTF8 test\package4\Sam4.java

C:\java\package>java test.package4.Sam4
めいん4 start
test.package4.Sam4 ppp 2013/01/03 DEBUG:0:test.package4.Sam4:Hello world.!!!!!
ppp 0 [main] /// 2013-03-03 15:01:48,518 DEBUG Sam4 - Hello world.!!!!!
さぶ3_1 start
さぶ3_1 end
めいん4 end

結果:かろやかに成功。

以上。

参考
基本事項クラスパス
apachePOI導入からCLASSPATHを指定して実行まで

ちなみに、springなどを使って、newせずDIしている場合、main()を含むクラスをコンパイルしても、すべてのソースがコンパイルされないので注意。なるほど、ここにきてantなどのビルドツールの必要性が強く感じられる。