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

新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 

(令人困惑的)看起来像一个文件path名,但不是一个。 请注意,术语完全限定的名称是标准的Java术语…不是我刚刚弄混淆你的:-)

下面是一个java命令的例子:

  java -Xmx100m com.acme.example.ListUsers fred joe bert 

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

  1. searchcom.acme.example.ListUsers类的编译版本。
  2. 加载类。
  3. 检查该类是否具有带有签名返回types和由public static void main(String[])给出的修饰符main方法。 (请注意,方法参数的名称不是签名的一部分。)
  4. 调用该方法将命令行参数(“fred”,“joe”,“bert”)作为String[]传递给它。

Java找不到类的原因

当您收到消息“无法find或加载主类…”时,表示第一步失败。 java命令无法find类。 事实上,消息中的“…”将是java正在寻找的完全合格的类名称

那为什么不能find这个class呢?

原因#1 – 你在classname参数上犯了一个错误

第一个可能的原因是你可能提供了错误的类名。 (或者…正确的类名称,但forms错误)考虑上面的例子,这里有很多错误的方法来指定类名:

  • 例#1 – 一个简单的类名:

     java ListUser 

    当类在com.acme.example等包中声明时,则必须在java命令中使用包括包名的完整类名; 例如

     java com.acme.example.ListUser 
  • 示例#2 – 文件名或path名而不是类名:

     java ListUser.class java com/acme/example/ListUser.class 
  • 示例#3 – 一个类名称与shell不正确:

     java com.acme.example.listuser 
  • 示例#4 – 一个错字

     java com.acme.example.mistuser 
  • 例5#源文件名

     java ListUser.java 
  • 例#6 – 你完全忘记了课程名称

     java lots of arguments 

原因#2 – 应用程序的类path被错误地指定

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

  • java命令文档
  • 设置类path 。
  • Java教程 – PATH和CLASSPATH

所以…如果您正确指定了类名,那么接下来要检查的是您已经正确指定了类path:

  1. 阅读上面链接的三个文件。 (是…阅读它们,重要的是Java程序员至less要了解Java类path机制的基本原理。)
  2. 查看运行java命令时有效的命令行和/或CLASSPATH环境variables。 检查目录名称和JAR文件名是否正确。
  3. 如果在类path中存在相对path名,请检查它们是否正确parsing…从运行java命令时有效的当前目录中。
  4. 检查该类(错误消息中提到的)是否可以位于有效的类path中。
  5. 请注意,Windows与Linux和Mac OS的classpath语法不同

原因#2a – 错误的目录位于类path中

在类path中放置一个目录时,它在概念上与合格名称空间的根对应。 通过将完全限定名称映射到path名 ,类位于根目录下的目录结构中。 因此,例如,如果类path中有“/ usr / local / acme / classes”,那么当JVM查找名为com.acme.example.Foon的类时,将使用此类查找“.class”文件path:

  /usr/local/acme/classes/com/acme/example/Foon.class 

如果在类path中放置了“/ usr / local / acme / classes / com / acme / example”,则JVM将无法find该类。

原因#2b – 子目录path与FQN不匹配

如果您的类FQN是com.acme.example.Foon ,那么JVM将在“com / acme / example”目录中查找“Foon.class”:

  • 如果您的目录结构与上面的模式不匹配,则JVM将找不到您的类。

  • 如果您尝试通过移动它来重命名类,那么也会失败…但是exception堆栈跟踪将会不同。

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

  • 你想运行com.acme.example.Foon类,
  • 完整的文件path是/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等各自的手册条目。
  • 在类path中select绝对path名和相对path名时请仔细考虑。 请记住,如果当前目录更改,相对path名可能会“中断”。

原因#2c – 类path中缺less依赖关系

类path需要包含应用程序依赖的所有其他 (非系统)类。 (系统类自动定位,你很less需要关心这个。)为了正确加载主类,JVM需要find:

  • class级本身。
  • 超类层次结构中的所有类和接口(例如,请参阅Java类存在于类path中,但启动失败,错误:无法find或加载主类 )
  • 所有通过variables或variables声明或方法调用或字段访问expression式引用的类和接口。

(注意:JLS和JVM规范允许JVM在一定范围内“懒惰地”加载类,这会影响类加载器exception的发生。)

理由#3 – 该类已被声明在错误的包中

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

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 )和类path在JAR文件的MANIFEST中指定。

集成开发环境

典型的Java IDE支持在IDE JVM本身或子JVM中运行Java应用程序。 这些通常不受此特定exception的影响,因为IDE使用自己的机制来构build运行时类path,确定主类并创buildjava命令行。

但是,如果您在IDE后面执行操作,则仍然有可能发生此exception。 例如,如果您以前在Eclipse中为您的Java应用程序设置了应用程序启动器,然后您将包含“main”类的JAR文件移动到文件系统中的其他位置而不告知Eclipse ,则Eclipse将无意中启动JVM与一个不正确的类path。

简而言之,如果在IDE中遇到这个问题,请检查IDE状态过期,项目引用损坏或启动器configuration损坏等情况。

