Java 找不到主类

我写了以下Java源文件():Hello.java

package com;

public class Hello {
    public static void main(String[] args) {
        System.out.println("Hello!");
    }
}

我把它保存到.C:/tmpjava/Hello.java

从命令行,我导航到该目录并运行 。然后我运行:javac Hello.javadir

  • Hello.class
  • Hello.java

然后,从我刚刚运行的同一目录中,我运行并得到:javacjava Hello.class

Exception in thread "main" java.lang.NoClassDefFoundError: Hello/class
Caused by: java.lang.ClassNotFoundException: Hello.class
    at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
Could not find the main class: Hello.class.  Program will exit.

这是怎么回事?!?怎么能跑得很好,但不是?javacjava


答案 1

您的类属于包 。因此,类的完全限定名是 。在命令行上使用 java 调用程序时,应提供包含方法的类的完全限定类名,并省略.class,如下所示:Hellocomcom.Hellomain

java com.Hello

java 程序需要此完全限定的类名来了解您所引用的类。

但你还有另一个问题。java 程序使用文件系统定位包、子包和属于它们的类。因此,如果你有一个像 这样的包结构,java程序期望在名为 com 的目录中找到一个名为 Hello.class 的类文件,如下所示:com/Hello.class。事实上,您可以在您看到的中观察到这种行为;您错误地使用了 Hello.class,Java 将其解释为名为 的和名为 的,并且正在寻找目录结构 Hello/classcom.HelloExceptionHelloclass

java.lang.NoClassDefFoundError: Hello/class

但是编译器javac默认情况下不会设置此目录结构。请参阅javac的文档,但重要的是:当您进行编译时,您可以使用标志指定目标目录:-d

-d 目录

设置类文件的目标目录。目标目录必须已经存在;javac 不会创建目标目录。如果类是包的一部分,javac 会将类文件放在反映包名称的子目录中,并根据需要创建目录。例如,如果指定 -d c:\myclasses 并且该类称为 com.mypackage.MyClass,则该类文件称为 c:\myclasses\com\mypackage\MyClass.class。

如果未指定 -d,javac 会将类文件放在与源文件相同的目录中。

粗体的最后一点是初学者感到困惑的根源,也是你自己问题的一部分。

所以你有两个选择:

  1. 在你的例子中,如果你提供当前目录作为目标目录是可以的,就像这样(句点意味着当前目录):.

    javac -d . Hello.java
    

    如果你像这样调用编译器,它将为你创建com目录,并将编译好的类文件放在其中,就像java程序期望找到它一样。然后,当您从c:\tmpJava运行上述Java时,您的程序应该执行。

  2. 您可以使用镜像包结构的目录结构来设置源代码:将源文件 Hello.java 放在名为 com 的目录中,在本例中为:c:\tmpJava\com\Hello.java。现在,从c:\tmpJava开始,你可以像这样运行你的javac编译:

    javac com\Hello.java
    

    您尚未提供标志,但没关系,因为您自己创建了目录结构,并再次引用了上面的文档:-d

    如果未指定 -d,javac 会将类文件放在与源文件相同的目录中。

    同样,当您如上所述运行java时,您的程序应该执行。

    请注意,第二种选择是Java程序员通常采用的一种:源代码文件以镜像包结构的目录结构进行组织。

在此解释中,我们忽略了类路径的概念。编写 java 程序时,您还需要了解这一点,但是在您只是在当前目录中编译程序的情况下 - 如果您在编译类时遵循上述两种选择之一 - 则可以在不设置类路径的情况下离开,因为默认情况下,java 程序将当前目录作为类路径。另一句话,来自java的文档

-cp 类路径

指定目录、JAR 存档和 ZIP 存档的列表以搜索类文件。类路径条目由分号 (;) 分隔。指定 -classpath 或 -cp 将覆盖 CLASSPATH 环境变量的任何设置。

如果未使用 -classpath 和 -cp 并且未设置 CLASSPATH,则用户类路径由当前目录 (.) 组成。

请注意,当您使用 Eclipse 等 IDE 来运行 Java 代码时,这主要是为您处理的,但您仍然会遇到类路径问题。


答案 2

Java 命令的语法为:

java [classname]

java [filename]

Java 在其类路径中查找您提供的名称的类。通常类路径包括当前目录,因此:

java Hello

...将在当前目录中找到 Hello.class,并运行其 main() 方法。

但是,如果该类位于其他位置(如在.jar中,或文件系统中的其他位置),则可以使用 CLASSPATH 环境变量或在命令行上指定它:

java -cp build/classes Hello
java -cp build/jars/myjar.jar Hello

推荐