协慌网

登录 贡献 社区

“无法找到或加载主类” 是什么意思?

新 Java 开发人员遇到的一个常见问题是,他们的程序无法运行并显示错误消息: Could not find or load main class ...

这是什么意思,是什么导致它,你应该如何解决它?

答案

java <class-name>命令语法

首先,您需要了解使用java (或javaw )命令启动程序的正确方法。

正常的语法1是这样的:

java [ <option> ... ] <class-name> [<argument> ...]

其中<option>是命令行选项(以 “-” 字符开头), <class-name>是完全限定的 Java 类名, <argument>是传递给应用程序的任意命令行参数。
1 - “可执行”JAR 文件有第二种语法,我将在底部描述。

该类的完全限定名称(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 - 你使用 classname 参数犯了一个错误

第一个可能的原因是您可能提供了错误的类名。 (或者...... 正确的类名,但形式错误。)考虑到上面的例子,这里有各种错误的方法来指定类名:

  • 示例#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 ListUser.java
  • 示例#6 - 您完全忘记了类名

    java lots of arguments

原因#2 - 未正确指定应用程序的类路径

第二个可能的原因是类名是正确的,但java命令找不到类。要理解这一点,您需要了解 “类路径” 的概念。 Oracle 文档很好地解释了这一点:

所以...... 如果你已经正确指定了类名,那么接下来要检查的是你已经正确地指定了类路径:

  1. 阅读上面链接的三个文件。 (是的...... 阅读。重要的是,Java 程序员理解的 Java 类路径的机制是如何工作的,至少基本资讯)。
  2. 查看运行java命令时生效的命令行和 / 或 CLASSPATH 环境变量。检查目录名称和 JAR 文件名是否正确。
  3. 如果类路径中有相对路径名,请检查它们是否正确解析... 从运行java命令时生效的当前目录。
  4. 检查类(在错误消息中提到)是否可以位于有效的类路径上。
  5. 请注意,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 将找不到您的类。

  • 如果您尝试通过移动来重命名一个类,那么它也将失败... 但异常堆栈跟踪将是不同的。

举一个具体的例子,假设:

  • 你想运行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 。检查javajavac等的相应手册条目。
  • 在类路径中选择绝对路径名和相对路径名时要仔细考虑。请记住,如果当前目录发生更改,相对路径名可能会 “中断”。

原因#2c - 类路径中缺少依赖项

类路径需要包含应用程序所依赖的所有其他 (非系统)类。 (系统类是自动定位的,你很少需要关注它。)为了正确加载主类,JVM 需要找到:

(注意:JLS 和 JVM 规范允许 JVM“延迟” 加载类的某些范围,这可能会影响何时抛出类加载器异常。)

原因#3 - 该类已在错误的包中声明

偶尔会有人将源代码文件放入其源代码树中的错误文件夹中,或者他们遗漏了package声明。如果您在 IDE 中执行此操作,IDE 的编译器将立即告诉您。同样,如果您使用一个不错的 Java 构建工具,该工具将以检测问题的方式运行javac 。但是,如果您手动构建 Java 代码,则可以使编译器不会注意到问题,并且生成的 “.class” 文件不在您期望的位置。

还是找不到问题?

有很多东西要检查,很容易错过一些东西。尝试将-Xdiag选项添加到java命令行(作为java之后的第一件事)。它将输出关于类加载的各种内容,这可以为您提供关于真正问题的线索。

另外,请考虑从网站,文档等复制和粘贴不可见或非 ASCII 字符可能导致的问题。并考虑 “同性恋”,两个字母或符号看起来相同...... 但不是。


java -jar <jar file>语法

用于 “可执行”JAR 文件的替代语法如下:

java [ <option> ... ] -jar <jar-file-name> [<argument> ...]

例如

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

在这种情况下,入口点类的名称(即com.acme.example.ListUser )和类路径在 JAR 文件的 MANIFEST 中指定。


集成开发环境

典型的 Java IDE 支持在 IDE JVM 本身或子 JVM 中运行 Java 应用程序。这些通常不受此特殊异常的影响,因为 IDE 使用自己的机制来构造运行时类路径,标识主类并创建java命令行。

但是,如果您在 IDE 后面执行操作,则仍可能发生此异常。例如,如果您之前在 Eclipse 中为 Java 应用程序设置了应用程序启动器,然后在不告知 Eclipse 的情况下将包含 “main” 类的 JAR 文件移动到文件系统中的其他位置,Eclipse 将无意中启动 JVM 使用不正确的类路径。

简而言之,如果您在 IDE 中遇到此问题,请检查旧的 IDE 状态,损坏的项目引用或损坏的启动程序配置等内容。

IDE 也可能简单地混淆。 IDE 是非常复杂的软件,包含许多交互部分。其中许多部分采用各种缓存策略,以使 IDE 作为一个整体响应。这些有时可能会出错,一种可能的症状是启动应用程序时出现问题。如果您怀疑可能发生这种情况,则值得重新启动 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