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

新的Java开发者经常遇到的问题是,他们的程序无法运行,并出现错误信息。 无法找到或加载主类..."。

这是什么意思,什么原因造成的,你应该如何解决?

解决办法

java命令语法

首先,你需要了解使用java(或javaw)命令启动程序的正确方法。 正常的语法1 是这样的。

    java [  ... ]  [ ...]

其中是一个命令行选项(以"-"字符开头),是一个完全合格的Java类名,``是一个任意的命令行参数,被传递给你的应用程序。
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正在寻找的*完全合格的类名。 那么,为什么会找不到这个类呢?
    原因一--你在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大量的参数 原因#2--应用程序的classpath被错误地指定了

    第二个可能的原因是,类名是正确的,但java命令找不到这个类。 要理解这一点,你需要理解"classpath"的概念。 这一点在Oracle文档中得到了*好的解释。

  • java命令文档

  • 设置Classpath]2

  • Java 教程 - PATH 和 CLASSPATH。 所以......如果你已经正确指定了类名,接下来要检查的是你是否正确指定了classpath。 1.阅读上面链接的三个文档。 (是的...。阅读它们。 一个Java程序员至少要了解Java classpath机制的基本原理,这一点很重要)。 1.看看命令行和/或CLASSPATH环境变量,它在你运行java命令时是有效的。 检查目录名和JAR文件名是否正确。 1.如果classpath中存在相对的路径名,检查它们是否能正确解析......从运行java命令时有效的当前目录。 1.检查(在错误信息中提到的)类是否可以在有效的classpath中找到。 1.请注意,Windows与Linux和Mac OS的classpath语法是不同的。(Windows的classpath分隔符是;,其他的是:。 如果你在你的平台上使用了错误的分隔符,你将不会得到一个明确的错误信息。 相反,你会在路径上得到一个不存在的文件或目录,它将被默默地忽略)。 原因#2a--错误的目录在classpath上

    当你把一个目录放在classpath上时,它在概念上对应于限定名称空间的根。 类位于该根下面的目录结构中,通过将完全合格的名称映射为路径名。 例如,如果"/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"放在classpath上,那么JVM就无法找到这个类。 原因#2b--子目录的路径与FQN不匹配

如果你的类的FQN是com.acme.example.Foon,那么JVM就会在"com/acme/example"目录下寻找"Foon.class"。

  • 如果你的目录结构与上述模式中的包命名不一致,JVM就不会找到你的类。
  • 如果你试图通过移动类来重命名*,也会失败......但异常的堆栈跟踪会有所不同。 它有可能是这样说的。 Caused by: java.lang.NoClassDefFoundError: <path>(错误的名称:)。 因为类文件中的FQN与类加载器期望找到的东西不一致。 举个具体的例子,假设。
  • 你想运行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等各自的手册条目。

  • 当在classpaths中选择绝对路径名和相对路径名时要仔细考虑。 记住,如果当前目录改变,相对路径名可能会中断。
    原因#2c--classpath中缺少依赖项

    classpath需要包括所有你的应用程序所依赖的其他(非系统)类。 (系统类是自动定位的,你很少需要关心这个问题)。 为了使主类能够正确加载,JVM需要找到。

  • 该类本身。

  • 超类层次结构中的所有类和接口(例如,见https://stackoverflow.com/questions/42880748)。

  • 所有通过变量或变量声明,或方法调用或字段访问表达式来引用的类和接口。 (注意:JLS和JVM规范允许JVM在一定范围内加载类"懒惰",这可能会影响类加载器异常的抛出。) 原因之三--类被声明在错误的包中

    偶尔会发生这样的情况:有人把一个源代码文件放到了 在他们的源代码树中放错了文件夹,或者他们漏掉了 "包 "的声明。 如果你在IDE中这样做,IDE的编译器会立即告诉你这一点。 同样地,如果你使用一个像样的Java构建工具,该工具将以检测问题的方式运行javac。 然而,如果你用手来构建你的Java代码,你可以用这样的方式,让编译器没有注意到这个问题,而产生的".class"文件不在你期望的地方。 还是找不到问题吗?

    有很多东西需要检查,而且很容易错过一些东西。 试着在 "java "命令行中添加 "Xdiag "选项(作为 "java "后面的第一项)。 它将输出关于类加载的各种信息,这可能为你提供真正问题的线索。 另外,考虑从网站、文档等处复制和粘贴不可见或非ASCII字符可能引起的问题。 还要考虑 "同音字",即两个字母或符号看起来一样......但其实不一样。

    java -jar 语法

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

  java [  ... ] -jar  [ ...]

例如

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

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

集成开发环境

一个典型的Java IDE支持在IDE JVM本身或子JVM中运行Java应用程序。 这些通常不受这种特殊情况的影响,因为IDE使用自己的机制来构建运行时classpath,识别主类并创建java命令行。 但是,如果你在 IDE 背后做一些事情,仍然有可能发生这种异常。 例如,如果你以前在Eclipse中为你的Java应用程序设置了一个应用程序启动器,然后你把包含"main"类的JAR文件移到了文件系统中的另一个地方,但没有告诉Eclipse*,Eclipse就会在不知不觉中以不正确的classpath启动JVM。 简而言之,如果你在IDE中遇到这个问题,请检查一下IDE状态是否过期、项目引用是否有问题、启动器配置是否有问题。 集成开发环境也有可能只是出现了混乱。 集成开发环境是非常复杂的软件,包括许多相互作用的部分。 其中许多部分采用了各种缓存策略,以使IDE作为一个整体做出反应。 这些策略有时会出错,一个可能的症状是启动应用程序时出现问题。 如果你怀疑这种情况可能发生,值得尝试一下,比如重新启动你的IDE和重建该项目。

其他参考资料

评论(11)

有时,可能导致问题的原因与主类无关,我不得不通过艰难的方式来发现这一点。我移动了一个被引用的库,它给了我。

无法找到或加载主类 xxx Linux

我只是删除了那个引用,又把它加了进去,结果又能正常工作了。

评论(5)

首先用这个命令设置路径。

set path="paste the set path address"

然后你需要加载该程序。输入"cd(文件夹名称)"在存储的驱动器中,然后编译它。例如,如果我的程序存储在D盘,输入"D:" 按回车键,然后输入"cd (文件夹名称)"。

评论(3)