IDE也可能会让人感到困惑。 IDE是非常复杂的软件,由许多相互作用的部分组成。 这些部分中的许多部分都采用了各种caching策略,以使IDE整体响应。 这些有时可能会出错,一个可能的症状是启动应用程序时出现的问题。 如果您怀疑可能发生这种情况,则值得重新启动IDE。

其他参考

  • 从Oracle Java教程 – 常见问题(及其解决scheme)

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

如果您使用以下方式调用,将会出现该错误:

 java HelloWorld.class 

相反,使用这个:

 java HelloWorld 

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

例:

我的课程在这里:

 D:\project\com\cse\ 

我的主要类的全名是:

 com.cse.Main 

所以我回到主目录:

 D:\project 

然后发出java命令:

 java com.cse.Main 

如果你的主要方法是在一个包下的类中,你应该在分层目录下运行它。

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

 package com.test; public class Main { public static void main(String[] args) { System.out.println("salam 2nya\n"); } } 

为了运行这个代码,你应该把Main.Class放在类似目录./com/test/Main.Java的包中。 并在根目录下使用java com.test.Main

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

 javac HelloWorld.java java -cp . HelloWorld 

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

  1. 创build一个新的文件夹, C:\temp

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

     public class Temp { public static void main(String args[]) { System.out.println(args[0]); } } 
  3. 打开文件夹C:\temp的命令行,然后编写以下命令来编译Temp类:

     javac Temp.java 
  4. 运行编译的Java类,添加-classpath选项以让JRE知道在哪里find该类:

     java -classpath C:\temp Temp Hello! 

根据错误消息(“无法find或加载主类”),有两类问题:

  1. 主要类无法find
  2. 主类无法加载 (这个案例在接受的答案中没有充分讨论)

如果在全限定类名 中存在 拼写错误或错误的语法,或者在提供的类path中不存在主类,则无法find主类。

类不能被启动时 ,主类不能被加载 ,通常主类扩展另一个类,并且该类在提供的类path中不存在。

例如:

 public class YourMain extends org.apache.camel.spring.Main 

如果不包括骆驼spring,这个错误将被报告。

有时可能会造成这个问题与主要课程无关,而我必须以艰难的方式来find这个问题。 这是一个引用的图书馆,我感动了,它给了我:

无法find或加载主类xxx Linux

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

在这种情况下,我有这样的错误:

 java -cp lib.jar com.mypackage.Main 

它适用于; 对于Windows和:对于Unix:

 java -cp lib.jar; com.mypackage.Main 

在这种情况下你有:

无法find或加载主类?classpath

这是因为你正在使用“-classpath”,但是在命令提示符下,破折号不是java所使用的破折号。 我有这个问题从记事本复制和粘贴到cmd。

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

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

试试看-Xdiag

Steve C的答案很好地涵盖了可能的情况,但是有时为了确定类是否找不到或者加载起来可能并不那么容易。 使用java -Xdiag (因为jdk 7)。 这打印出一个很好的stacktrace,它提供了什么信息Could not find or load main class消息手段暗示。

例如,它可以指向主类所使用的无法find的其他类,并阻止加载主类。

首先使用这个命令设置path;

 set path="paste the set path address" 

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

在我的情况下解决这个问题的是:

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

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

使用这个命令

 java -cp . [PACKAGE.]CLASSNAME 

例如,如果你的类名是从Hello.java创build的Hello.class,那么使用下面的命令

 java -cp . Hello 

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

 java -cp . com.demo.Hello 

使用jdk 8很多时候,类文件存在于同一个文件夹中,但是java命令期望classpath,为此我们添加-cp . 以当前文件夹作为classpath的参考。

