新 Java 开发人员遇到的一个常见问题是他们的程序无法运行并显示错误消息:Could not find or load main class …
Could not find or load main class
这是什么意思,是什么原因造成的,你应该如何解决它?
首先,您需要了解使用java(或javaw)命令启动程序的正确方法。
java
javaw
正常的语法1是这样的:
java [ <options> ] <class-name> [<arg> ...]
where<option>是命令行选项(以“-”字符开头),<class-name>是完全限定的 Java 类名,<arg>是传递给应用程序的任意命令行参数。
<option>
<class-name>
<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[]
当您收到消息“无法找到或加载主类…”时,表示第一步失败。该java命令无法找到该类。事实上,消息中的“…”将是正在寻找的完全限定的类名。java
那么为什么它可能找不到类呢?
第一个可能的原因是您可能提供了错误的类名。(或者......正确的类名,但格式错误。)考虑到上面的例子,这里有多种指定类名的错误方法:
java java ListUser
当类在包中声明时,例如com.acme.example,您必须使用完整的类名,包括命令中的包名java;例如
com.acme.example
java java com.acme.example.ListUser
java java ListUser.class java com/acme/example/ListUser.class
java java com.acme.example.listuser
java java com.acme.example.mistuser
java java ListUser.java
java java lots of arguments
第二个可能的原因是类名正确,但是java命令找不到类。要理解这一点,您需要了解“类路径”的概念。Oracle 文档很好地解释了这一点:
所以…如果您正确指定了类名,接下来要检查的是您是否正确指定了类路径:
;
:
当您将目录放在类路径上时,它理论上对应于限定名称空间的根目录。通过将完全限定名映射到路径名,类位于该根目录下的目录结构中。例如,如果“/usr/local/acme/classes”在类路径上,那么当 JVM 查找名为 的类时com.acme.example.Foon,它将查找具有此路径名的“.class”文件:
com.acme.example.Foon
/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 将找不到您的类。
如果您尝试通过移动它来重命名一个类,那也会失败......但异常堆栈跟踪会有所不同。很容易说这样的话:
java Caused by: java.lang.NoClassDefFoundError: <path> (wrong name: <name>)
因为类文件中的 FQN 与类加载器期望找到的不匹配。
举一个具体的例子,假设:
/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
javac
类路径需要包含您的应用程序所依赖的所有其他(非系统)类。(系统类是自动定位的,你很少需要关心这个。)为了正确加载主类,JVM 需要找到:
(注意:JLS 和 JVM 规范允许 JVM 在一定范围内“延迟”加载类,这会影响何时引发类加载器异常。)
偶尔会发生有人将源代码文件放入源代码树中错误的文件夹中,或者他们遗漏了package声明。如果您在 IDE 中执行此操作,IDE 的编译器会立即告诉您这一点。同样,如果您使用一个不错的 Java 构建工具,该工具javac将以检测问题的方式运行。但是,如果您手动构建您的 Java 代码,您可以这样做,编译器不会注意到问题,并且生成的“.class”文件不在您期望的位置。
package
有很多东西要检查,很容易错过一些东西。尝试将-Xdiag选项添加到java命令行(作为 之后的第一件事java)。它将输出有关类加载的各种信息,这可能会为您提供关于真正问题所在的线索。
-Xdiag
此外,请考虑从网站、文档等复制和粘贴不可见或非 ASCII 字符可能导致的问题。并考虑“同形文字”,其中两个字母或符号看起来相同......但不是。
如果您的签名无效或不正确,您可能会遇到此问题META-INF/*.SF。您可以尝试在您最喜欢的 ZIP 编辑器中打开 .jar,然后从中删除文件,META-INF直到您拥有.jar 文件为止MANIFEST.MF。但是,一般不建议这样做。(无效签名可能是由于有人将恶意软件注入到原始签名的 JAR 文件中。如果您删除了无效签名,您就是在用恶意软件感染您的应用程序!)推荐的方法是获取具有有效的 JAR 文件签名,或从(真实的)原始源代码重建它们。
META-INF/*.SF
META-INF
MANIFEST.MF
最后,如果MANIFEST.MF文件中存在语法错误,您显然会遇到此问题
使用java command.
java command
java java [ <options> ] -jar <jar-file-name> [<arg> ...]
例如
java java -Xmx100m -jar /usr/local/acme-example/listuser.jar fred
入口点类的名称(即com.acme.example.ListUser)和类路径在 JAR 文件的 MANIFEST 中指定。
com.acme.example.ListUser
java java [ <options> ] --module <module>[/<mainclass>] [<arg> ...]
入口点类的名称要么由它<module>自己定义,要么由可选的 给定<mainclass>。
<module>
<mainclass>
java java [ <options> ] <sourcefile> [<arg> ...]
where<sourcefile>是(通常)带有后缀“.java”的文件。
<sourcefile>
有关更多详细信息,请参阅java您正在使用的 Java 版本的命令的官方文档。
典型的 Java IDE 支持在 IDE JVM 本身或子 JVM 中运行 Java 应用程序。这些通常不受此特定异常的影响,因为 IDE 使用自己的机制来构建运行时类路径、识别主类并创建java命令行。
但是,如果您在 IDE 后面执行操作,则仍有可能发生此异常。例如,如果您之前在 Eclipse 中为您的 Java 应用程序设置了 Application Launcher,然后您将包含“main”类的 JAR 文件移动到文件系统中的不同位置,而没有告诉 Eclipse,Eclipse 会在不知不觉中启动 JVM使用不正确的类路径。
简而言之,如果您在 IDE 中遇到此问题,请检查过时的 IDE 状态、损坏的项目引用或损坏的启动器配置等。
IDE 也可能会简单地感到困惑。IDE 是非常复杂的软件,包含许多交互部分。其中许多部分采用各种缓存策略,以使 IDE 作为一个整体响应。这些有时会出错,一个可能的症状是启动应用程序时出现问题。如果您怀疑这可能会发生,那么值得尝试其他方法,例如重新启动 IDE、重建项目等等。