新Java开发人员遇到的一个常见问题是,他们的程序无法运行,并显示错误消息:无法找到或加载主类。。。
这意味着什么,是什么导致的,你应该如何解决?
新Java开发人员遇到的一个常见问题是,他们的程序无法运行,并显示错误消息:无法找到或加载主类。。。
这意味着什么,是什么导致的,你应该如何解决?
当前回答
在IDE开发环境中(Eclipse、NetBeans或其他),您必须将项目财产配置为具有主类,以便IDE知道当您单击“Play”时要执行的主类的位置。
右键单击项目,然后单击财产转到跑步类别并选择您的主类别点击Run(运行)按钮。
其他回答
java<类名>命令语法
首先,您需要了解使用java(或javaw)命令启动程序的正确方法。
正常语法1如下:
java [ <options> ] <class-name> [<arg> ...]
其中,<option>是命令行选项(以“-”字符开头),<类名>是完全限定的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方法,该方法具有公共静态void main(String[])提供的签名、返回类型和修饰符。(注意,方法参数的名称不是签名的一部分。)调用该方法,将命令行参数(“fred”、“joe”、“bert”)作为String[]传递给它。
Java找不到类的原因
当您收到消息“找不到或加载主类…”时,这意味着第一步失败了。java命令找不到类。事实上,消息中的“…”将是java正在查找的完全限定类名。
那么,为什么它可能找不到该类?
原因#1-类名参数出错
第一个可能的原因是您可能提供了错误的类名。(或者……正确的类名,但格式错误。)考虑到上面的示例,这里有多种错误的方法来指定类名:
示例#1-一个简单的类名:java列表用户当类在包(如com.acme.example)中声明时,必须在java命令中使用包含包名的完整类名;例如java com.acme.example.ListUser示例#2-文件名或路径名而不是类名:java ListUser.classjava com/acme/example/ListUser.class示例#3-大小写不正确的类名:java com.acme.example.listuser示例#4-拼写错误java com.acme.example.mistuser示例#5-源文件名(Java 11或更高版本除外;见下文)java列表用户.java示例#6-您完全忘记了类名java大量参数
原因#2-应用程序的类路径指定不正确
第二个可能的原因是类名正确,但java命令找不到类。要理解这一点,您需要理解“类路径”的概念。Oracle文档很好地解释了这一点:
java命令文档设置Classpath。Java教程-PATH和CLASSPATH
所以如果正确指定了类名,接下来要检查的是是否正确指定了类路径:
阅读上面链接的三个文档。(是的…阅读它们!重要的是,Java程序员至少要了解Java类路径机制的基本原理。)查看运行java命令时生效的命令行和/或CLASSPATH环境变量。检查目录名和JAR文件名是否正确。如果类路径中存在相对路径名,请检查它们是否正确解析。。。从运行java命令时生效的当前目录。检查该类(在错误消息中提到)是否可以位于有效的类路径上。注意,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
如果在类路径上放置了“/usr/local/acme/classes/com/acme/example”,那么JVM将无法找到该类。
原因#2b-子目录路径与FQN不匹配
如果您的类FQN是com.acme.example.Foon,那么JVM将在目录“com/acme/example”中查找“Foon.class”:
如果您的目录结构与上述模式中的包命名不匹配,JVM将找不到您的类。如果您试图通过移动类来重命名类,那么也会失败。。。但异常堆栈将不同。可以这样说:原因:java.lang.NoClassDefFoundError:<path>(错误名称:<name>)因为类文件中的FQN与类加载器期望找到的不匹配。
举一个具体的例子,假设:
要运行com.acme.example.Foon类,完整文件路径是/usr/local/acme/classes/com/acme/example/Fun.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。检查java、javac等各自的手动条目。在类路径中选择绝对路径名和相对路径名时,请仔细考虑。请记住,如果当前目录发生更改,相对路径名可能会“中断”。
原因#2c-类路径中缺少依赖项
类路径需要包含应用程序依赖的所有其他(非系统)类
课程本身。超类层次结构中的所有类和接口(例如,请参见类路径中存在Java类,但启动失败,出现错误:无法找到或加载主类)通过变量或变量声明、方法调用或字段访问表达式引用的所有类和接口。
(注意:JLS和JVM规范允许JVM“惰性”加载类,这可能会影响抛出类加载器异常的时间。)
原因#3-类在错误的包中声明
偶尔会有人将源代码文件放入源代码树中的错误文件夹,或者忽略了包声明。如果在IDE中执行此操作,IDE的编译器将立即告诉您。类似地,如果您使用一个像样的Java构建工具,该工具将以检测问题的方式运行javac。但是,如果您手动构建Java代码,那么可以这样做,编译器不会注意到问题,并且生成的“.class”文件不在您期望的位置。
还是找不到问题?
有很多事情要检查,很容易漏掉一些东西。尝试将-Xdiag选项添加到java命令行(作为java之后的第一件事)。它将输出关于类加载的各种信息,这可能会为您提供真正问题所在的线索。
此外,考虑从网站、文档等复制和粘贴不可见或非ASCII字符可能导致的问题。并考虑“同字形”,其中两个字母或符号看起来相同。。。但不是。
如果META-INF/*.SF中的签名无效或不正确,您可能会遇到此问题。您可以尝试在您最喜欢的ZIP编辑器中打开.jar,然后从META-INF中删除文件,直到您只有MANIFEST.MF为止。但是,一般情况下不建议这样做。(无效签名可能是有人将恶意软件注入到原始签名的JAR文件中的结果。如果您删除了无效签名,则会将恶意软件感染到您的应用程序!)建议的方法是使用有效签名保存JAR文件,或从(真实的)原始源代码重建它们。
最后,如果MANIFEST.MF文件中有语法错误,显然会遇到这个问题(请参见https://stackoverflow.com/a/67145190/139985).
java的替代语法
使用Java命令启动Java程序有三种可选语法。
用于启动“可执行”JAR文件的语法如下:java〔<options>〕-jar<jar文件名>〔<arg>…〕例如java-Xmx100m-jar/usr/local/acme示例/listuser.jar-fred入口点类的名称(即com.acme.example.ListUser)和类路径在JAR文件的MANIFEST中指定。从模块(Java 9及更高版本)启动应用程序的语法如下:java[<options>]--模块<module>[/<mainclass>][<arg>…]入口点类的名称要么由<module>本身定义,要么由可选的<mainclass>给定。从Java11开始,您可以使用Java命令使用以下语法编译和运行单个源代码文件:java[<options>]<sourcefile>[<arg>…]其中<sourcefile>(通常)是后缀为“.java”的文件。
有关更多详细信息,请参阅您正在使用的java版本的java命令的官方文档。
IDEs
典型的Java IDE支持在IDE JVM本身或子JVM中运行Java应用程序。这些通常不受这种特殊异常的影响,因为IDE使用自己的机制来构造运行时类路径、标识主类和创建java命令行。
但是,如果您在IDE后面执行操作,则仍然可能发生此异常。例如,如果您之前在Eclipse中为Java应用程序设置了Application Launcher,然后在没有通知Eclipse的情况下将包含“main”类的JAR文件移动到文件系统中的其他位置,Eclipse将无意中使用错误的类路径启动JVM。
简而言之,如果您在IDE中遇到此问题,请检查是否存在过时的IDE状态、损坏的项目引用或损坏的启动器配置。
IDE也有可能简单地混淆。IDE是由许多交互部分组成的极其复杂的软件。其中许多部分采用了各种缓存策略,以使IDE作为一个整体具有响应能力。这些有时会出错,一个可能的症状是启动应用程序时出现问题。如果您怀疑这可能会发生,那么值得尝试其他事情,如重新启动IDE、重建项目等等。
其他参考文献
来自Oracle Java教程-常见问题(及其解决方案)
我在做mvn eclipse后遇到了这个错误:eclipse。这有点搞乱了我的.classpath文件。
我不得不将.classpath中的行从
<classpathentry kind="src" path="src/main/java" including="**/*.java"/>
<classpathentry kind="src" path="src/main/resources" excluding="**/*.java"/>
to
<classpathentry kind="src" path="src/main/java" output="target/classes" />
<classpathentry kind="src" path="src/main/resources" excluding="**" output="target/classes" />
如果是Maven项目:
转到POM文件。删除所有依赖项。保存POM文件。再次只导入必要的依赖项。保存POM文件。
这个问题应该消失。
好吧,已经有很多答案了,但没有人提到文件权限可能是罪魁祸首。
运行时,用户可能无法访问JAR文件或路径的某个目录。例如,考虑:
/dir1/dir2/dir3/myjar.Jar中的Jar文件
拥有JAR文件的用户1可以执行以下操作:
# Running as User1
cd /dir1/dir2/dir3/
chmod +r myjar.jar
但它仍然不起作用:
# Running as User2
java -cp "/dir1/dir2/dir3:/dir1/dir2/javalibs" MyProgram
Error: Could not find or load main class MyProgram
这是因为正在运行的用户(User2)无权访问dir1、dir2或javalibs或dir3。当User1可以看到文件并可以访问这些文件时,这可能会让某人发疯,但User2仍然会发生错误。
在测试JavaMongoDB JDBC连接时,我也遇到了类似的错误。我认为简单总结一下我的最终解决方案是很好的,这样将来任何人都可以直接研究这两个命令,并可以继续进行下去。
假设您位于Java文件和外部依赖项(JAR文件)所在的目录中。
编译:
javac -cp mongo-java-driver-3.4.1.jar JavaMongoDBConnection.java
-cp-类路径参数;逐个传递所有从属JAR文件*.java-这是具有main方法的java类文件。标准差分法
Run:
java -cp mongo-java-driver-3.4.1.jar: JavaMongoDBConnection
请在所有依赖JAR文件结束后观察冒号(Unix)/逗号(Windows)最后,观察没有任何扩展名的主类名(没有.class或.java)