Dev Study
← 解説「クラスパスと JAR」に戻る

サンプルコードで身につける: クラスパスと JAR

解説で学んだ概念を、5つの具体例で確認します。素朴な例から実務寄りの例へと進みます。

1JAR の中身を一覧する

コマンドで作った app.jar を、jar と の両方で開いたものです。入っているのは と だけで、unzip でそのまま読めます。は jar コマンドが自動で作り、入口の名が の行に書かれています。

$ jar tf / unzip -l / unzip -p(JDK 25 で作った app.jar)コマンド出力
$ jar tf dist/app.jar
META-INF/
META-INF/MANIFEST.MF
app/
app/Main.class
app/Util.class
$ unzip -l dist/app.jar
Length Date Time Name
--------- ---------- ----- ----
0 2026-10-01 13:20 META-INF/
88 2026-10-01 13:20 META-INF/MANIFEST.MF
0 2026-10-01 13:20 app/
532 2026-10-01 13:20 app/Main.class
347 2026-10-01 13:20 app/Util.class
--------- -------
967 5 files
$ unzip -p dist/app.jar META-INF/MANIFEST.MF
Manifest-Version: 1.0
Created-By: 25.0.4.1 (Eclipse Adoptium)
Main-Class: app.Main

2クラスパスに無い名前を頼むとどうなるか

クラスの名前を文字列で渡して読み込みを頼む を使った例です。にある Main は見つかり、どこにも無い greet.Greeter は になります。このページの実行環境では、クラスパスは . (カレントディレクトリ)だけです。

Java

3依存の JAR が足りないまま起動する

app.Main は別の に入っている greet.Greeter を使います。その JAR を渡さずに起動すると、Main started までは進み、Greeter を初めて使う8行目で になりました。 dist/greet.jar dist/app.jar のように -cp を足しても、同じエラーのままでした。

$ java -jar dist/app.jar(JDK 25、greet.jar を渡していない)コマンド出力
Main started
Exception in thread "main" java.lang.NoClassDefFoundError: greet/Greeter
at app.Main.main(Main.java:8)
Caused by: java.lang.ClassNotFoundException: greet.Greeter
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:580)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:490)
... 1 more
package app;

import greet.Greeter;

public class Main {
    public static void main(String[] args) {
        System.out.println("Main started");
        System.out.println(new Greeter().greet("jar"));   // 8行目
    }
}

4依存を渡して動かす3通り

同じアプリが動いた起動方法です。-cp に2つの JAR を並べて入口のクラスを名前で指定する方法、dist/* でディレクトリ内の JAR をまとめて指す方法、マニフェストに を書いて java -jar だけで起動する方法の3つです。3つ目は greet.jar が同じディレクトリにファイルとして在ることが条件でした。

動いた3通り(JDK 25)コマンド出力
$ java -cp dist/app.jar:dist/greet.jar app.Main
Main started
Hello, jar
$ java -cp 'dist/*' app.Main
Main started
Hello, jar
$ unzip -p dist/app-cp.jar META-INF/MANIFEST.MF
Manifest-Version: 1.0
Class-Path: greet.jar
Created-By: 25.0.4.1 (Eclipse Adoptium)
Main-Class: app.Main
$ java -jar dist/app-cp.jar
Main started
Hello, jar

5JAR の中に JAR を入れると読まれない

依存の greet.jar を app-nested.jar の中の に入れて起動すると、依存が無いときと同じエラーになりました。後半は入れ子の場所を指す URL を 標準の に渡した結果で、中の JAR をバイト列として読むことはできても、クラスは見つかりません。外に書き出したコピーを渡すと読み込めました。

入れ子の JAR を試す(JDK 25)コマンド出力
$ jar tf dist/app-nested.jar
META-INF/
META-INF/MANIFEST.MF
app/
app/Main.class
app/Util.class
lib/
lib/greet.jar
$ java -jar dist/alone/app-nested.jar
Main started
Exception in thread "main" java.lang.NoClassDefFoundError: greet/Greeter
at app.Main.main(Main.java:8)
Caused by: java.lang.ClassNotFoundException: greet.Greeter
...
$ java -cp build Nested
nested entry readable as bytes: 931
file:/w/dist/alone/app-nested.jar -> java.lang.ClassNotFoundException: greet.Greeter
jar:file:/w/dist/alone/app-nested.jar!/lib/greet.jar -> java.lang.ClassNotFoundException: greet.Greeter
jar:file:/w/dist/alone/app-nested.jar!/lib/greet.jar!/ -> java.lang.ClassNotFoundException: greet.Greeter
extracted copy -> class greet.Greeter

図やコードに出てくる用語(タップで説明)