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

Ste*_*n C 1277 java program-entry-point class

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

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

Ste*_*n C 1145

java <class-name>命令语法

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

正常的语法1是这样的:

    java [ <option> ... ] <class-name> [<argument> ...]
Run Code Online (Sandbox Code Playgroud)

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

该类的完全限定名称(FQN)通常按照Java源代码编写; 例如

    packagename.packagename2.packagename3.ClassName
Run Code Online (Sandbox Code Playgroud)

但是,该java命令的某些版本允许您使用斜杠而不是句点; 例如

    packagename/packagename2/packagename3/ClassName
Run Code Online (Sandbox Code Playgroud)

其中(令人困惑)看起来像文件路径名,但不是一个.请注意,术语完全限定名称是标准Java术语...而不是我只是让你迷惑的东西:-)

以下是java命令应该是什么样子的示例:

    java -Xmx100m com.acme.example.ListUsers fred joe bert
Run Code Online (Sandbox Code Playgroud)

以上将导致java命令执行以下操作:

  1. 搜索com.acme.example.ListUsers该类的编译版本.
  2. 加载课程.
  3. 检查该类是否main具有签名,返回类型修饰符给出的方法public static void main(String[]).(注意,方法参数的名称不是签名的一部分.)
  4. 调用该方法将命令行参数("fred","joe","bert")作为一个传递给它String[].

Java无法找到类的原因

当您收到消息"无法找到或加载主类..."时,这意味着第一步失败.该java命令无法找到该类.事实上,在"..."的消息将是完全合格的类名java所期待的.

那么为什么它无法找到班级呢?

原因#1 - 你使用classname参数犯了一个错误

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

原因#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
Run Code Online (Sandbox Code Playgroud)

如果你在类路径上放了"/ 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/,

然后:

Caused by: java.lang.NoClassDefFoundError: <path> (wrong name: <name>)
Run Code Online (Sandbox Code Playgroud)

笔记:

  • 在大多数Java版本中,该-classpath选项可以缩短为-cp.检查相应的手册条目java,javac依此类推.
  • 在类路径中选择绝对路径名和相对路径名时要仔细考虑.请记住,如果当前目录发生更改,相对路径名可能会"中断".

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

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

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

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

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

还是找不到问题?

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

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


java -jar <jar file>语法

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

# 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
Run Code Online (Sandbox Code Playgroud)

例如

  java [ <option> ... ] -jar <jar-file-name> [<argument> ...]
Run Code Online (Sandbox Code Playgroud)

