【问题标题】:java CLASSPATH not working on command-linejava CLASSPATH 在命令行上不起作用
【发布时间】:2018-01-19 20:19:40
【问题描述】:

系统详情:

Ubuntu 17.10
openjdk version "1.8.0_151"
OpenJDK Runtime Environment (build 1.8.0_151-8u151-b12-0ubuntu0.17.10.2-b12)

我的 java 程序无法运行。我不知道为什么它找不到课程。它使用-classpath 标志编译,但在运行时找不到类。

$ ls -ltra
total 668
-rw-rw-r-- 1 bvpx bvpx 653275 Jan 19 14:45 javax.mail.jar
drwxr-xr-x 3 bvpx bvpx   4096 Jan 19 14:59 ..
-rw-r--r-- 1 bvpx bvpx    960 Jan 19 15:07 Example.java
drwxr-xr-x 2 bvpx bvpx   4096 Jan 19 15:07 .

不使用-classpath 编译不起作用(我以为-classpath 默认为.?)

$ javac Example.java 
Example.java:2: error: package javax.mail does not exist

指定-classpath 有帮助,程序现在编译并生成Example.class

$ javac -classpath javax.mail.jar Example.java
$ 

这里是源代码:

import java.util.*;
import javax.mail.*;
import javax.mail.internet.*;

public class Example {
    static final int PORT = 587;
    /* ... */

    public static void main(String[] args) throws Exception {
        /* ... */
        Transport transport = session.getTransport();
        try
        {
            System.out.println("Sending...");
            transport.connect(HOST, SMTP_USERNAME, SMTP_PASSWORD);
            transport.sendMessage(msg, msg.getAllRecipients());
            System.out.println("Email sent!");
        }
        catch (Exception ex) {
            System.out.println("Error message: " + ex.getMessage());
        }
    }
}

运行程序会产生这个错误:

$ java -Xdiag -classpath javax.mail.jar Example 
Error: Could not find or load main class Example
java.lang.ClassNotFoundException: Example
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:495)

在没有-classpath 的情况下运行java 会导致JNI 找不到javax/mail,即使它在目录中。

$ java -Xdiag Example 
Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.NoClassDefFoundError: javax/mail/Address
    at java.lang.Class.getDeclaredMethods0(Native Method)

为什么java找不到Example类?

【问题讨论】:

    标签: java linux ubuntu classpath javac


    【解决方案1】:

    您似乎在这里遗漏了一些基本概念。

    类路径提供目录和 JAR 文件列表以搜索所需的类。当尝试加载不属于标准库的类foo.bar.MyClass 时,默认类加载器将依次在每个类路径元素中查找它,直到找到该类或用完元素为止。

    但是请注意,它按完全限定名称进行搜索。对于作为目录的类路径条目,这意味着它会查找相对于目录的foo/bar/MyClass.class。对于 JAR 文件的类路径条目,它会查找相对于 JAR 根目录的 foo/bar/MyClass.class。属于未命名的默认包的类有点特殊,或者看起来可能是这样,因为它们的类文件(例如InDefaultPackage.class)应该直接位于指定 JAR 的根目录中或直接位于指定目录中。

    没有-classpath 编译是不行的(我以为-classpath 默认为.?)

    $ javac Example.java 
    Example.java:2: error: package javax.mail does not exist
    

    类路径确实默认为.。这是一个目录的名称,因此当在javax.mail 包中搜索类时,它会查找子目录javax/mail,如果找到,它会检查其中的类文件。请注意,它不会下降到它在目录树中发现的 JAR 文件中。它只在类路径中明确命名的那些 JAR 中查找。

    错误消息告诉您javac 根本没有从javax.mail 包中找到任何类。您可以通过在编译类路径中指定 JAR(就像您最终所做的那样)或通过在当前目录中解压缩 JAR 来解决它。

    指定-classpath 有帮助,程序现在编译并生成 Example.class:

    $ javac -classpath javax.mail.jar Example.java
    $
    

    请注意,编译器会将类文件存储在与其包对应的目录结构中,这正是java 命令将在其中查找它的位置。

    运行程序会产生这个错误:

    $ java -Xdiag -classpath javax.mail.jar Example 
    Error: Could not find or load main class Example
    java.lang.ClassNotFoundException: Example
        at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
        at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:495)
    

    您在回答中澄清说,您通过从 Example.java 中删除 package 语句解决了这个问题。没关系,但它并不能真正解释问题,即java 期望您为其提供类的完全限定名称。如果该类位于命名包中,则包括包名。因此,如果Example.java 包含这个包声明:

    package com.my;
    

    那么您需要指定给java 的类名将是com.my.Example。您只指定了Example,它在默认包中指定了一个名为“Example”的类,您对找不到类问题的解决方案是将您的类移到默认包中。

    还请注意,将 Java 源文件布置在与其包结构相匹配的目录结构中也是常规且有用的。因此,com.my.Example 类的源文件通常位于com/my/Example.java。 Java 编译器将依赖此方案来查找它找不到的类的源代码。

    在没有-classpath 的情况下运行java 会导致JNI 找不到 javax/mail 即使它在目录中。

    $ java -Xdiag Example 
    Error: A JNI error has occurred, please check your installation and try again
    Exception in thread "main" java.lang.NoClassDefFoundError: javax/mail/Address
        at java.lang.Class.getDeclaredMethods0(Native Method)
    

    不,javax/mail/Address 不在目录中。它位于目录中的 JAR 文件中。这根本不是一回事,而且差别很大。

    【讨论】:

      【解决方案2】:

      我必须设置-classpath 以包含当前目录。根据documentationclasspath:分隔。正确的类路径字符串是:

      javax.mail.jar:.
      

      下面是一个工作示例。

      $ javac -classpath javax.mail.jar:. Example.java  
      $ java -classpath javax.mail.jar:. Example 
      Sending...
      Email sent!
      

      另外需要注意的是,在 Example.java 的顶部最初有一个 package 定义。我不得不删除它。

      【讨论】:

      • 那么问题中提供的源代码,不包含package语句,实际上并没有重现java.lang.ClassNotFoundException: Example错误?
      • 源代码中的package 语句与正确的javax.mail.jar:. 类路径的组合仍然会产生java.lang.ClassNotFoundException: Example 错误。通过添加 :. 作为类路径的一部分并删除 package 语句(我在写这个问题之前已经完成)解决了这个错误。
      • 这不是重点,@bvpx。您似乎是在说您在问题中提供的来源不足以重现您询问的某些错误。我完全相信这一点,但我想确认一下。此外,如果确实如此,那么您应该更新问题以提供实际重现问题的来源。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-04
      • 2018-06-21
      相关资源
      最近更新 更多