Java CLASSPATH在命令行上不起作用 [英] java CLASSPATH not working on command-line

查看:147
本文介绍了Java CLASSPATH在命令行上不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

系统详细信息:

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标志进行编译,但在运行时找不到该类.

I can't get my java program to run. 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.

$ 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默认为.?)

Compiling without -classpath does not work (I thought -classpath defaulted to .?)

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

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

Specifying the -classpath helps, the program now compiles and produces 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());
        }
    }
}

运行程序会产生此错误:

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)

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

Running java without -classpath causes the JNI to not find javax/mail even though it's in the directory.

$ 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类?

Why can't java find the Example class?

推荐答案

您似乎在这里缺少了一些基本概念.

You seem to be missing some fundamental concepts here.

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

The classpath gives a list of directories and JAR files to search for needed classes. 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.class.对于作为JAR文件的类路径条目,它将查找相对于JAR根目录的foo/bar/MyClass.class.属于未命名默认软件包的类似乎有些特殊,因为它们的类文件(例如InDefaultPackage.class)应该直接位于指定JAR的根目录中或直接位于指定目录中. /p>

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. For classpath entries that are JAR files, it looks for foo/bar/MyClass.class relative to the root of the JAR. Classes that belong to the unnamed default package are a little special, or so it may seem, because their class files (e.g. InDefaultPackage.class) are expected to be located directly in the root of the designated JAR or directly in the specified directory.

没有-classpath的编译将不起作用(我认为-classpath 默认为.?)

Compiling without -classpath does not work (I thought -classpath defaulted to .?)

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

类路径默认为..这是目录的名称,因此当在javax.mail包中搜索类时,它会查找子目录javax/mail,如果找到了子目录,它将检查其中的类文件.请注意,它不会进入其在目录树中发现的JAR文件.它只会在类路径中显式命名的那些JAR中查找.

The classpath does default to .. 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. Note that it does not descend into JAR files it discovers in the directory tree. It looks only in those JARs explicitly named in the classpath.

错误消息告诉您javac根本没有从javax.mail包中找到任何类.您可以通过在编译类路径中指定JAR(最终还是这样做)或在当前目录中解压缩JAR来解决此问题.

The error message is telling you that javac didn't find any classes at all from the javax.mail package. 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.

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

Specifying the -classpath helps, the program now compiles and produces Example.class:

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

请注意,编译器会将类文件存储在与其包相对应的目录结构中,而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.

运行程序会产生此错误:

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)

您在回答中澄清说,通过从Example.java中删除package语句解决了此问题.没关系,但这并不能真正解释问题,这是java希望您为其指定类的完全限定名称.如果该类在命名程序包中,则包括程序包名称.因此,如果Example.java包含以下package语句:

You clarified in your answer that you solved this problem by removing a package statement from Example.java. 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. That includes the package name if the class is in a named package. Thus, if Example.java contained this package statement:

package com.my;

,那么您需要为java指定的类名称将为com.my.Example.您只指定了Example,它在默认程序包中指定了一个名为"Example"的类,而您对该类未找到问题的解决方案是将您的类移到默认程序包中.

then the class name you would need to specify to java would be 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.

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

Note also that it is conventional and helpful to lay out your Java source files, too, in a directory structure matching their package structure. Thus, the source file for class com.my.Example would conventionally be located in com/my/Example.java. The Java compiler will rely on this scheme to locate sources for classes that it does not find.

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

Running java without -classpath causes the JNI to not find javax/mail even though it's in the directory.

$ 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文件中.那根本不是一回事,而且区别是很大的.

No, javax/mail/Address was not in the directory. It was in a JAR file in the directory. That's not at all the same thing, and the difference is significant.

这篇关于Java CLASSPATH在命令行上不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