在这种情况下,入口点类(即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.


其他参考文献

  • 当我尝试使用第三方库运行类时,我遇到了这个问题.我像这样调用java:`java -cp ../third-party-library.jar com.my.package.MyClass`; 这不起作用,相反,有必要将本地文件夹添加到类路径中(由`:`分隔,如下所示:`java -cp ../third-party-library.jar:.com.my. package.MyClass`,然后它应该工作 (41认同)
  • 经过多年的java编程,我仍然设法在这个页面上结束.对我来说,问题是[类路径语法依赖于操作系统](http://stackoverflow.com/a/4528456/645270).我对Windows上的编程很陌生并且不知道. (20认同)
  • 附加说明,第2点救了我!很遗憾看到`java`没有说它没有找到导入的类,而是你正在尝试运行的主类.这是误导,虽然我确信这是有原因的.我遇到过`java`确切知道我的类在哪里的情况,但它无法找到导入的类之一.而不是说,它抱怨没有找到我的主要课程.真的,是的. (5认同)

pan*_*oet 229

如果您的源代码名称是HelloWorld.java,那么您的编译代码将是HelloWorld.class.

如果您使用以下方法调用它,您将收到该错误:

java HelloWorld.class
Run Code Online (Sandbox Code Playgroud)

相反,使用这个:

java HelloWorld
Run Code Online (Sandbox Code Playgroud)

  • 我需要做`java -classpath.HelloWorld` (12认同)
  • 问题是此解决方案仅适用于在默认包中声明且没有JAR文件依赖性的Java类.(即使这样,也不是所有的时间.)大多数Java程序并不那么简单. (3认同)
  • @ChrisPrince - 是的......有时有效。要了解它何时有效以及何时无效,请阅读投票最高的答案。 (3认同)
  • 就像斯蒂芬说的那样,这只适用于“默认包”——这意味着文件顶部的 *no* 包声明。为了快速测试一些代码,我做了:`javac TestCode.java` 后跟 `java TestCode` (2认同)

tha*_*ane 130

如果您的类在包中,那么您必须到cd主目录并使用类的全名运行(packageName.MainClassName).

例:

我的课程在这里:

D:\project\com\cse\
Run Code Online (Sandbox Code Playgroud)

我的主要课程的全名是:

com.cse.Main
Run Code Online (Sandbox Code Playgroud)

所以我cd回到主目录:

D:\project
Run Code Online (Sandbox Code Playgroud)

然后发出java命令:

java com.cse.Main
Run Code Online (Sandbox Code Playgroud)

  • 这个答案做了大量的假设。还有其他方法可以实现这一目标。我建议人们不要盲目地遵循上述建议,而是建议人们花时间阅读我的答案中解释 Java 类路径如何工作的链接。最好理解你在做什么...... (2认同)
  • 这个答案做出了我所需要的确切假设:)我位于.class文件的目录中,而java.exe无法正常工作。一旦我在上面cd-ed并运行了命令行中包含的程序包名称,它就会起作用。 (2认同)
  • 我同意尼克·康斯坦丁的观点。同样在这里。这是一个遵循我所做步骤的精确示例,它也对我有用。java 类路径处理有一定的逻辑,但我肯定不会那样设计。 (2认同)

M-R*_*avi 59

如果您的main方法位于包下的类中,则应该在层次结构目录上运行它.

假设有一个源代码文件(Main.java):

package com.test;

public class Main {

    public static void main(String[] args) {
        System.out.println("salam 2nya\n");
    }
}
Run Code Online (Sandbox Code Playgroud)

要运行此代码,您应该放在package类似目录的包中packageName.MainClassName.并在根目录中使用Main.Class.

  • @StephenC是的,你的答案更完整(当然还有+1),但这个特殊的答案里面有"包"这个词,这让我能够快速找到我需要的东西.它奏效了.所以+1 Razavi.StephenC,你的缺乏我需要的简单包示例,因为我是Java的新手. (13认同)
  • 这正是我的问题.我一直在浏览大量的Java文档,这个具体的例子就是我所需要的 (5认同)

Ena*_*san 44

当相同的代码在一台PC上工作,但它在另一台PC上显示错误时,我发现的最佳解决方案是编译如下:

javac HelloWorld.java
java -cp . HelloWorld
Run Code Online (Sandbox Code Playgroud)

  • 这不是一个好的建议。您取决于未设置CLASSPATH环境变量,或者其值与“。”一致。是的,它在很多情况下都有效,但在其他情况下则无效。 (2认同)
  • 如果您将“ com.some.address软件包”作为第一行-这将无法工作。您将需要注释掉“包裹地址”。 (2认同)

Cel*_*bes 34

帮助我的是在命令行上指定类路径,例如:

  1. 新建一个文件夹, C:\temp

  2. 创建文件Temp.java C:\temp,其中包含以下类:

    public class Temp {
        public static void main(String args[]) {
            System.out.println(args[0]);
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  3. 在文件夹中打开命令行C:\temp,并编写以下命令以编译Temp类:

    javac Temp.java
    
    Run Code Online (Sandbox Code Playgroud)
  4. 运行已编译的Java类,添加-classpath选项让JRE知道在哪里找到类:

    java -classpath C:\temp Temp Hello!
    
    Run Code Online (Sandbox Code Playgroud)

  • 在Ubuntu中,我还必须指定路径.不明白为什么默认情况下它不能使用当前工作目录.我确信Java是由键盘制造商赞助的! (3认同)

Xia*_*com 25

根据错误消息("找不到或加载主类"),有两类问题:

  1. 无法找到主要班级
  2. 无法加载主类(此案例未在接受的答案中详细讨论)

主类不能被发现时有错字或错误的语法完全限定类名,或者没有在所提供的类路径中存在.

无法启动类,无法加载主类,通常主类扩展另一个类,并且该类在提供的类路径中不存在.

例如:

public class YourMain extends org.apache.camel.spring.Main
Run Code Online (Sandbox Code Playgroud)

如果未包含camel-spring,则会报告此错误.

  • 这些信息至关重要,值得一提(这是提到`扩展'的唯一答案).我刚学会了很难的方法,当主类无法*加载*因为它扩展了另一个无法找到*时,java**不会报告找不到哪个实际类**(与`NoClassDefFoundError`不同).所以是的,它确实发生了,当你不知道这一点时,这是一个令人毛骨悚然的情况. (5认同)
  • 我会将其修改为“您需要包含启动主类所需的所有类以避免此特定错误”。我不是要说服你。这只是我想看到的一种方式。我把答案留在这里只是给那些可能喜欢以这种方式阅读的人。让我们不要进一步扩展这个讨论 :) 我将我的陈述改为“在接受的答案中没有充分讨论”,希望你感觉好些。 (2认同)

Yam*_*1sp 16

在这种情况下我遇到了这样的错误:

java -cp lib.jar com.mypackage.Main
Run Code Online (Sandbox Code Playgroud)

它适用;于Windows和:Unix:

java -cp lib.jar; com.mypackage.Main
Run Code Online (Sandbox Code Playgroud)


Edu*_*nis 15

有时可能导致问题的原因与主要课程无关,我必须以艰难的方式找到它.它是我移动的引用库,它给了我:

无法找到或加载主类xxx Linux

我刚刚删除了该引用,再次添加它,它再次正常工作.


sha*_*ILU 15

使用此命令:

java -cp . [PACKAGE.]CLASSNAME
Run Code Online (Sandbox Code Playgroud)

示例:如果您的类名是从Hello.java创建的Hello.class,则使用以下命令:

java -cp . Hello
Run Code Online (Sandbox Code Playgroud)

如果你的文件Hello.java在包com.demo中,那么使用下面的命令

java -cp . com.demo.Hello
Run Code Online (Sandbox Code Playgroud)

对于JDK 8,很多时候,类文件出现在同一个文件夹中,但java命令需要classpath,因此我们添加-cp .以当前文件夹作为classpath的引用.

  • 当我尝试从命令行运行简单程序时,这对我有用 (2认同)

jan*_*pol 14

试试-Xdiag.

史蒂夫C的答案很好地涵盖了可能的情况,但有时确定无法找到加载类可能不那么容易.使用java -Xdiag(自JDK 7起).这会打印出一个很好的堆栈跟踪,它提供了消息Could not find or load main class消息含义的提示.

例如,它可以指向主类使用的其他类,这些类无法找到并阻止加载主类.


Nat*_*ams 9

在这种情况下,你有:

无法找到或加载主类?classpath

这是因为您使用的是"-classpath",但破折号java与命令提示符下使用的破折号不同.我有这个问题从记事本复制和粘贴到cmd.

  • 哇!这是一个完全奇怪的原因!(但它适合使用记事本而不是真正的文本编辑器:-)) (2认同)

Omi*_*bbi 9

我遇到了同样的问题,最后发现了我的错误:)我使用了此命令进行编译,并且可以正常工作:

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
Run Code Online (Sandbox Code Playgroud)

但是此命令对我不起作用(我找不到或加载主类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
Run Code Online (Sandbox Code Playgroud)

最后,我只是在类路径的末尾添加了':'字符,问题得以解决:

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
Run Code Online (Sandbox Code Playgroud)


Kaw*_*iKx 7

在我的情况下,出现错误是因为我提供了源文件名而不是类名.

我们需要向解释器提供包含main方法的类名.


mat*_*ens 6

我花了相当多的时间试图解决这个问题.我以为我是以某种方式错误地设置我的类路径,但问题是我键入:

java -cp C:/java/MyClasses C:/java/MyClasses/utilities/myapp/Cool  
Run Code Online (Sandbox Code Playgroud)

代替:

java -cp C:/java/MyClasses utilities/myapp/Cool   
Run Code Online (Sandbox Code Playgroud)

我认为完全限定的含义意味着包括完整的路径名而不是完整的包名.

  • 这些都不正确.该类必须以`utilities.myapp.Cool`或其包名称的形式给出,如果有的话. (2认同)

blu*_*sky 6

这里的所有答案似乎都是针对Windows用户的。对于Mac,classpath分隔符是:,不是;。由于设置类路径使用时;未抛出错误,因此如果从Windows到Mac,则很难发现。

这是相应的Mac命令:

java -classpath ".:./lib/*" com.test.MyClass
Run Code Online (Sandbox Code Playgroud)

在此示例中,程序包所在的位置com.test以及lib类路径中还将包含一个文件夹。

  • 在Linux上和在Mac上一样。 (2认同)

dev*_*747 6

在此输入图像描述

类文件位置: C:\ test\com\company

文件名: Main.class

完全限定的类名: com.company.Main

命令行命令:

java  -classpath "C:\test" com.company.Main
Run Code Online (Sandbox Code Playgroud)

请注意,类路径不包含\ com\company


Che*_*izz 6

java当使用 Windows PowerShell 中公布的选项运行时,-cp您可能会收到类似以下内容的错误:

The term `ClassName` is not recognized as the name of a cmdlet, function, script ...
Run Code Online (Sandbox Code Playgroud)

为了让 PowerShell 接受该命令,-cp选项的参数必须包含在引号中,如下所示:

java -cp 'someDependency.jar;.' ClassName
Run Code Online (Sandbox Code Playgroud)

以这种方式形成命令应该允许 Java 正确处理类路径参数。


Ram*_*eek 6

如果您的情况与我的情况特别相似,这可能对您有所帮助:作为初学者,当我尝试运行Java程序时,我也遇到了这个问题.

我编译它像这样:

javac HelloWorld.java
Run Code Online (Sandbox Code Playgroud)

我也尝试使用相同的扩展名运行:

java Helloworld.java
Run Code Online (Sandbox Code Playgroud)

当我删除.java并重写命令时java HelloWorld,程序运行完美.:)

  • 这是因为您正在执行.java的编译版本。它实际上正在执行.class文件 (2认同)

小智 5

首先使用此命令设置路径;

set path="paste the set path address"
Run Code Online (Sandbox Code Playgroud)

然后,您需要加载程序。在存储的驱动器中键入“ cd(文件夹名称)”并进行编译。例如,如果我的程序存储在D驱动器上,则键入“ D:”,然后按Enter键并键入“ cd(文件夹名称)”。

  • 这无济于事。这个问题是关于Java程序的,而不是普通的可执行文件。Java不会使用PATH来定位任何内容,如果“ cd”有帮助,那么它是靠运气而不是凭判断。 (4认同)
  • @GKFX-这就是我的意思。除非您知道使用的是默认的类路径(或带有“。”的类路径),否则“ cd”将无效。与运气(即猜测/希望“。”位于类路径上)相比,此解决方案的工作要多于判断(即检查“。”位于类路径上)。此外,您对默认值不正确。Java使用“。” 默认情况下为类路径,而不默认为类路径的一部分。 (2认同)

Nen*_*vic 5

在 Windows 上.;,将 CLASSPATH 值放在开头。

这 。(点)的意思是“在当前目录中查找”。这是一个永久的解决方案。

您也可以使用 set 将其设置为“一次” CLASSPATH=%CLASSPATH%;.。只要您的 cmd 窗口打开,这就会持续。


Gui*_*ter 5

这是一个特定的案例,但由于我来到此页面寻找解决方案并没有找到,我将其添加到此处。

Windows(用 7 测试)不接受á类和包名称中的特殊字符(如)。不过,Linux 确实如此。

当我.jar在 NetBeans 中构建一个并尝试在命令行中运行它时,我发现了这一点。它在 NetBeans 中运行,但不在命令行中运行。


syn*_*gma 5

解决我的问题的原因是:

右键单击要运行的项目/类,然后单击Run As-> Run Configurations。然后,您应该修复现有配置或通过以下方式添加新配置:

打开Classpath选项卡,单击Advanced...按钮,然后添加项目的bin文件夹


Jun*_*Liu 5

如果您使用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>
Run Code Online (Sandbox Code Playgroud)


khi*_*nil 5

我在测试 Java MongoDB JDBC 连接时也遇到了类似的错误。我认为简短地总结我的最终解决方案是很好的,以便将来任何人都可以直接查看这两个命令,并有利于进一步进行。

假设您位于 Java 文件和外部依赖项(JAR 文件)所在的目录中。

编译:

javac -cp mongo-java-driver-3.4.1.jar JavaMongoDBConnection.java
Run Code Online (Sandbox Code Playgroud)
  • -cp - 类路径参数;将所有依赖的JAR文件一一传递
  • *.java - 这是具有 main 方法的 Java 类文件。SDSD

跑步:

java -cp mongo-java-driver-3.4.1.jar: JavaMongoDBConnection
Run Code Online (Sandbox Code Playgroud)
  • 所有依赖 JAR 文件结束后,请务必遵守冒号 (Unix)/逗号 (Windows)
  • 最后,观察没有任何扩展名的主类名称(没有 .class 或 .java)


归档时间:

查看次数:

2520525 次

最近记录:

5 年,11 月 前