「メインクラスが見つからないか、ロードできませんでした」とはどういう意味ですか? 質問する

「メインクラスが見つからないか、ロードできませんでした」とはどういう意味ですか? 質問する

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

これは何を意味し、何が原因で、どのように修正すればよいのでしょうか?

ベストアンサー1

コマンド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. クラスに、シグネチャ戻り値の型および で指定された修飾子mainを持つメソッドがあることを確認します。(メソッド引数の名前はシグネチャの一部ではないことに注意してください。)public static void main(String[])
  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
    
  • Example #5 - a source filename (except for Java 11 or later; see below)

    java ListUser.java
    
  • Example #6 - you forgot the class name entirely

    java lots of arguments
    

Reason #2 - the application's classpath is incorrectly specified

The second likely cause is that the class name is correct, but that the java command cannot find the class. To understand this, you need to understand the concept of the "classpath". This is explained well by the Oracle documentation:

So ... if you have specified the class name correctly, the next thing to check is that you have specified the classpath correctly:

  1. Read the three documents linked above. (Yes ... READ them! It is important that a Java programmer understands at least the basics of how the Java classpath mechanisms works.)
  2. Look at command line and / or the CLASSPATH environment variable that is in effect when you run the java command. Check that the directory names and JAR file names are correct.
  3. If there are relative pathnames in the classpath, check that they resolve correctly ... from the current directory that is in effect when you run the java command.
  4. Check that the class (mentioned in the error message) can be located on the effective classpath.
  5. Note that the classpath syntax is different for Windows versus Linux and Mac OS. (The classpath separator is ; on Windows and : on the others. If you use the wrong separator for your platform, you won't get an explicit error message. Instead, you will get a nonexistent file or directory on the path that will be silently ignored.)

Reason #2a - the wrong directory is on the classpath

When you put a directory on the classpath, it notionally corresponds to the root of the qualified name space. Classes are located in the directory structure beneath that root, by mapping the fully qualified name to a pathname. So for example, if "/usr/local/acme/classes" is on the class path, then when the JVM looks for a class called com.acme.example.Foon, it will look for a ".class" file with this pathname:

  /usr/local/acme/classes/com/acme/example/Foon.class

If you had put "/usr/local/acme/classes/com/acme/example" on the classpath, then the JVM wouldn't be able to find the class.

Reason #2b - the subdirectory path doesn't match the FQN

If your classes FQN is com.acme.example.Foon, then the JVM is going to look for "Foon.class" in the directory "com/acme/example":

  • If your directory structure doesn't match the package naming as per the pattern above, the JVM won't find your class.

  • If you attempt rename a class by moving it, that will fail as well ... but the exception stacktrace will be different. It is liable to say something like this:

    Caused by: java.lang.NoClassDefFoundError: <path> (wrong name: <name>)
    

    because the FQN in the class file doesn't match what the class loader is expecting to find.

To give a concrete example, supposing that:

  • you want to run com.acme.example.Foon class,
  • the full file path is /usr/local/acme/classes/com/acme/example/Foon.class,
  • your current working directory is /usr/local/acme/classes/com/acme/example/,

then:

# 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

Notes:

  • The -classpath option can be shortened to -cp in most Java releases. Check the respective manual entries for java, javac and so on.
  • Think carefully when choosing between absolute and relative pathnames in classpaths. Remember that a relative pathname may "break" if the current directory changes.

Reason #2c - dependencies missing from the classpath

The classpath needs to include all of the other (non-system) classes that your application depends on. (The system classes are located automatically, and you rarely need to concern yourself with this.) For the main class to load correctly, the JVM needs to find:

(Note: the JLS and JVM specifications allow some scope for a JVM to load classes "lazily", and this can affect when a classloader exception is thrown.)

Reason #3 - the class has been declared in the wrong package

It occasionally happens that someone puts a source code file into the the wrong folder in their source code tree, or they leave out the package declaration. If you do this in an IDE, the IDE's compiler will tell you about this immediately. Similarly if you use a decent Java build tool, the tool will run javac in a way that will detect the problem. However, if you build your Java code by hand, you can do it in such a way that the compiler doesn't notice the problem, and the resulting ".class" file is not in the place that you expect it to be.

Still can't find the problem?

There lots of things to check, and it is easy to miss something. Try adding the -Xdiag option to the java command line (as the first thing after java). It will output various things about class loading, and this may offer you clues as to what the real problem is.

Also, consider possible problems caused by copying and pasting invisible or non-ASCII characters from websites, documents and so on. And consider "homoglyphs", where two letters or symbols look the same ... but aren't.

You may run into this problem if you have invalid or incorrect signatures in META-INF/*.SF. You can try opening up the .jar in your favorite ZIP editor, and removing files from META-INF until all you have is your MANIFEST.MF. However this is NOT RECOMMENDED in general. (The invalid signature may be the result of someone having injected malware into the original signed JAR file. If you erase the invalid signature, you are in infecting your application with the malware!) The recommended approach is to get hold of JAR files with valid signatures, or rebuild them from the (authentic) original source code.

Finally, you can apparently run into this problem if there is a syntax error in the MANIFEST.MF file (see https://stackoverflow.com/a/67145190/139985).


Alternative syntaxes for java

There are three alternative syntaxes for the launching Java programs using the java command.

  1. The syntax used for launching an "executable" JAR file is as follows:

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

    e.g.

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

    The name of the entry-point class (i.e. com.acme.example.ListUser) and the classpath are specified in the MANIFEST of the JAR file. Anything you specify as a classpath on the command line is ignored with this syntax: only the Class-Path entry in the Manifest is used (and, transitively, those in any JAR files referenced by this entry). Note also that URLs in this Class-Path are relative to the location of the JAR it is contained in.

  2. The syntax for launching an application from a module (Java 9 and later) is as follows:

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

    The name of the entrypoint class is either defined by the <module> itself, or is given by the optional <mainclass>.

  3. From Java 11 onwards, you can use the java command to compile and run a single source code file using the following syntax:

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

    where <sourcefile> is (typically) a file with the suffix ".java".

For more details, please refer to the official documentation for the java command for the Java release that you are using.


IDEs

A typical Java IDE has support for running Java applications in the IDE JVM itself or in a child JVM. These are generally immune from this particular exception, because the IDE uses its own mechanisms to construct the runtime classpath, identify the main class and create the java command line.

However it is still possible for this exception to occur, if you do things behind the back of the IDE. For example, if you have previously set up an Application Launcher for your Java app in Eclipse, and you then moved the JAR file containing the "main" class to a different place in the file system without telling Eclipse, Eclipse would unwittingly launch the JVM with an incorrect classpath.

In short, if you get this problem in an IDE, check for things like stale IDE state, broken project references or broken launcher configurations.

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


その他の参考文献

おすすめ記事