你真的需要从src文件夹中做到这一点。 在那里你input下面的命令行:

 [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 

有时,在一些你可能已经尝试过的在线编译器中,如果你不写public class [Classname]而只是class [Classname] ,那么你会得到这个错误。

我花了相当长的时间来解决这个问题。 我以为我以某种方式错误地设置我的类path,但问题是,我键入:

java -cp C:/ java / MyClasses C:/ java / MyClasses / utilities / myapp / Cool
代替:
java -cp C:/ java / MyClasses utilities / myapp / Cool
我认为完全合格的含义意味着包括完整的path名称而不是完整的包名称。

这是一个特定的情况,但是因为我来到这个页面寻找一个解决scheme,并没有find它,我会在这里添加它。

Windows(使用7进行testing)不能接受类和包名中的特殊字符(如á )。 不过,Linux确实如此。

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

在Windows上.; 在开始的CLASSPATH值。

的。 (点)表示“查看当前目录”。 这是一个永久的解决scheme。

你也可以设置“一次” CLASSPATH=%CLASSPATH%;. 。 只要您的cmd窗口打开,这将持续。

在这里输入图像描述

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

文件名: Main.class

完全合格的课程名称: com.company.Main

命令行命令:

 java -classpath "C:\test" com.company.Main 

请注意,类path不包含\ com \ company

默认情况下,Java使用. ,“当前工作目录”的geek字母(你现在知道geek字母右边的一个字母)作为默认的CLASSPATH 。 这意味着当你在提示符例如java MyClass键入一个命令时,该命令被解释为你的types是java -cp . MyClass java -cp . MyClass 。 你在-cpMyClass之间看到了那个点吗? ( cp是较长的类path选项的缩写)

这对于大多数情况来说已经足够了,而且事情看起来很好,直到您尝试将某个目录添加到您的CLASSPATH 。 在大多数情况下,当程序员需要这样做时,他们只需运行一个命令,如set CLASSPATH=path\to\some\dir 。 这个命令创build一个名为CLASSPATH的新环境variables,其值path\to\some\dir或者如果之前已经设置了CLASSPATH ,则将其path\to\some\dirreplacepath\to\some\dir

完成后,您现在拥有一个CLASSPATH环境variables,Java不再使用它的默认类path( . ),而是您设置的那个。 So the next day you open your editor, write some java program, cd to the directory where you saved it, compile it, and try to run it with the command java MyClass , and you are greeted with a nice output: Could not find or load main class … (If your commands were working well before and you are now getting this output, then this might be the case for you).

What happens is that when you run the command java MyClass , Java searches for the class file named MyClass in the directory or directories that you have set in your CLASSPATH and not your current working directory so it doesn't find your class file there and hence complains.

What you need to do is add . to your class path again which can be done with the command set CLASSPATH=%CLASSPATH%;. (notice the dot after the semicolon). In plain english this command says "Pick what was initially the value of CLASSPATH ( %CLASSPATH% ), add . to it ( ;. ) and assign the result back to CLASSPATH ".

And viola, you are once again able to use your command java MyClass as usual.

谢谢。

When running the java with the -cp option as advertised in Windows PowerShell you may get an error that looks something like:

 The term `ClassName` is not recognized as the name of a cmdlet, function, script ... 

In order to for PowerShell to accept the command, the arguments of the -cp option must be contained in quotes as in:

 java -cp 'someDependency.jar;.' ClassName 

Forming the command this way should allow Java process the classpath arguments correctly.

This might help you if your case is specifically like mine: as a beginner I also ran into this problem when I tried to run a java program.

I compiled it like this: javac HelloWorld.java

and tried to run also with the same extension

java Helloworld.java

When I removed the .java and rewrote the command like this java HelloWorld , The Program ran perfectly. 🙂

if you use maven to build the jar please making sure to specify the main class in the 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> 

In Java, when you sometimes run the JVM from the command line using the java executable and are trying to start a program from a class file with public static void main (PSVM), you might run into the below error even though the classpath parameter to the JVM is accurate and the class file is present on the classpath:

 Error: main class not found or loaded 

This happens if the class file with PSVM could not be loaded. One possible reason for that is that the class may be implementing an interface or extending another class that is not on the classpath. Normally if a class is not on the classpath, the error thrown indicates as such. But, if the class in use is extended or implemented, java is unable to load the class itself.

Reference: https://www.computingnotes.net/java/error-main-class-not-found-or-loaded/

I got this error after doing mvn eclipse:eclipse This messed up my .classpath file a little bit.

Had to change the lines in .classpath from

 <classpathentry kind="src" path="src/main/java" including="**/*.java"/> <classpathentry kind="src" path="src/main/resources" excluding="**/*.java"/> 

 <classpathentry kind="src" path="src/main/java" output="target/classes" /> <classpathentry kind="src" path="src/main/resources" excluding="**" output="target/classes" /> 

I was unable to solve this problem with the solutions stated here (although the answer stated has, no doubt, cleared my concepts). I faced this problem two times and each time I have tried different solutions (in the Eclipse IDE).

  • Firstly, I have come across with multiple main methods in different classes of my project. So, I had deleted the main method from subsequent classes.
  • Secondly, I tried following solution:
    1. Right click on my main project directory.
    2. Head to source then clean up and stick with the default settings and on Finish. After some background tasks you will be directed to your main project directory.
    3. After that I close my project, reopen it, and boom, I finally solved my problem.

Sometimes it's better to remove the added JAR files and add again with proper build helps. For me it has been a regular issue, and I followed the same approach:

  1. Put all the referred JAR files in a folder, jarAddOns, and copy it in a safe place
  2. Now from Eclipse (or from your IDE) remove the JAR files.
  3. Move the whole project folder from the workspace to a safe location
  4. Restart Eclipse (your IDE)
  5. Now import your project directory from the safe location.
  6. Add the JAR files into your project from the jarAddOns folder (previously saved in safe location)
  7. Project buildpath, add JAR files and apply
  8. Now run the project. It should not show the error.

All answers here are directed towards Windows users it seems. For Mac, the classpath separator is : , not ; 。 As an error setting the classpath using ; is not thrown then this can be a difficult to discover if coming from Windows to Mac.

Here is corresponding Mac command:

 java -classpath ".:./lib/*" com.test.MyClass 

Where in this example the package is com.test and a lib folder is also to be included on classpath.