简体   繁体   English

Java CLASSPATH在命令行上不起作用

[英]java CLASSPATH not working on command-line

System details: 系统细节:

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

I can't get my java program to run. 我无法运行Java程序。 I don't know why it won't find the class. 我不知道为什么找不到班。 It compiles with the -classpath flag, but doesn't find the class when running. 它使用-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 .

Compiling without -classpath does not work (I thought -classpath defaulted to . ?) 不带-classpath编译不起作用(我认为-classpath默认为. ?)

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

Specifying the -classpath helps, the program now compiles and produces Example.class : 指定-classpath帮助,该程序现在编译并生成Example.class

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

Here's the source code: 这是源代码:

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());
        }
    }
}

Running the program produces this error: 运行程序会产生以下错误:

$ 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)

Running java without -classpath causes the JNI to not find javax/mail even though it's in the directory. 在不带-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)

Why can't java find the Example class? Java为什么找不到Example类?

I had to set -classpath to include the current directory. 我必须设置-classpath以包括当前目录。 According to the documentation classpath is delimited by : . 根据文档, classpath:分隔。 The correct classpath string was: 正确的类路径字符串为:

javax.mail.jar:.

Below is a working example. 下面是一个工作示例。

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

Another thing to note was that there was originally a package definition at the top of Example.java. 还要注意的另一件事是,Example.java的顶部最初有一个package定义。 I had to remove it. 我不得不将其删除。

You seem to be missing some fundamental concepts here. 您似乎在这里缺少了一些基本概念。

The classpath gives a list of directories and JAR files to search for needed classes. 类路径提供了目录和JAR文件的列表,以搜索所需的类。 When trying to load a class foo.bar.MyClass that is not part of the standard library, the default classloader will look for it in each classpath element in turn, in order, until it finds the class or runs out of elements. 尝试加载不属于标准库的类foo.bar.MyClass ,默认的类加载器将依次在每个classpath元素中寻找它,直到找到该类或元素用完为止。

Note well, however, that it searches by fully-qualified name. 但是请注意,它按完全限定的名称进行搜索。 For classpath entries that are directories, that means that it looks for foo/bar/MyClass.class relative to the directory. 对于作为目录的类路径条目,这意味着它将查找相对于目录的foo/bar/MyClass.class For classpath entries that are JAR files, it looks for foo/bar/MyClass.class relative to the root of the JAR. 对于作为JAR文件的类路径条目,它将查找相对于JAR根目录的foo/bar/MyClass.class Classes that belong to the unnamed default package are a little special, or so it may seem, because their class files (eg InDefaultPackage.class ) are expected to be located directly in the root of the designated JAR or directly in the specified directory. 属于未命名默认软件包的类似乎有些特殊,因为它们的类文件(例如InDefaultPackage.class )应直接位于指定JAR的根目录中或直接位于指定目录中。

Compiling without -classpath does not work (I thought -classpath defaulted to . ?) 不带-classpath编译不起作用(我认为-classpath默认为. ?)

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

The classpath does default to . classpath 确实默认为. . This is the name of a directory, so when searching it for classes in, say, the javax.mail package, it looks for a subdirectory javax/mail , and if that is found, it examines the class files within. 这是目录的名称,因此当在javax.mail软件包中搜索类时,它会查找子目录javax/mail ,如果找到了子目录,它将检查其中的类文件。 Note that it does not descend into JAR files it discovers in the directory tree. 请注意,它不会归入它在目录树中发现的JAR文件。 It looks only in those JARs explicitly named in the classpath. 它仅在类路径中显式命名的那些JAR中查找。

The error message is telling you that javac didn't find any classes at all from the javax.mail package. 错误消息告诉您javac根本没有从javax.mail包中找到任何类。 You could have solved it either by specifying the JAR in the compilation classpath (as ultimately you did) or by unpacking the JAR in the current directory. 您可以通过在编译类路径中指定JAR(最终还是这样做)或在当前目录中解压缩JAR来解决它。

Specifying the -classpath helps, the program now compiles and produces Example.class: 指定-classpath帮助,该程序现在编译并生成Example.class:

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

Note that the compiler will store the classfile in a directory structure corresponding to its package, just where the java command will look for it. 请注意,编译器会将类文件存储在与其包相对应的目录结构中,恰好是java命令在其中查找的位置。

Running the program produces this error: 运行程序会产生以下错误:

 $ 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) 

You clarified in your answer that you solved this problem by removing a package statement from Example.java . 您在回答中澄清说,通过从Example.java删除package语句解决了此问题。 That's ok, but it doesn't really explain the problem, which is that java expects you to give it the fully-qualified name of the class. 没关系,但这并不能真正解释问题,这是java希望您为其提供类的完全限定名称。 That includes the package name if the class is in a named package. 如果该类在命名包中,则包括包名。 Thus, if Example.java contained this package statement: 因此,如果Example.java包含以下package语句:

package com.my;

then the class name you would need to specify to java would be com.my.Example . 那么您需要为java指定的类名称为com.my.Example You specified just Example , which designates a class named "Example" in the default package, and your solution to the class not found problem was to move your class into the default package. 您只指定了Example ,它在默认包中指定了一个名为“ Example”的类,而您对该类未找到问题的解决方案是将您的类移到默认包中。

Note also that it is conventional and helpful to lay out your Java source files, too, in a directory structure matching their package structure. 还要注意,将Java源文件布置在与它们的包结构相匹配的目录结构中也是常规且有用的。 Thus, the source file for class com.my.Example would conventionally be located in com/my/Example.java . 因此,类com.my.Example的源文件通常位于com/my/Example.java The Java compiler will rely on this scheme to locate sources for classes that it does not find. Java编译器将依靠此方案找到它找不到的类的源。

Running java without -classpath causes the JNI to not find javax/mail even though it's in the directory. 在不带-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) 

No, javax/mail/Address was not in the directory. 否, javax/mail/Address 不在目录中。 It was in a JAR file in the directory. 它在目录中的JAR文件中。 That's not at all the same thing, and the difference is significant. 那根本不是一回事,而且区别是巨大的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM