できない.dev

Java「Could not find or load main class」の原因と直し方

Could not find or load main class は、完全修飾クラス名で実行し、-cp で .class のルートを指せば直る。
拡張子付きの指定とパッケージ名の省略が二大原因だ。

公開: 更新:

症状できない · exit 1
java out/com/example/App.class
Error: Could not find or load main class out.com.example.App.class
Caused by: java.lang.ClassNotFoundException: out.com.example.App.class
解決後できた · exit 0
java -cp out com.example.App
App started

2026-10-14 に eclipse-temurin:21-jdk(Java 21.0.12.1) で実際に打って取った出力。検証環境の詳細

要約

Error: Could not find or load main class ... は、JVM が指定された名前のクラスをクラスパス上で見つけられなかったときに出る。
設定が壊れているわけではなく、ほとんどは「渡した名前」か「クラスパスのルート」のどちらかが間違っている。

$ java Main
Error: Could not find or load main class Main
Caused by: java.lang.ClassNotFoundException: Main

続く Caused by: が java.lang.ClassNotFoundException なら探索経路の問題である。UnsupportedClassVersionError などの LinkageError が続く場合は別問題なので、class file version の記事を参照する。

実行例

eclipse-temurin:21-jdk で上記の手順を動かすと、.class のパスをそのまま渡した場合は、区切りの / が . に置き換わった out.com.example.App.class というクラスを探しに行った。
これもパッケージ名の省略やクラスパスのルート違いと同じく、ClassNotFoundException で終了コード 1 になった。-cp out と完全修飾名 com.example.App を組み合わせたときだけ、App started が出力された。

$ java out/com/example/App.class
Error: Could not find or load main class out.com.example.App.class
Caused by: java.lang.ClassNotFoundException: out.com.example.App.class
$ echo $?
1
$ java -cp out App
Error: Could not find or load main class App
Caused by: java.lang.ClassNotFoundException: App
$ echo $?
1
$ java -cp out/com/example com.example.App
Error: Could not find or load main class com.example.App
Caused by: java.lang.ClassNotFoundException: com.example.App
$ echo $?
1
$ find out -name "*.class"
out/com/example/App.class
$ java -cp out com.example.App
App started
$ echo $?
0

— 2026-10-14 時点の出力

検証環境Java 21.0.12.1 / 2026-10-14 検証
検証日
実行環境
eclipse-temurin:21-jdk Ubuntu 26.04.1 LTS
バージョン
  • Java 21.0.12.1

この記事の「実行例」は、上記の環境で実際にコマンドを実行して得られた出力をそのまま掲載しています。 再現手順はリポジトリの検証スクリプトとして管理し、定期的に再実行して出力を更新しています。

解決策

1. 完全修飾クラス名で実行する

java com.example.App        # ○ 拡張子なし・パッケージ込み
java App                    # × パッケージ宣言があると失敗する
java com/example/App.class  # × 拡張子付きは失敗する

2. クラスパスのルートを -cp で指す

javac -d out src/com/example/App.java
java -cp out com.example.App

-cp を省略するとカレントディレクトリだけが探索対象になる。
ルート以外の場所から起動するなら明示が必要である。
詳細は java コマンドの公式ドキュメント(新しいタブで開く)にある --class-path の説明を参照する。

3. クラスファイルの実在を確認する

find . -name '*.class'
# ./out/com/example/App.class → ルートは ./out

出力されたパスからパッケージ階層をそのまま取り除いた部分がクラスパスのルートになる。

4. jar なら Main-Class を確認する

unzip -p app.jar META-INF/MANIFEST.MF

Main-Class: com.example.App の行が無い、または綴りが違うと java -jar で同じエラーになる。

よくある原因

  1. 拡張子まで渡している。java Hello.class と打つと、JVM は Hello.class という名前のクラスを探すため必ず失敗する。.java を渡した場合はソースファイルモードとして別扱いになるので、症状が出るのは .class の方である。
  2. パッケージ名を省いている。package com.example; を持つクラスは、ディレクトリを移動しても短い名前では起動できない。
    JVM が受け取るのは常に完全修飾名である。
  3. クラスパスのルートがずれている。com/example/App.class に対するルートは com の親ディレクトリであって、com/example ではない。
  4. 出力先と実行時の指定が食い違っている。javac -d out で出したのに、-cp を付けずに実行しているケースが多い。