java - "Could not find or load main class"是什么意思?

标签 java class main

新 Java 开发人员遇到的一个常见问题是他们的程序无法运行并显示以下错误消息:Could not find or load main class ...
这是什么意思,是什么原因造成的,你应该如何解决它?

最佳答案

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命令执行以下操作:
  • 搜索 com.acme.example.ListUsers 的编译版本类(class)。
  • 加载类。
  • 检查该类是否具有 main带有签名、返回类型和修饰符的方法由 public static void main(String[]) 给出. (注意,方法参数的名称是 不是 签名的一部分。)
  • 调用该方法,将命令行参数(“fred”、“joe”、“bert”)作为 String[] 传递给它.

  • Java找不到类的原因
    当您收到“Could not find or load main class ...”消息时,这意味着第一步失败了。 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 11 或更高版本除外;见下文)
    java ListUser.java
    
  • 示例 #6 - 你完全忘记了类名
    java lots of arguments
    

  • 原因 #2 - 应用程序的类路径指定不正确
    第二个可能的原因是类名是正确的,但 java命令找不到类。要理解这一点,您需要了解“类路径”的概念。 Oracle 文档对此进行了很好的解释:
  • The java command documentation
  • Setting the Classpath .
  • Java 教程 - PATH and CLASSPATH

  • 所以......如果你正确指定了类名,接下来要检查的是你是否正确指定了类路径:
  • 阅读上面链接的三个文件。 (是的……阅读它们!Java 程序员至少了解 Java 类路径机制如何工作的基础知识很重要。)
  • 查看命令行和/或运行 java 时生效的 CLASSPATH 环境变量。命令。检查目录名和 JAR 文件名是否正确。
  • 如果类路径中存在相对路径名,请检查它们是否正确解析...从运行 java 时生效的当前目录。命令。
  • 检查该类(错误消息中提到的)是否可以位于有效的类路径上。
  • 请注意,Windows 与 Linux 和 Mac OS 的类路径语法不同。 (类路径分隔符在 Windows 上是 ;,在其他系统上是 :。如果你的平台使用了错误的分隔符,你不会得到明确的错误消息。相反,你会得到一个不存在的文件或目录将被默默忽略的路径。)

  • 原因 #2a - 错误的目录在类路径上
    当您在类路径上放置一个目录时,它理论上对应于限定 namespace 的根。通过将完全限定名称映射到路径名,类位于该根目录下的目录结构中。因此,例如,如果“/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 不匹配
    如果您的类(class) 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类(class),
  • 完整的文件路径是 /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选项可以缩短为 -cp在大多数 Java 版本中。检查 java 的相应手册条目, javac等等。
  • 在类路径中的绝对路径名和相对路径名之间进行选择时要仔细考虑。请记住,如果当前目录更改,相对路径名可能会“中断”。

  • 原因 #2c - 类路径中缺少依赖项
    类路径需要包含您的应用程序依赖的所有其他(非系统)类。 (系统类是自动定位的,你很少需要关心这个。)为了正确加载主类,JVM 需要找到:
  • 类(class)本身。
  • 父类(super class)层次结构中的所有类和接口(interface)(例如,参见 Java class is present in classpath but startup fails with Error: Could not find or load main class)
  • 通过变量或变量声明、方法调用或字段访问表达式引用的所有类和接口(interface)。

  • (注意:JLS 和 JVM 规范允许 JVM 在一定范围内“延迟地”加载类,这会影响类加载器异常何时抛出。)
    原因 #3 - 该类已在错误的包中声明
    偶尔会发生有人将源代码文件放入
    在他们的源代码树中错误的文件夹,或者他们遗漏了 package宣言。如果您在 IDE 中执行此操作,IDE 的编译器会立即告诉您有关情况。同样,如果您使用一个不错的 Java 构建工具,该工具将运行 javac以一种能够检测到问题的方式。但是,如果您手动构建 Java 代码,那么编译器不会注意到问题,并且生成的“.class”文件不在您期望的位置。
    还是找不到问题?
    有很多东西要检查,很容易错过一些东西。尝试添加 -Xdiag java 的选项命令行(作为 java 之后的第一件事)。它将输出有关类加载的各种信息,这可能会为您提供有关真正问题所在的线索。
    此外,请考虑从网站、文档等中复制和粘贴不可见或非 ASCII 字符可能导致的问题。并考虑“同形文字”,其中两个字母或符号看起来相同……但并非如此。
    最后,如果您尝试从 (META-INF/*.SF) 中签名不正确的 JAR 文件启动,显然会遇到此问题。或者如果 MANIFEST.MF 中存在语法错误文件(见 https://stackoverflow.com/a/67145190/139985)。
    java 的替代语法
    使用 java command 启动 Java 程序有三种替代语法。 .
  • 用于启动“可执行”JAR 文件的语法如下:
    java [ <options> ] -jar <jar-file-name> [<arg> ...]
    
    例如
    java -Xmx100m -jar /usr/local/acme-example/listuser.jar fred
    
    入口点类的名称(即 com.acme.example.ListUser )和类路径在 JAR 文件的 MANIFEST 中指定。
  • 从模块(Java 9 及更高版本)启动应用程序的语法如下:
    java [ <options> ] --module <module>[/<mainclass>] [<arg> ...]
    
    入口点类的名称由 <module> 定义。本身,或者由可选的 <mainclass> 给出.
  • 从 Java 11 开始,您可以编译和运行单个源代码文件,并使用以下语法运行它:
    java [ <options> ] <sourcefile> [<arg> ...]
    
    哪里<sourcefile>是(通常)后缀为“.java”的文件。

  • 更多详情请引用java的官方文档您正在使用的 Java 版本的命令。

    集成开发环境
    典型的 Java IDE 支持在 IDE JVM 本身或子 JVM 中运行 Java 应用程序。这些通常不受此特定异常的影响,因为 IDE 使用自己的机制来构建运行时类路径、识别主类并创建 java。命令行。
    但是,如果您在 IDE 背后进行操作,则仍有可能发生此异常。例如,如果您之前在 Eclipse 中为您的 Java 应用程序设置了一个应用程序启动器,然后您将包含“主”类的 JAR 文件移动到文件系统中的不同位置,而没有告诉 Eclipse,Eclipse 将在不知不觉中启动 JVM使用不正确的类路径。
    简而言之,如果您在 IDE 中遇到此问题,请检查诸如过时的 IDE 状态、损坏的项目引用或损坏的启动器配置等内容。
    IDE 也可能会感到困惑。 IDE 是由许多交互部分组成的极其复杂的软件。其中许多部分采用了各种缓存策略,以使 IDE 作为一个整体进行响应。这些有时会出错,一种可能的症状是启动应用程序时出现问题。如果您怀疑这可能发生,值得尝试其他方法,例如重新启动 IDE、重建项目等。

    其他引用
  • 来自 Oracle Java 教程 - Common Problems (and Their Solutions)
  • 关于java - "Could not find or load main class"是什么意思?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18093928/

    相关文章:

    java - 从 mongodb 结果 java 中删除 _id

    c++ - 我将如何为列表编写 pop_front 函数?

    android - 不同 Activity 中的 AsyncTask 类?

    java - 成绩簿 Java 程序。帮忙打电话上课吗?

    linux - 为什么非图片代码不能完全使用运行时修复程序进行ASLR?

    C - 检查主要参数

    java - 默认情况在进入 switch-case 之前就被执行

    java - Bufferedreader 无法通过其他方法访问

    java - 智能 : Class not found: "" Empty test suite

    scala - 未检测到主类