できない.dev

Java で「Could not find or load main class」が解決できない

java コマンドに渡すのはファイル名ではなく完全修飾クラス名で、.class が置かれたルートディレクトリを -cp で指す必要がある。
拡張子付きの指定とパッケージ名の省略が二大原因である。

公開:

要約

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 の記事を参照する。

よくある原因

  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 を付けずに実行しているケースが多い。

解決策

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 で同じエラーになる。

この記事は役立ちましたか?