新しい Java 開発者が経験する一般的な問題は、プログラムの実行に失敗して次のエラー メッセージが表示されることです。 Could not find or load main class ...
これは何を意味し、何が原因で、どのように修正する必要がありますか?
java <class-name>
コマンド構文まず、java
(またはjavaw
) コマンドを使用してプログラムを起動する正しい方法を理解する必要があります。
通常の構文1は次のとおりです。
java [ <options> ] <class-name> [<arg> ...]
ここ<option>
で、 はコマンド ライン オプション (「-」文字で始まる) で<class-name>
あり、完全修飾 Java クラス名であり<arg>
、アプリケーションに渡される任意のコマンド ライン引数です。
1 - この回答の終わり近くで説明されている他の構文がいくつかあります。
クラスの完全修飾名 (FQN) は、Java ソース コードの場合と同様に慣例的に記述されます。例えば
packagename.packagename2.packagename3.ClassName
ただし、java
コマンドの一部のバージョンでは、ピリオドの代わりにスラッシュを使用できます。例えば
packagename/packagename2/packagename3/ClassName
これは (紛らわしいことに) ファイルのパス名のように見えますが、そうではありません。完全修飾名という用語は、標準的な Java 用語であることに注意してください...混乱させるために私が作ったものではありません :-)
コマンドの例を次に示しjava
ます。
java -Xmx100m com.acme.example.ListUsers fred joe bert
上記により、java
コマンドは次のことを実行します。
com.acme.example.ListUsers
クラスのコンパイル済みバージョンを検索します。main
を持つメソッドがクラスにあることを確認してください。(メソッド引数の名前は署名の一部ではないことに注意してください。)public static void main(String[])
String[]
.「Could not find or load main class ...」というメッセージが表示された場合は、最初のステップが失敗したことを意味します。java
コマンドはクラスを見つけることができませんでした。実際、メッセージ内の「...」は、探している完全修飾クラス名になります。java
では、なぜクラスを見つけることができないのでしょうか?
最初に考えられる原因は、間違ったクラス名を指定した可能性があることです。(または ... 正しいクラス名ですが、形式が間違っています。) 上記の例を考慮して、クラス名を指定するさまざまな間違った方法を次に示します。
例 #1 - 簡単なクラス名:
java ListUser
クラスが などのパッケージで宣言されている場合は、コマンドでパッケージ名を含むcom.acme.example
完全なクラス名を使用する必要があります。例えばjava
java com.acme.example.ListUser
例 #2 - クラス名ではなくファイル名またはパス名:
java ListUser.class
java com/acme/example/ListUser.class
例 #3 - 大文字と小文字が正しくないクラス名:
java com.acme.example.listuser
例 #4 - タイプミス
java com.acme.example.mistuser
例 #5 - ソース ファイル名 (Java 11 以降を除く。以下を参照)
java ListUser.java
例 #6 - クラス名を完全に忘れた
java lots of arguments
2 番目に考えられる原因は、クラス名は正しいが、java
コマンドがクラスを見つけられないことです。これを理解するには、「クラスパス」の概念を理解する必要があります。これは、Oracleのドキュメントでよく説明されています。
java
ドキュメントそのため...クラス名を正しく指定した場合、次に確認することは、クラスパスを正しく指定したことです。
java
。ディレクトリ名とJARファイル名が正しいことを確認してください。java
。;
Windows と:
その他のものにあります。プラットフォームに間違ったセパレーターを使用しても、明示的なエラーメッセージは表示されません。代わりに、パス上に存在しないファイルまたはディレクトリが表示され、黙って無視されます。 .)クラスパスにディレクトリを配置すると、概念的には修飾された名前空間のルートに対応します。クラスは、完全修飾名をパス名にマッピングすることにより、そのルートの下のディレクトリ構造に配置されます。たとえば、「/usr/local/acme/classes」がクラス パス上にある場合、JVM が というクラスを探すとき、次のcom.acme.example.Foon
パス名を持つ「.class」ファイルを探します。
/usr/local/acme/classes/com/acme/example/Foon.class
クラスパスに「/usr/local/acme/classes/com/acme/example」を配置した場合、JVM はクラスを見つけることができません。
クラスの FQN がcom.acme.example.Foon
の場合、JVM はディレクトリ「com/acme/example」で「Foon.class」を探します。
上記のパターンに従ってディレクトリ構造がパッケージの命名と一致しない場合、JVM はクラスを見つけられません。
クラスを移動して名前を変更しようとすると、それも失敗します...ただし、例外スタックトレースは異なります。次のようなことを言いがちです。
Caused by: java.lang.NoClassDefFoundError: <path> (wrong name: <name>)
クラス ファイル内の FQN が、クラス ローダーが期待しているものと一致しないためです。
具体例を挙げると、次のようになります。
com.acme.example.Foon
クラスを実行したい、/usr/local/acme/classes/com/acme/example/Foon.class
、/usr/local/acme/classes/com/acme/example/
、それから:
# wrong, FQN is needed
java Foon
# wrong, there is no `com/acme/example` folder in the current working directory
java com.acme.example.Foon
# wrong, similar to above
java -classpath . com.acme.example.Foon
# fine; relative classpath set
java -classpath ../../.. com.acme.example.Foon
# fine; absolute classpath set
java -classpath /usr/local/acme/classes com.acme.example.Foon
ノート:
-classpath
短縮できます。などについては、-cp
それぞれのマニュアル エントリを確認してください。java
javac
クラスパスには、アプリケーションが依存する他の(システム以外の) クラスをすべて含める必要があります。(システム クラスは自動的に配置されるため、これについて気にする必要はほとんどありません。) メイン クラスを正しくロードするには、JVM が以下を見つける必要があります。
(注: JLS および JVM の仕様では、JVM がクラスを「遅延」してロードする範囲が許可されており、これはクラスローダー例外がスローされたときに影響を与える可能性があります。)
package
ソース コード ツリー内の間違ったフォルダーにソース コード ファイルを配置したり、宣言を省略したりすることがあります。IDE でこれを行うと、IDE のコンパイラがこれについてすぐに通知します。同様に、適切な Java ビルド ツールを使用すると、ツールはjavac
問題を検出する方法で実行されます。ただし、Java コードを手動でビルドすると、コンパイラが問題に気付かず、結果の ".class" ファイルが期待どおりの場所にないような方法でビルドできます。
確認する項目が多く、見落としがちです。-Xdiag
オプションをjava
コマンド ラインに追加してみてください( の後の最初のものとしてjava
)。クラスのロードに関するさまざまな情報が出力されます。これにより、実際の問題が何であるかについての手がかりが得られる場合があります。
また、Web サイトやドキュメントなどから非表示または非 ASCII 文字をコピーして貼り付けることによって発生する可能性のある問題についても考慮してください。そして、2 つの文字または記号が同じように見えますが、そうではない「ホモグリフ」を考えてみましょう。
の署名が無効または正しくない場合、この問題が発生する可能性がありますMETA-INF/*.SF
。お気に入りの ZIP エディターで .jar を開き、.jar ファイルがMETA-INF
なくなるまでファイルを削除してみてくださいMANIFEST.MF
。ただし、これは一般的に推奨されません。(無効な署名は、元の署名付き JAR ファイルに誰かがマルウェアを挿入した結果である可能性があります。無効な署名を消去すると、アプリケーションがマルウェアに感染することになります!)署名を作成するか、(本物の) 元のソース コードから再構築します。
MANIFEST.MF
最後に、ファイルに構文エラーがあると、この問題が発生する可能性があります ( https://stackoverflow.com/a/67145190/139985を参照)。
java
を使用して Java プログラムを起動するための代替構文が 3 つありますjava command
。
「実行可能」JAR ファイルの起動に使用される構文は次のとおりです。
java [ <options> ] -jar <jar-file-name> [<arg> ...]
例えば
java -Xmx100m -jar /usr/local/acme-example/listuser.jar fred
エントリポイント クラスの名前 (つまりcom.acme.example.ListUser
) とクラスパスは、JAR ファイルの MANIFEST で指定されます。
モジュール (Java 9 以降) からアプリケーションを起動するための構文は次のとおりです。
java [ <options> ] --module <module>[/<mainclass>] [<arg> ...]
エントリポイント クラスの名前は、<module>
それ自体によって定義されるか、オプションの によって指定されます<mainclass>
。
Java 11 以降では、java
コマンドを使用して、次の構文を使用して単一のソース コード ファイルをコンパイルおよび実行できます。
java [ <options> ] <sourcefile> [<arg> ...]
<sourcefile>
(通常) は、接尾辞「.java」が付いたファイルです。
詳細については、java
使用している Java リリースのコマンドの公式ドキュメントを参照してください。
標準的な Java IDE は、IDE JVM 自体または子 JVM での Java アプリケーションの実行をサポートしています。IDE は独自のメカニズムを使用してランタイム クラスパスを構築し、メイン クラスを識別し、コマンド ラインを作成するため、これらは通常、この特定の例外の影響を受けません。java
ただし、IDE の背後で何かを行うと、この例外が発生する可能性があります。たとえば、以前に Eclipse で Java アプリ用の Application Launcher をセットアップしており、「メイン」クラスを含む JAR ファイルをEclipse に通知せずにファイル システム内の別の場所に移動した場合、Eclipse は無意識のうちに JVM を起動します。クラスパスが正しくありません。
つまり、IDE でこの問題が発生した場合は、古い IDE 状態、壊れたプロジェクト参照、壊れたランチャー構成などを確認してください。
IDE が単純に混乱する可能性もあります。IDE は、相互に作用する多くのパーツからなる非常に複雑なソフトウェアです。これらのパーツの多くは、IDE を全体として応答性の高いものにするために、さまざまなキャッシュ戦略を採用しています。これらは時々うまくいかないことがあり、考えられる症状の 1 つは、アプリケーションの起動時の問題です。これが起こっている可能性があると思われる場合は、IDE の再起動、プロジェクトの再構築など、他のことを試す価値があります。
ソース コード名が HelloWorld.java の場合、コンパイルされたコードはHelloWorld.class
.
次を使用して呼び出すと、そのエラーが発生します。
java HelloWorld.class
代わりに、これを使用します。
java HelloWorld
クラスがパッケージに含まれている場合cd
は、プロジェクトのルート ディレクトリに移動し、クラスの完全修飾名 (packageName.MainClassName) を使用して実行する必要があります。
例:
私のクラスはここにあります:
D:\project\com\cse\
私のメインクラスの完全修飾名は次のとおりです。
com.cse.Main
そこでcd
、ルート プロジェクト ディレクトリに戻ります。
D:\project
次に、次のjava
コマンドを発行します。
java com.cse.Main
この回答は、初心者の Java プログラマーをよくある間違いによって引き起こされるフラストレーションから救うためのものです。Javaクラスパスに関するより深い知識については、受け入れられた回答を読むことをお勧めします。
コマンドラインでクラスパスを指定すると役に立ちました。例えば:
新しいフォルダを作成し、C:\temp
C:\temp
次のクラスを含むファイル Temp.java を に作成します。
public class Temp {
public static void main(String args[]) {
System.out.println(args[0]);
}
}
folderC:\temp
でコマンド ラインを開き、次のコマンドを記述して Temp クラスをコンパイルします。
javac Temp.java
コンパイルされた Java クラスを実行し、-classpath
JRE にクラスの場所を知らせるオプションを追加します。
java -classpath C:\temp Temp Hello!
-Xdiagを試してください。
Steve C の回答は考えられるケースを適切にカバーしていますが、クラスが見つからないかロードされていないかどうかを判断するのはそれほど簡単ではない場合があります。使用しますjava -Xdiag
(JDK 7 以降)。これは、メッセージ メッセージが何を意味するかについてのヒントを提供する素敵なスタック トレースを出力しますCould not find or load main class
。
たとえば、メイン クラスで使用されている他のクラスが見つからず、メイン クラスのロードを妨げていることを示すことができます。
この場合、次のようなエラーが発生しました。
java -cp lib.jar com.mypackage.Main
;
Windows および:
Unix で動作します。
java -cp lib.jar; com.mypackage.Main
問題の原因がメインクラスとは関係ない場合があり、これを見つけるのは難しい方法でした。私が移動したのは参照ライブラリであり、次のことがわかりました。
メイン クラス xxx Linux が見つからないか、読み込めませんでした
その参照を削除して再度追加したところ、再び正常に機能しました。
私は同じ問題を抱えていて、最終的に間違いを見つけました:)コンパイルにこのコマンドを使用したところ、正しく機能しました:
javac -cp "/home/omidmohebbi/AAAATest/jars/core-1.7.jar:/home/omidmohebbi/AAAATest/jars/javase-1.7.jar:/home/omidmohebbi/AAAATest/jars/qrgen-1.2.jar" qrcode.java
しかし、このコマンドはうまくいきませんでした (メイン クラスを見つけたりロードしたりできませんでしたqrcode
):
java -cp "/home/omidmohebbi/AAAATest/jars/core-1.7.jar:/home/omidmohebbi/AAAATest/jars/javase-1.7.jar:/home/omidmohebbi/AAAATest/jars/qrgen-1.2.jar" qrcode
最後に、クラスパスの最後に「:」文字を追加したところ、問題は解決しました。
java -cp "/home/omidmohebbi/AAAATest/jars/core-1.7.jar:/home/omidmohebbi/AAAATest/jars/javase-1.7.jar:/home/omidmohebbi/AAAATest/jars/qrgen-1.2.jar:" qrcode
私の場合、クラス名ではなくソースファイル名を指定したため、エラーが発生しました。
main メソッドを含むクラス名をインタープリターに提供する必要があります。
Mavenを使用して JAR ファイルをビルドする場合は、必ず pom.xml ファイルでメイン クラスを指定してください。
<build>
<plugins>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>class name us.com.test.abc.MyMainClass</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
ここでのすべての回答は、Windows ユーザーに向けられているようです。Mac の場合、クラスパス セパレータは:
であり、 ではありません;
。を使用してクラスパスを設定するエラー;
がスローされないため、Windows から Mac に移行する場合、これを発見するのが難しい場合があります。
対応する Mac コマンドは次のとおりです。
java -classpath ".:./lib/*" com.test.MyClass
この例では、パッケージはどこにcom.test
あり、lib
フォルダーもクラスパスに含まれます。
どういうわけかクラスパスを間違って設定していると思いましたが、問題は次のように入力したことです。
java -cp C:/java/MyClasses C:/java/MyClasses/utilities/myapp/Cool
それ以外の:
java -cp C:/java/MyClasses utilities/myapp/Cool
完全修飾の意味は、完全なパッケージ名の代わりに完全なパス名を含めることを意味すると思いました。
私の場合の問題を修正したのは次のとおりです。
実行するプロジェクト/クラスを右クリックし、Run As → Run Configurations。次に、既存の構成を修正するか、次の方法で新しい構成を追加する必要があります。
[クラスパス] タブを開き、 [詳細... ] ボタンをクリックして、プロジェクトのbin
フォルダーを追加します。
Windows では.;
、先頭に CLASSPATH 値を置きます。
。(ドット) は「現在のディレクトリを調べる」という意味です。これは恒久的な解決策です。
また、 set で「1回」設定することもできますCLASSPATH=%CLASSPATH%;.
。これは、コマンド ウィンドウが開いている限り続きます。
public static void main
Java では、Java インタープリター実行可能ファイルを使用してコマンド ラインから JVM を実行し、 (PSVM)を使用してクラス ファイルからプログラムを起動しようとすると、JVM へのクラスパス パラメーターが正確で、クラスファイルがクラスパスに存在します:
エラー: メイン クラスが見つからないか、ロードされていません
これは、PSVM を含むクラス ファイルをロードできなかった場合に発生します。考えられる理由の 1 つは、クラスがインターフェイスを実装しているか、クラスパスにない別のクラスを拡張している可能性があることです。通常、クラスがクラスパスにない場合、スローされるエラーはそのことを示します。ただし、使用中のクラスが拡張または実装されている場合、Java はクラス自体をロードできません。
参考:https ://www.computingnotes.net/java/error-main-class-not-found-or-loaded/
Java MongoDB JDBC 接続のテスト中にも、同様のエラーに直面しました。最終的な解決策を手短に要約するのは良いことだと思います。そうすれば、将来、誰でも 2 つのコマンドを直接調べて、さらに先に進むことができます。
Java ファイルと外部依存関係 (JAR ファイル) が存在するディレクトリーにいるとします。
コンパイル:
javac -cp mongo-java-driver-3.4.1.jar JavaMongoDBConnection.java
走る:
java -cp mongo-java-driver-3.4.1.jar: JavaMongoDBConnection
実行後にこのエラーが発生しましたmvn eclipse:eclipse
。.classpath
これは私のファイルを少し台無しにしました。
.classpath
からの行を変更する必要がありました
<classpathentry kind="src" path="src/main/java" including="**/*.java"/>
<classpathentry kind="src" path="src/main/resources" excluding="**/*.java"/>
に
<classpathentry kind="src" path="src/main/java" output="target/classes" />
<classpathentry kind="src" path="src/main/resources" excluding="**" output="target/classes" />
少し時間がかかった別の問題があります。コマンド ラインのクラス パス パラメータが期待どおりに動作しません。私は MacOS で CLI を直接呼び出しており、呼び出しに 2 つの jar を含めています。
たとえば、これらは両方とも、メイン クラスの名前についてツールを混乱させていました。
これは、アスタリスクが原因で引数が正しく解析されなかったためです。
java -cp path/to/jars/* com.mypackage.Main
そして、これは - 理由がわかりません:
java -cp "*.jar" com.mypackage.Main
これはうまくいきました:
java -cp "path/to/jars/*" com.mypackage.Main
2 つの jar を明示的にリストすることも機能しました。
java -cp path/to/jars/jar1.jar:path/to/jars/jar2.jar com.mypackage.Main
ときどき、あなたが試したことがあるかもしれないいくつかのオンライン コンパイラでは、記述せずpublic class [Classname]
にclass [Classname]
.
IntelliJ で作成したデモ プログラムでこの問題が発生しました。
それを解決するには、次の 2 つのポイントがあります。
私のデモプログラム:
package io.rlx.tij.c2;
public class Ex10 {
public static void main(String[] args) {
// do something
}
}
ソースコードのパス:
../projectRoot/src/main/java/io/rlx/tij/c2/Ex10.java
java
次のディレクトリに移動します。cd ../projectRoot/src/main/java
javac ./io/rlx/tij/c2/Ex10.java
java io.rlx.tij.c2.Ex10
でプログラムを../projectRoot/src/main/java/io/rlx/tij/c2
実行するか、パッケージ名なしで実行すると、次のエラーが発生します: Error: Could not find or load main class
.