「メインクラスを検索またはロードできませんでした」とはどういう意味ですか?

2013年08月07日に質問されました。  ·  閲覧回数 2.9M回  ·  ソース

Stephen C picture
2013年08月07日

新しいJava開発者が経験する一般的な問題は、プログラムが次のエラーメッセージで実行されないことです。 Could not find or load main class ...

これはどういう意味ですか、何が原因で、どのように修正する必要がありますか?

回答

Stephen C picture
2013年08月07日
1308

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コマンドは次のことを実行します。

  1. com.acme.example.ListUsersクラスのコンパイル済みバージョンを検索します。
  2. クラスをロードします。
  3. クラスに、 public static void main(String[])指定された署名戻り値の型、および修飾子を持つmainメソッドがあることを確認します。 (メソッド引数の名前は署名の一部ではないことに注意してください。)
  4. そのメソッドを呼び出して、コマンドライン引数( "fred"、 "joe"、 "bert")をString[]として渡します。

Javaがクラスを見つけられない理由

「メインクラスが見つかりませんでした。またはロードできませんでした...」というメッセージが表示された場合は、最初の手順が失敗したことを意味します。 javaコマンドはクラスを見つけることができませんでした。 実際、メッセージ内の「...」は、 javaが探している完全修飾クラス名になります。

では、なぜクラスが見つからないのでしょうか。

理由#1-クラス名引数を間違えた

最初に考えられる原因は、間違ったクラス名を指定した可能性があることです。 (または...正しいクラス名ですが、形式が間違っています。)上記の例を考慮して、クラス名を指定するためのさまざまな間違った方法を次に

  • 例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-アプリケーションのクラスパスが正しく指定されていない

2番目に考えられる原因は、クラス名は正しいが、 javaコマンドがクラスを見つけられないことです。 これを理解するには、「クラスパス」の概念を理解する必要があります。 これは、Oracleのドキュメントで十分に説明されています。

