新 Java 开发人员遇到的一个常见问题是他们的程序无法运行并显示错误消息:Could not find or load main class ...
这是什么意思,是什么原因造成的,你应该如何解决它?
java
首先,您需要了解使用 java
(或 javaw
)命令启动程序的正确方法。
正常的语法是这样的:
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 类的编译版本。加载类。检查该类是否有一个带有签名、返回类型和由 public static void main(String[]) 给出的修饰符的 main 方法。 (注意,方法参数的名称不是签名的一部分。)调用该方法,将命令行参数(“fred”、“joe”、“bert”)作为 String[] 传递给它。
Java找不到类的原因
当您收到消息“无法找到或加载主类...”时,表示第一步失败。 java
命令无法找到该类。实际上,消息中的“...”将是 java
正在寻找的完全限定的类名。
那么为什么它可能找不到类呢?
原因 #1 - 你在 classname 参数上犯了一个错误
第一个可能的原因是您可能提供了错误的类名。 (或者......正确的类名,但格式错误。)考虑到上面的例子,这里有多种错误的方式来指定类名:
示例#1 - 一个简单的类名:java ListUser 当类在包中声明时,例如 com.acme.example,那么您必须在 java 命令中使用包括包名在内的完整类名;例如 java com.acme.example.ListUser
示例 #2 - 文件名或路径名而不是类名:java ListUser.class java com/acme/example/ListUser.class
Example #3 - 一个大小写不正确的类名:java com.acme.example.listuser
示例 #4 - 一个错字 java com.acme.example.mistuser
示例 #5 - 源文件名(Java 11 或更高版本除外;见下文)java ListUser.java
Example #6 - 你完全忘记了类名 java很多参数
原因 #2 - 应用程序的类路径指定不正确
第二个可能的原因是类名正确,但 java
命令找不到该类。要理解这一点,您需要了解“类路径”的概念。 Oracle 文档对此进行了很好的解释:
java命令文档
设置类路径。
Java 教程 - PATH 和 CLASSPATH
所以......如果您正确指定了类名,接下来要检查的是您是否正确指定了类路径:
阅读上面链接的三个文件。 (是的......阅读它们!重要的是,Java 程序员至少了解 Java 类路径机制如何工作的基础知识。)查看命令行和/或运行 java 命令时生效的 CLASSPATH 环境变量.检查目录名和 JAR 文件名是否正确。如果类路径中有相对路径名,请检查它们是否正确解析......从运行 java 命令时有效的当前目录。检查类(在错误消息中提到)是否可以位于有效的类路径上。请注意,Windows 与 Linux 和 Mac OS 的类路径语法不同。 (类路径分隔符在 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:
举一个具体的例子,假设:
你想运行 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
笔记:
在大多数 Java 版本中,-classpath 选项可以缩短为 -cp。检查 java、javac 等的相应手册条目。
在类路径中选择绝对路径名和相对路径名时要仔细考虑。请记住,如果当前目录更改,相对路径名可能会“中断”。
原因 #2c - 类路径中缺少依赖项
类路径需要包含您的应用程序所依赖的所有其他(非系统)类。 (系统类是自动定位的,你很少需要关心这个。)要正确加载主类,JVM 需要找到:
类本身。
超类层次结构中的所有类和接口(例如,参见 Java 类存在于类路径中,但启动失败并出现错误:无法找到或加载主类)
通过变量或变量声明、方法调用或字段访问表达式引用的所有类和接口。
(注意:JLS 和 JVM 规范允许 JVM 在一定范围内“延迟”加载类,这会影响何时引发类加载器异常。)
原因 #3 - 该类已在错误的包中声明
有时有人将源代码文件放入其源代码树中的错误文件夹中,或者他们遗漏了 package
声明。如果您在 IDE 中执行此操作,IDE 的编译器会立即告诉您这一点。同样,如果您使用一个不错的 Java 构建工具,该工具将以检测问题的方式运行 javac
。但是,如果您手动构建 Java 代码,那么编译器可能不会注意到问题,并且生成的“.class”文件不在您期望的位置。
还是找不到问题?
有很多东西要检查,很容易错过一些东西。尝试将 -Xdiag
选项添加到 java
命令行(作为 java
之后的第一件事)。它将输出有关类加载的各种信息,这可能会为您提供关于真正问题所在的线索。
此外,请考虑从网站、文档等复制和粘贴不可见或非 ASCII 字符可能导致的问题。并考虑“同形文字”,其中两个字母或符号看起来相同......但不是。
如果您在 META-INF/*.SF
中有无效或不正确的签名,您可能会遇到此问题。您可以尝试在您最喜欢的 ZIP 编辑器中打开 .jar,然后从 META-INF
中删除文件,直到您只剩下 MANIFEST.MF
。但是,一般不建议这样做。 (无效签名可能是由于有人将恶意软件注入到原始签名的 JAR 文件中。如果您删除了无效签名,您就是在用恶意软件感染您的应用程序!)推荐的方法是获取具有有效的 JAR 文件签名,或从(真实的)原始源代码重建它们。
最后,如果 MANIFEST.MF
文件中存在语法错误(请参阅 https://stackoverflow.com/a/67145190/139985),您显然会遇到此问题。
java的替代语法
使用 java command
启动 Java 程序有三种替代语法。
用于启动“可执行”JAR 文件的语法如下: java [
有关更多详细信息,请参阅您正在使用的 Java 版本的 java
命令的官方文档。
IDE
典型的 Java IDE 支持在 IDE JVM 本身或子 JVM 中运行 Java 应用程序。这些通常不受此特定异常的影响,因为 IDE 使用自己的机制来构建运行时类路径、识别主类并创建 java
命令行。
但是,如果您在 IDE 后面执行操作,则仍有可能发生此异常。例如,如果您之前在 Eclipse 中为您的 Java 应用程序设置了一个应用程序启动器,然后您将包含“main”类的 JAR 文件移动到文件系统中的不同位置而没有告诉 Eclipse,Eclipse 会在不知不觉中启动 JVM使用不正确的类路径。
简而言之,如果您在 IDE 中遇到此问题,请检查过时的 IDE 状态、损坏的项目引用或损坏的启动器配置等。
IDE 也可能会简单地感到困惑。 IDE 是非常复杂的软件,包含许多交互部分。其中许多部分采用各种缓存策略,以使 IDE 作为一个整体响应。这些有时会出错,一个可能的症状是启动应用程序时出现问题。如果您怀疑这可能会发生,那么值得尝试其他方法,例如重新启动 IDE、重建项目等等。
其他参考
来自 Oracle Java 教程 - 常见问题(及其解决方案)
如果您的源代码名称是 HelloWorld.java,那么您的编译代码将为 HelloWorld.class
。
如果您使用以下方法调用它,您将收到该错误:
java HelloWorld.class
相反,使用这个:
java HelloWorld
javac TestCode.java
,然后是 java TestCode
java -classpath . HelloWorld
如果您的类在包中,那么您必须 cd
到项目的根目录并使用类的完全限定名称 (packageName.MainClassName) 运行。
例子:
我的课在这里:
D:\project\com\cse\
我的主类的完全限定名称是:
com.cse.Main
所以我cd
回到根项目目录:
D:\project
然后发出 java
命令:
java com.cse.Main
这个答案是为了将新手 Java 程序员从一个常见错误造成的挫折中解救出来。我建议您阅读接受的答案,以更深入地了解 Java 类路径。
java com.firstpackage.Test
不起作用,命令 java -classpath C:\Users\matuagkeetarp\IdeaProjects\Helloworld\src\com\firstpackage Test.java
也没有设置类路径变量。你能帮我吗?
使用关键字“包”
如果您的源代码中有 package
关键字(主类在包中定义),您应该使用类的全名(packageName.MainClassName
)。
假设有一个源代码文件(Main.java):
package com.test;
public class Main {
public static void main(String[] args) {
System.out.println("salam 2nya\n");
}
}
要运行此代码,您应该将 Main.Class
放在 package like 目录中:
C:\Users\workspace\testapp\com\test\Main.Java
然后将终端的当前目录更改为项目的根目录:
cd C:\Users\workspace\testapp
最后,运行代码:
java com.test.Main
没有关键字“包”
如果您的源代码名称上没有任何包,则可能是您输入了错误的命令。假设您的 Java 文件名为 Main.java
,编译后:
javac Main.java
您的编译代码将是 Main.class
如果您使用以下方法调用它,您将收到该错误:
java Main.class
相反,使用这个:
java Main
当相同的代码在一台 PC 上运行,但在另一台 PC 上显示错误时,我发现的最佳解决方案是编译如下:
javac HelloWorld.java
java -cp . HelloWorld
javac -classpath . HelloWorld.java
肯定会奏效!在您的情况下,这是一个更好的解决方案。
在命令行上指定类路径对我有帮助。例如:
创建一个新文件夹 C:\temp 在 C:\temp 中创建文件 Temp.java,其中包含以下类: public class Temp { public static void main(String args[]) { System.out.println(args[ 0]);在文件夹 C:\temp 中打开命令行,编写以下命令编译 Temp 类: javac Temp.java 运行编译后的 Java 类,添加 -classpath 选项让 JRE 知道在哪里可以找到该类:java -classpath C:\temp Temp 你好!
java
没有查看 $CLASSPATH(因为您使用了 -classpath 或 -jar)或 2) 未在 中的环境中设置类路径设置在运行 java
的上下文中效果;例如,因为您没有在正确的 shell 中“获取”添加 setenv 命令的文件。
根据报错信息(“Could not find or load main class”),有两类问题:
找不到主类无法加载主类(在接受的答案中没有完全讨论这种情况)
当完全限定的类名中存在拼写错误或语法错误或在提供的类路径中不存在时,找不到 Main 类。
无法启动类时无法加载主类。通常主类扩展另一个类,并且该类不存在于提供的类路径中。
例如:
public class YourMain extends org.apache.camel.spring.Main
如果不包含camel-spring,会报这个错误。
extends
的答案)。我刚刚了解到,当主类由于扩展了另一个无法找到而无法加载时,java 不会报告哪个实际类是未找到(与 NoClassDefFoundError
不同)。所以是的,它确实发生了,当你不知道这一点时,这是一个令人毛骨悚然的情况。
使用这个命令:
java -cp . [PACKAGE.]CLASSNAME
示例:如果您的类名是从 Hello.java 创建的 Hello.class,则使用以下命令:
java -cp . Hello
如果您的文件 Hello.java 在包 com.demo 中,则使用以下命令
java -cp . com.demo.Hello
在 JDK 8 中,类文件经常出现在同一个文件夹中,但 java
命令需要类路径,因此我们添加 -cp .
以将当前文件夹作为参考类路径。
-cp .
是不必要的,因为如果未设置 $CLASSPATH
,则 .
是默认的类路径。
echo %CLASSPATH%
输出什么?)不,我无法检查,因为我没有 Windows PC。
在这种情况下,我遇到了这样的错误:
java -cp lib.jar com.mypackage.Main
它适用于 Windows 的 ;
和 Unix 的 :
:
java -cp lib.jar; com.mypackage.Main
Main
不在 JAR 文件中。 -cp lib.jar;
与 -cp lib.jar;.
的含义相同,即当前目录包含在类路径中。
试试 -Xdiag。
Steve C's answer 很好地涵盖了可能的情况,但有时要确定类是无法找到还是加载可能并不那么容易。使用 java -Xdiag
(自 JDK 7 起)。这会打印出一个很好的堆栈跟踪,它为消息 Could not find or load main class
消息的含义提供了一个提示。
例如,它可以将您指向无法找到的主类使用的其他类,并阻止加载主类。
有时可能导致问题的原因与主要课程无关,我不得不以艰难的方式找出这一点。这是我移动的一个引用库,它给了我:
无法找到或加载主类 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
在这种情况下,您有:
无法找到或加载主类?classpath
这是因为您使用的是“-classpath”,但破折号与命令提示符上 java
使用的破折号不同。我在从 Notepad 复制和粘贴到 cmd 时遇到了这个问题。
如果您使用 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>
就我而言,出现错误是因为我提供了源文件名而不是类名。
我们需要向解释器提供包含 main 方法的类名。
如果您的情况特别像我的情况,这可能会对您有所帮助:作为初学者,我在尝试运行 Java 程序时也遇到了这个问题。
我是这样编译的:
javac HelloWorld.java
我也尝试使用相同的扩展名运行:
java Helloworld.java
当我删除 .java
并重写 java HelloWorld
之类的命令时,程序运行完美。 :)
这里的所有答案似乎都是针对 Windows 用户的。对于 Mac,类路径分隔符是 :
,而不是 ;
。由于没有抛出使用 ;
设置类路径的错误,因此如果从 Windows 到 Mac,这可能很难发现。
这是相应的Mac命令:
java -classpath ".:./lib/*" com.test.MyClass
在此示例中,包为 com.test
,并且类路径中还包含一个 lib
文件夹。
/*
?
https://i.stack.imgur.com/eegzM.png
类文件位置:C:\test\com\company
文件名:Main.class
完全限定的类名:com.company.Main
命令行命令:
java -classpath "C:\test" com.company.Main
请注意,类路径不包括 \com\company。
我以为我以某种方式错误地设置了我的类路径,但问题是我输入了:
java -cp C:/java/MyClasses C:/java/MyClasses/utilities/myapp/Cool
代替:
java -cp C:/java/MyClasses utilities/myapp/Cool
我认为完全限定的意思是包含完整的路径名而不是完整的包名。
utilities.myapp.Cool
或其包名称(如果有)的形式给出。
在 Windows 上,将 .;
放在开头的 CLASSPATH 值中。
这 。 (点)表示“查看当前目录”。这是一个永久的解决方案。
您也可以使用 set CLASSPATH=%CLASSPATH%;.
将其设置为“一次性”。只要您的 cmd 窗口打开,这将持续。
在 Windows PowerShell 中宣传的使用 -cp
选项运行 java
时,您可能会收到类似于以下内容的错误:
The term `ClassName` is not recognized as the name of a cmdlet, function, script ...
为了让 PowerShell 接受命令,-cp
选项的参数必须包含在引号中,如下所示:
java -cp 'someDependency.jar;.' ClassName
以这种方式形成命令应该允许 Java 正确处理类路径参数。
在我的情况下解决问题的是:
右键单击要运行的项目/类,然后运行方式 → 运行配置。然后,您应该通过以下方式修复现有配置或添加新配置:
打开 Classpath 选项卡,单击 Advanced... 按钮,然后添加您项目的 bin
文件夹。
首先使用该命令设置路径;
set path="paste the set path address"
然后你需要加载程序。在存储的驱动器中键入“cd(文件夹名称)”并编译它。例如,如果我的程序存储在 D 盘,输入“D:”按回车并输入“cd(文件夹名称)”。
if "cd" helps then it by luck rather than by judgement
。这是错误的(我相信),因为 java 默认使用当前目录 .
作为类路径的一部分。
在 Java 中,当您有时使用 Java 解释器可执行文件从命令行运行 JVM 并尝试使用 public static void main
(PSVM) 从类文件启动程序时,即使 classpath 参数为JVM 是准确的,并且类文件存在于类路径中:
错误:找不到或未加载主类
如果无法加载带有 PSVM 的类文件,则会发生这种情况。一个可能的原因是该类可能正在实现一个接口或扩展另一个不在类路径上的类。通常,如果一个类不在类路径上,则抛出的错误表明如此。但是,如果正在使用的类被扩展或实现,Java 就无法加载该类本身。
参考:https://www.computingnotes.net/java/error-main-class-not-found-or-loaded/
您确实需要从 src
文件夹执行此操作。在此处键入以下命令行:
[name of the package].[Class Name] [arguments]
假设您的类名为 CommandLine.class
,代码如下所示:
package com.tutorialspoint.java;
/**
* Created by mda21185 on 15-6-2016.
*/
public class CommandLine {
public static void main(String args[]){
for(int i=0; i<args.length; i++){
System.out.println("args[" + i + "]: " + args[i]);
}
}
}
然后您应该 cd
到 src 文件夹,您需要运行的命令如下所示:
java com.tutorialspoint.java.CommandLine this is a command line 200 -100
命令行上的输出将是:
args[0]: this
args[1]: is
args[2]: a
args[3]: command
args[4]: line
args[5]: 200
args[6]: -100
cd
进入 src
,然后运行对我有用的命令 java ../bin com.blah.blah.MyClass
。所以谢谢你的提示!
好吧,已经有很多答案了,但是没有人提到文件权限可能是罪魁祸首的情况。
运行时,用户可能无法访问 JAR 文件或路径的目录之一。例如,考虑:
/dir1/dir2/dir3/myjar.jar
中的 Jar 文件
拥有 JAR 文件的 User1 可以执行以下操作:
# Running as User1
cd /dir1/dir2/dir3/
chmod +r myjar.jar
但它仍然不起作用:
# Running as User2
java -cp "/dir1/dir2/dir3:/dir1/dir2/javalibs" MyProgram
Error: Could not find or load main class MyProgram
这是因为运行用户 (User2) 无权访问 dir1、dir2 或 javalibs 或 dir3。当用户 1 可以看到文件并且可以访问它们时,它可能会让某人发疯,但是用户 2 仍然会发生错误。
在测试 Java MongoDB JDBC 连接时,我也遇到了类似的错误。我认为简短地总结我的最终解决方案是很好的,以便将来任何人都可以直接查看这两个命令并且可以进一步进行。
假设您位于 Java 文件和外部依赖项(JAR 文件)所在的目录中。
编译:
javac -cp mongo-java-driver-3.4.1.jar JavaMongoDBConnection.java
-cp - 类路径参数;一个一个地传递所有依赖的 JAR 文件
*.java - 这是具有 main 方法的 Java 类文件。 sdsd
跑:
java -cp mongo-java-driver-3.4.1.jar: JavaMongoDBConnection
请在所有依赖 JAR 文件结束后注意冒号 (Unix) / 逗号 (Windows)
最后,观察没有任何扩展名的主类名(没有.class或.java)
JavaMongoDBConnection
没有包,并且 2) 您不更改目录。至少可以说,它是脆弱的。由于不解释问题,它会导致新手尝试这种方法在它不起作用的情况下。简而言之,它鼓励“巫毒编程技术”:en.wikipedia.org/wiki/Voodoo_programming
我无法使用此处所述的解决方案解决此问题(尽管所述答案无疑清除了我的概念)。我两次遇到这个问题,每次我都尝试了不同的解决方案(在 Eclipse IDE 中)。
首先,我在项目的不同类别中遇到了多种主要方法。因此,我从后续课程中删除了 main 方法。
其次,我尝试了以下解决方案:右键单击我的主项目目录。前往源代码,然后清理并坚持使用默认设置并点击完成。在完成一些后台任务后,您将被定向到您的主项目目录。之后我关闭我的项目,重新打开它,然后繁荣,我终于解决了我的问题。
右键单击我的主项目目录。
前往源代码,然后清理并坚持使用默认设置并点击完成。在完成一些后台任务后,您将被定向到您的主项目目录。
之后我关闭我的项目,重新打开它,然后繁荣,我终于解决了我的问题。
main
方法不会解决问题。具有多个入口点的应用程序在技术上没有任何问题。
有时,在您可能尝试过的某些在线编译器中,如果您不编写 public class [Classname]
而只编写 class [Classname]
,则会收到此错误。
public
是常规/正常的,但 Java 规范不需要这样做,标准 Oracle / OpenJDK java
命令也不需要。
java -cp ../third-party-library.jar com.my.package.MyClass
;这不起作用,而是需要将本地文件夹也添加到类路径中(由:
分隔,如下所示:java -cp ../third-party-library.jar:. com.my.package.MyClass
,那么它应该可以工作java
并没有说它没有找到导入的类,而是说您尝试运行的主类。这是一种误导,尽管我确信这是有原因的。我遇到过java
确切知道我的班级在哪里的情况,但是它找不到导入的班级之一。它没有这么说,而是抱怨找不到我的主要课程。真的,很烦。