java“找不到或加载不到主类”是什么意思?

3bygqnnd  于 2021-08-20  发布在  Java
关注(0)|答案(1)|浏览(460)

新java开发人员遇到的一个常见问题是,他们的程序无法运行,并显示错误消息: Could not find or load main class ... 这意味着什么,是什么导致它,你应该如何修复它?

nimxete2

nimxete21#

java命令语法

首先,您需要了解使用 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 班级。
加载该类。
检查该类是否具有 main 方法,其签名、返回类型和修饰符由 public static void main(String[]) . (注意,方法参数的名称不是签名的一部分。)
调用该方法,并将命令行参数(“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 11或更高版本除外;(见下文)

java ListUser.java

示例#6-您完全忘记了类名

java lots of arguments

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

第二个可能的原因是类名是正确的,但是 java 命令找不到该类。要理解这一点,您需要理解“类路径”的概念。oracle文档很好地解释了这一点:
这个 java 命令文档
设置类路径。
java教程-路径和类路径
所以如果正确指定了类名,那么接下来要检查的是是否正确指定了类路径:
阅读上面链接的三个文档(对读它们!java程序员至少要了解java类路径机制的基本工作原理,这一点很重要。)
查看命令行和/或运行时生效的classpath环境变量 java 指挥部。检查目录名和jar文件名是否正确。
如果类路径中有相对路径名,请检查它们是否正确解析。。。从运行时有效的当前目录 java 指挥部。
检查类(错误消息中提到的)是否可以位于有效的类路径上。
请注意,windows与linux和mac os的类路径语法不同(类路径分隔符是 ; 在windows和 : 在其他人身上。如果您的平台使用了错误的分隔符,您将不会收到明确的错误消息。相反,您将在路径上获得一个不存在的文件或目录,该文件或目录将被静默忽略。)

原因#2a-类路径上的目录错误

当您将目录放在类路径上时,它在概念上对应于限定名称空间的根。通过将完全限定名Map到路径名,类位于该根目录下的目录结构中。例如,如果“/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将找不到您的类。
如果您试图通过移动类来重命名它,那么也将失败。。。但异常stacktrace将有所不同。它可能会这样说:

Caused by: java.lang.NoClassDefFoundError: <path> (wrong name: <name>)

因为类文件中的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

笔记:
这个 -classpath 选项可以缩短为 -cp 在大多数java版本中。检查相应的手动输入是否存在错误 java , javac 等等
在类路径中选择绝对路径名和相对路径名时,请仔细考虑。请记住,如果当前目录发生更改,相对路径名可能会“中断”。

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

类路径需要包括应用程序所依赖的所有其他(非系统)类(系统类是自动定位的,您很少需要关注这一点。)要正确加载主类,jvm需要找到:
班级本身。
超类层次结构中的所有类和接口(例如,参见类路径中存在java类,但启动失败,错误为:找不到或加载主类)
通过变量或变量声明、方法调用或字段访问表达式引用的所有类和接口。
(注意:jls和jvm规范允许jvm“延迟”加载类,这可能会影响引发类装入器异常的时间。)

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

偶尔会有人将源代码文件放入源代码树中的错误文件夹中,或者忽略 package 宣言。如果在ide中执行此操作,ide的编译器将立即告诉您。同样,如果您使用一个像样的java构建工具,该工具将运行 javac 以检测问题的方式。但是,如果您手工构建java代码,则可以这样做:编译器不会注意到问题,并且生成的“.class”文件不在您期望的位置。

还是找不到问题?

有很多东西需要检查,很容易漏掉一些东西。尝试添加 -Xdiag 选择权 java 命令行(作为之后的第一件事 java ). 它将输出关于类加载的各种信息,这可能会为您提供关于真正问题是什么的线索。
此外,考虑复制和粘贴来自网站、文档等的不可见或非ASCII字符可能引起的问题。考虑两个字母或符号看起来相同的“同形异义词”…但事实并非如此。
最后,如果您试图从一个jar文件启动,而该文件中的签名不正确,显然会遇到这个问题 (META-INF/*.SF) 或者如果在 MANIFEST.MF 文件(见https://stackoverflow.com/a/67145190/139985).

java的可选语法

使用 java command .
用于启动“可执行”jar文件的语法如下:

java [ <options> ] -jar <jar-file-name> [<arg> ...]

例如

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

入口点类的名称(即。 com.acme.example.ListUser )类路径在jar文件的清单中指定。
从模块(java 9及更高版本)启动应用程序的语法如下:

java [ <options> ] --module <module>[/<mainclass>] [<arg> ...]

入口点类的名称由 <module> 本身,或由可选 <mainclass> .
从java 11开始,您可以编译和运行单个源代码文件,并使用以下语法运行它:

java [ <options> ] <sourcefile> [<arg> ...]

哪里 <sourcefile> 是(通常)后缀为“.java”的文件。
有关更多详细信息,请参阅 java 用于您正在使用的java版本的命令。

IDE

典型的JavaIDE支持在IDEJVM本身或子jvm中运行java应用程序。由于ide使用自己的机制来构造运行时类路径、标识主类和创建 java 命令行。
但是,如果您在ide后面进行操作,则仍然可能发生此异常。例如,如果您以前在eclipse中为java应用程序设置了应用程序启动器,然后在不告诉eclipse的情况下将包含“main”类的jar文件移动到文件系统中的另一个位置,eclipse将不自觉地以错误的类路径启动jvm。
简言之,如果您在ide中遇到此问题,请检查诸如过时的ide状态、损坏的项目引用或损坏的启动器配置之类的情况。
ide也有可能会感到困惑。ide'

相关问题