CLASSPATH总结

假设你在C:\workspace下写了个HelloWorld.java,并顺利使用编译程序javac将之编译为HelloWorld.class,在不 切换路径的情况下,可以直接执行java HelloWorld来加载HelloWorld.class并运行当中所定义的行为。
如果你切换到C:\底下或是其它路径底下,那么该如何加载HelloWorld.class并执行呢?以下并不是正解:
java C:\workspace\HelloWorld
首先你要知道java这个指令是作什么用的?执行java,其实就是启动JVM,之后接下类别名称,表示由JVM载入该类别的.class并执行。
在 PATH 是什么? 中提过,当你在实体操作系统下执行某个指令时,操作系统会依PATH中的路径信息,试图找到可执行的档案(例如对Windows来说,就是.exe、.bat,对Linux等就是有执行权限的档案)。
在 为什么需 要 JVM? 中则提过,JVM是Java程序唯一认得的操作系统,对JVM来说,可执行文件就是扩展名为.class的档案。当你要想在JVM中执行某个它的可执行文件(.class)时,则JVM会依CLASSPATH中的路径信息来寻找。
作个简单的比照,可以很清楚地对照PATH与CLASSPATH:
实体操作系统依PATH中的路径信息来寻找可执行指令(对Windows就是.exe、.bat等,对Linux等就是有执行权限的档案)。
JVM(虚拟操作系统)依CLASSPATH中的路径信息来寻找可执行指令(.class档案)。
如何在启动JVM时告知可执行文件(.class)的位置?可以使用-classpath自变量来指定:
java -classpath c:\workspace HelloWorld
指定可执行文件(.class)时,不用加上.class扩展名,这跟在Windows下执行javac时,不用特别再加上扩展名(javac.exe)是类似的。如果有多个路径信息,则可以用分别区隔。-classpath有个缩写形式-cp。例如:
java -cp c:\workspace;c:\classes HelloWorld
与PATH类似地,JVM会依路径的顺序,找寻是否有对应的类别档案,先找到先赢,先找到先载入。如果在JVM的CLASSPATH路径信息中都找不到指定的类别档案,则会出现java.lang.NoClassDefFoundError的信息。
如果使用Java开发了一些程序作为链接库,这些链接库中的类别档案,会封装为JAR(Java Archive)档案,也就是扩展名为.jar的档案。JAR档案实际上是使用ZIP格式作压缩,当中包含一堆.class档案,之后还会介绍如何制作 JAR档案。总之,现在如果你拿到一个JAR档案,如何在CLASSPATH中设定?
答案是将JAR档案当作一个特别的文件夹,例如,你拿到一个abc.jar与xyz.jar,放在C:\lib底下,则执行时如果使用到该JAR档案中的类别,则可以如下:
java -cp c:\workspace;c:\lib\abc.jar;c:\lib\xyz.jar SomeApp
在使用IDE的时候,会在IDE的项目中设定(或有时称汇入)所谓的「链接库」,其实就是在IDE项目环境下的CLASSPATH中设定JAR档案的位置与名称。
事实上,不只执行时可以设定CLASSPATH,编译时也会需要设定CLASSPATH,例如你开发了一个Message.java:
public class Message {
private String text;
public Message(String text) {
this.text = text;
}
public String getText() {
return text;
}
}
编译完的Message.class是放在c:\classes之下。现在你在c:\workspace下写了个HelloWorld.java:
public class HelloWorld {
public static void main(String[] args) {
Message message = new Message(“Hello!World!”);
System.out.println(message.getText());
}
}
如果你直接编译HelloWorld.java,则会出现以下的讯息:
表面字义看来,叫作不认得Message是什么符号,这其实是编译程序不知道你的Message定义档在哪?也就是编译程序找不到Message.class在哪!你在编译时,必须告知所使用到的类别档案是放在哪边,指定的方式也是靠CLASSPATH:
javac -cp c:\classes HelloWorld.java
编译程序如果看到原始码中有使用到Message这个名称,就会试着找看看在类别路径中,有无Message.class,如果有就读取刚中的信息,看看相关方法等定义是否正确,然后才进行编译。
那么要执行时,也是得指定CLASSPATH,不过以下指定却会发生问题:
原 因其实很简单,因为你指定的类别路径是c:\classes,所以JVM只在c:\classes下找相关的.class档案,而当中并没有 HelloWorld.class,因为HelloWorld.class是位于c:\workspace下。你要这样指定才正确:
java -cp c:\workspace;c:\classes HelloWorld
那为什么执行第一个HelloWorld时,不用特别指定CLASSPATH?默认的CLASSPATH就会读取当前目录下的.class,但是如果你自行指定了CLASSPATH,则以你指定的为主。
如果有些类别路径很常使用,则你也可以透过环境变量设定,例如:
SET CLASSPATH=C:\classes;c:\lib\abc.jar;c:\lib\xyz.jar
当 你启动JVM时,也就是执行java时,或者是编译时,也就是使用javac时,不指定CLASSPATH,则会读取环境变量信息中的CLASSPATH 变量设定。同样地,这个设定在关闭这个文本模式之后,就会失效,下次必须重新设定。如果你希望每次开启文本模式都可以套用某个CLASSPATH设定的 话,则可以设定在系统变量或用户变量中。如果你执行或编译时,使用了-cp或-classpath来指定类别的路径所在,则以-cp或-classpath设定的为主。
实际上,CLASSPATH的路径设定,是给应用程序类别加载器(AppClassLoader)使用的信息。想要了解类别加载的方式,则要了解类别加载器机制,这是进阶议题,要在较后面的文件中才会谈到。
在Java SE 6前,如果目录下有很多.jar档案,则要一个一个.jar档案分别指定,才可以正确的设定Classpath,例如您可能在执行程序时,如下指定Classpath:
java –cp .;c:\jars\a.jar;c:\jars\b.jar cc.openhome.JNotePad
在Java SE 6中,您可以使用’*’来指定某个目录下的所有.jar档案,例如上例在Java SE 6中,可以如下指定:
java –cp .;c:\jars\* cc.openhome.JNotePad
Java SE 6中Classpath新的指定方式,也适用在系统环境变量的设定上。

此条目发表在java/j2ee分类目录,贴了标签。将固定链接加入收藏夹。

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据