したがって...クラス名を正しく指定した場合、次に確認することは、クラスパスを正しく指定したことです。

  1. 上記のリンク先の3つのドキュメントをお読みください。 (はい...それらを読んでください!Javaプログラマー少なくともJavaクラスパスメカニズムがどのように機能するかの基本を
  2. javaコマンドを実行したときに有効なコマンドラインまたはCLASSPATH環境変数を確認します。 ディレクトリ名とJARファイル名が正しいことを確認してください。
  3. クラスパスに相対パス名がある場合は、それらが正しく解決されることを確認してください... javaコマンドを実行したときに有効になっている現在のディレクトリから。
  4. クラス(エラーメッセージに記載)が有効なクラスパスに配置されていることを確認します。
  5. クラスパス構文は、WindowsとLinuxおよびMacOSでは異なることに注意してください。 (クラスパスセパレーターは、Windowsでは; 、その他では:です。プラットフォームに間違ったセパレーターを使用すると、明示的なエラーメッセージは表示されません。代わりに、パス上に存在しないファイルまたはディレクトリで、サイレントに無視されます。)

理由#2a-間違ったディレクトリがクラスパスにあります

クラスパスにディレクトリを配置すると、概念的には、修飾された名前空間のルートに対応します。 クラスは、完全修飾名をパス名にマッピングすることにより、そのルートの下のディレクトリ構造に配置されます。 したがって、たとえば、「/ 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はクラスを見つけることができません。

理由#2b-サブディレクトリパスがFQNと一致しません

クラスの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オプションは、ほとんどのJavaリリースで-cpに短縮できます。 javajavacなどのそれぞれの手動エントリを確認してください。
  • クラスパスで絶対パス名と相対パス名を選択するときは、慎重に検討してください。 現在のディレクトリが変更されると、相対パス名が「壊れて」しまう可能性があることに注意してください。

理由#2c-クラスパスに依存関係がありません

クラスパスには、アプリケーションが依存する他の(システム以外の)クラスをすべて含める必要があります。 (システムクラスは自動的に配置され、これを気にする必要はほとんどありません。)メインクラスを正しくロードするには、JVMは以下を見つける必要があります。

(注:JLSおよびJVM仕様では、JVMがクラスを「遅延」でロードするためのスコープが許可されており、これはクラスローダー例外がスローされるときに影響を与える可能性があります。)

理由#3-クラスが間違ったパッケージで宣言されている

誰かがソースコードファイルをソースコードツリーの間違ったフォルダに置いたり、 package宣言を省略したりすることが時々あります。 IDEでこれを行うと、IDEのコンパイラがすぐにこれを通知します。 同様に、適切なJavaビルドツールを使用する場合、ツールは問題を検出する方法でjavacを実行します。 ただし、Javaコードを手動でビルドする場合は、コンパイラーが問題に気付かないようにすることができ、結果の「.class」ファイルは期待した場所にありません。

それでも問題を見つけることができませんか?

チェックすることがたくさんあり、何かを見逃しがちです。 -Xdiagオプションをjavaコマンドラインに追加してみてください( java後の最初のものとして)。 クラスのロードに関するさまざまな情報が出力されます。これにより、実際の問題が何であるかについての手がかりが得られる場合があります。

また、Webサイトやドキュメントなどから非表示または非ASCII文字をコピーして貼り付けることによって発生する可能性のある問題についても検討してください。 そして、「ホモグリフ」について考えてみましょう。2つの文字または記号は同じように見えますが、そうではありません。

最後に、 (META-INF/*.SF)署名が正しくないJARファイルから起動しようとすると、明らかにこの問題が発生する可能性があります。


java代替構文

java commandを使用してJavaプログラムを起動するための3つの代替構文があります。

1)「実行可能」JARファイルの起動に使用される構文は次のとおりです。

  java [ <options> ] -jar <jar-file-name> [<arg> ...]

例えば

  java -Xmx100m -jar /usr/local/acme-example/listuser.jar fred

エントリポイントクラスの名前(つまり、 com.acme.example.ListUser )とクラスパスは、JARファイルのMANIFESTで指定されます。

2)モジュール(Java 9以降)からアプリケーションを起動するための構文は次のとおりです。

  java [ <options> ] --module <module>[/<mainclass>] [<arg> ...]

エントリポイントクラスの名前は、 <module>自体によって定義されるか、オプションの<mainclass>によって指定されます。

3)Java 11以降では、単一のソースコードファイルをコンパイルして実行し、次の構文で実行できます。

  java [ <options> ] <sourcefile> [<arg> ...]

ここで、は(通常)接尾辞「.java」が付いたファイルです。

詳細については、使用しているJavaリリースのjavaコマンドの公式ドキュメントを参照してください。


IDE

一般的なJavaIDEは、IDEJVM自体または子JVMでのJavaアプリケーションの実行をサポートしています。 IDEは独自のメカニズムを使用してランタイムクラスパスを構築し、メインクラスを識別し、 javaコマンドラインを作成するため、これらは通常、この特定の例外の影響を受けません。

ただし、IDEの背後で何かを行うと、この例外が発生する可能性があります。 たとえば、以前にEclipseでJavaアプリのアプリケーションランチャーを設定し、Eclipseに通知せずに「main」クラスを含むJARファイルをファイルシステムの別の場所に移動した場合、Eclipseは無意識のうちにJVMを起動します。クラスパスが正しくありません。

つまり、IDEでこの問題が発生した場合は、IDEの状態が古い、プロジェクト参照が壊れている、ランチャー構成が壊れていないかどうかを確認してください。

IDEが単に混乱する可能性もあります。 IDEは、相互作用する多くの部分で構成される非常に複雑なソフトウェアです。 これらの部分の多くは、IDE全体の応答性を高めるために、さまざまなキャッシュ戦略を採用しています。 これらは時々うまくいかないことがあり、1つの考えられる症状はアプリケーションを起動するときの問題です。 これが発生している可能性があると思われる場合は、IDEの再起動、プロジェクトの再構築など、他のことを試す価値があります。


その他の参考資料

panoet picture
2014年05月21日
247

ソースコード名がHelloWorld.javaの場合、コンパイルされたコードはHelloWorld.classます。

次を使用して呼び出すと、そのエラーが発生します。

java HelloWorld.class

代わりに、これを使用してください:

java HelloWorld
tharinduwijewardane picture
2015年03月06日
148

クラスがパッケージ内にある場合は、プロジェクトのルートディレクトリにcdして、クラスの完全修飾名(packageName.MainClassName)を使用して実行する必要があります。

例:

私のクラスはここにあります:

D:\project\com\cse\

私のメインクラスの完全修飾名は次のとおりです。

com.cse.Main

だから私はcdをルートプロジェクトディレクトリに戻します:

D:\project

次に、 javaコマンドを発行します。

java com.cse.Main

この回答は、一般的な間違いによって引き起こされるフラストレーションから初心者のJavaプログラマーを救うためのものです。受け入れられた回答を読んで、Javaクラスパスに関するより深い知識を得ることをお勧めします。

M-Razavi picture
2014年10月27日
65

メインクラスとメインメソッドをpackagepackageName.MainClassName )を使用して、階層ディレクトリ上で実行する必要があります。

ソースコードファイル(Main.java)があると仮定します。

package com.test;

public class Main {

    public static void main(String[] args) {
        System.out.println("salam 2nya\n");
    }
}

このコードを実行するには、ディレクトリ./com/test/Main.JavaようなパッケージにMain.Classを配置する必要があります。 そして、ルートディレクトリでjava com.test.Mainます。

Enamul Hassan picture
2015年08月21日
50

同じコードが1つのPCで機能するが、別のPCでエラーが表示される場合、私がこれまでに見つけた最善の解決策は、次のようにコンパイルすることです。

javac HelloWorld.java
java -cp . HelloWorld
Celebes picture
2014年07月02日
38

私を助けたのは、コマンドラインでクラスパスを指定することでした。次に例を示します。

  1. 新しいフォルダC:\temp作成します

  2. 次のクラスを含むファイルTemp.javaをC:\tempに作成します。

    public class Temp {
        public static void main(String args[]) {
            System.out.println(args[0]);
        }
    }
    
  3. フォルダC:\tempでコマンドラインを開き、次のコマンドを記述してTempクラスをコンパイルします。

    javac Temp.java
    
  4. コンパイルされたJavaクラスを実行し、 -classpathオプションを追加して、クラスの場所をJREに知らせます。

    java -classpath C:\temp Temp Hello!
    
Xiao Peng - ZenUML.com picture
2015年09月17日
29

エラーメッセージ(「メインクラスが見つかりませんでした」)によると、問題には2つのカテゴリがあります。

  1. メインクラスが見つかりませんでした
  2. メインクラスをロードできませんでした(このケースは、受け入れられた回答で十分に説明されていません)

完全修飾クラス名にタイプミスまたは間違った構文がある、指定されたクラスパスに存在しない場合、メインクラスが見つかりませんでした

クラスを開始できない場合ロードできませんでした。通常、メインクラスは別のクラスを拡張し、そのクラスは指定されたクラスパスに存在しません。

例えば:

public class YourMain extends org.apache.camel.spring.Main

キャメルスプリングが含まれていない場合、このエラーが報告されます。

jan.supol picture
2016年08月24日
20

-Xdiagを試してください。

スティーブCの答えはうまく可能なケースをカバーし、時にはクラスが見つからないか、またはそれは容易ではないかもしれませんロードできなかったかどうかを判断します。 java -Xdiag使用します(JDK 7以降)。 これは、メッセージCould not find or load main classメッセージが何を意味するかについてのヒントを提供する素晴らしいスタックトレースを出力します。

たとえば、メインクラスによって使用されている他のクラスが見つからず、メインクラスのロードを妨げていることを示すことができます。

shaILU picture
2017年02月23日
18

次のコマンドを使用します。

java -cp . [PACKAGE.]CLASSNAME

例:クラス名がHello.javaから作成されたHello.classの場合は、次のコマンドを使用します。

java -cp . Hello

ファイルHello.javaがパッケージcom.demo内にある場合は、以下のコマンドを使用します

java -cp . com.demo.Hello

JDK 8では、クラスファイルが同じフォルダに存在することがよくありますが、 javaコマンドはクラスパスを想定しているため、 -cp .を追加して、現在のフォルダをクラスパスの参照として使用します。 。

Yamahar1sp picture
2016年09月22日
17

この場合、このようなエラーが発生しました。

java -cp lib.jar com.mypackage.Main

それはで動作します; Windows用と: Unix用:

java -cp lib.jar; com.mypackage.Main