2005年9月22日星期四

Java 路径解析

路径设置

首先我们看看java学习的最为基础的工作:路径设置。

JDK安装好后会要求设置以下路径:“JAVA_HOME”、“classpath”、“path”。
Windows操作方法:

在Windows下java这些路径设置主要是在系统属性里改变(控制面板->系统->高级->环境变量)

如:

JAVA_HOME D:\j2sdk1.4.2_06\

classpath

.;%JAVA_HOME%\lib\tools.jar;%JAVA_HOME%\lib\htmlconverter.jar;%JAVA_HOME%\lib\dt.jar;d:\Tomcat_4.1\common\lib\servlet.jar

path:

%SystemRoot%\system32;%SystemRoot%;%SystemRoot%\System32\Wbem;D:\j2sdk1.4.2_06\bin\;D:\j2sdk1.4.2_06\jre\bin\

注意:分隔符是分号“;”
Linux操作方法:

增加可执行权限: chmod 755 j2sdk-1_4_2_04-linux-i586-rpm.bin

执行命令运行 ./ j2sdk-1_4_2_04-linux-i586-rpm.bin

执行成功后生成rpm文件:j2sdk-1_4_2_04-linux-i586-rpm

执行rpm –ivh j2sdk-1_4_2_04-linux-i586-rpm安装jdk

在linux下修改文件 /etc/profile中的信息来添加JAVA_HOME,classpath,和修改PATH。在此文件末尾加入以下内容:

JAVA_HOME=/opt/jdk1.4.2_04

CLASSPATH=.:$JAVA_HOME/lib/dt.jar:JAVA_HOME/lib/tools.jar

PATH=$JAVA_HOME/bin:$PATH

Export JAVA_HOME,CLASSPATH,PATH

注意:分隔符是冒号“:”
配制说明

前面我们做了路径的设置,现在我们说明一下他们到底是什么东西,为什么要做这些设置。(Java作为跨平台的语言不能像一般程序一样通过写windows注册表的形式添加其它程序访问的路径。)其中“path”一般系统本身就有,主要是确定系统在运行程序时默认查找的路径,添加%JAVA_HOME%/bin就是方便操作系统找到JDK运行程序的目录;“JAVA_HOME”为JDK安装的路径主要提供其他应用程序访问使用,譬如:Tomcat;“classpath”是最易混淆的设置,我们常常都听说要设置此值中要包含如下内容:“.;%JAVA_HOME%\lib\tools.jar;%JAVA_HOME%\lib\htmlconverter.jar;%JAVA_HOME%\lib\dt.jar”其中“.”常常被强调不可遗漏,但是为什么呢?

首先我们要从java的类(class)说起,java开发中所有一切均为对象,而对象的实现全通过类(class)实现,每个class在操作系统中表现为一个文件(*.class),而包(package)则做为类管理的一种方式。将功能相近,相关的类统一部署在一个包(package)内。这种方式在操作系统里则表现为一个目录。

“.”在操作系统里表示为当前目录当你在Windows操作系统里输入dir时便可以看到两个奇怪的目录“.”“..”,分别代表着当前目录,和上一级目录,这也就是当你想在命令控制附里切换到上一级目录输入“cd ..”的原因。

%JAVA_HOME%代表着设置的“JAVA_HOME”的值,可以使用echo %JAVA_HOME%显示此值。

*.jar文件为java的一种特殊的包文件,若你用winrar工具打开它,就会发现里面也是一级一级的目录最后保存着*.class,和操作系统未打包前的文件格式完全一致。

所以常常设置的java路径“.;%JAVA_HOME%\lib\tools.jar;%JAVA_HOME%\lib\htmlconverter.jar;%JAVA_HOME%\lib\dt.jar”代表的意思为:当java程序编译或运行时,若是需要调用其它的类文件将从以上路径中查询,这个路径首先是当前运行路径然后是其次的几个JDK默认所带的jar包中。
编译示例

现在还是让我们从HelloWord开始了解路径的意义

创建一个java文件E:\HelloWord.java

public class HelloWord {

public static void main(String[] args) {

System.out.println("HelloWord");

}

}

在命令控制附种切换HelloWord.java的路径下,此处为E:\输入javac HelloWord.java编译HelloWord.java将其转化为二进制文件:HelloWord.class,然后使用java HelloWord来运行。

我们再做一个实验同样是此文件,我们在第一行加上:

package A;

删除以前生成的二进制文件:HelloWord.class。现在我们再次编译此文件,会发现编译正常而且同样会在当前目录下生成HelloWord.class。再次用java HelloWord运行他,却抛出NoClassDefFoundError,意思为找不到class文件,也就是说HelloWord类无法找到。但是HelloWord.class文件明明存在的啊?

第一次java在运行时要查找的是classpath中提供路径中的HelloWord.class,它在当前目录下找到了(“.”),所以可以很好的运行。第二次当他再次查找HelloWord.class时现存的HelloWord.class在操作系统文件名称上没用任何变化,但是它是属于A这个package的决定了它实际为A.HelloWord类而不是HelloWord类。所以当前目录下没有HelloWord这个类。那么java A.HelloWord可以运行这个.class文件么?依然不行!为什么呢?因为java的类要和操作系统得文件目录相对应,现在虽然有了A.HelloWord的类,但是却无法找到A这个package对应的目录,所以无法运行。正确的方法为在当前目录下建名为A的目录,将HelloWord.class移入其中,然后再运行java A.HelloWord。
javac参数

让我们通过javac /?来查看javac的参数

我们从了解以下参数来进一步理解java路径:

-classpath,-sourcepath,-d

-classpath为java编译时查找的路径和在操作系统里制定的意义相同。但是当在javac中制定-classpath时,操作系统里指定的classpath将会在此javac运行期间无效。

-sourcepath,当javac编译若是查找不到所需要的class文件,默认情况下它会在当前目录查找class所对应的java文件,若是存在,则自动编译好后再次定位class文件。但是若是源文件没有放在当前目录下(注意class文件要和操作系统文件格式相对应,也就是说A.b class 对应的应该是A目录下的b.java文件。)则可以通过-soucepath来指定源文件可能所在的目录。

-d,javac编译默认情况是在*.java所在的目录生成二进制文件*.class,当源文件不在同一个classpath下时,就会造成程序发布或者运行很困难。-d的意义在于自动在制定路径下按照将程序编译出来的二进制文件按照类所对应的操作系统目录文件形式存放。

下面我们写两个程序介绍下这几个参数的意义。

HelloWord.java

package A;

import B.HelloName;

public class HelloWord {

public static void main(String[] args) {

HelloName peple = new HelloName();

System.out.println("Hello Word " +peple.name);

}

}HelloName.java

package B;

public class HelloName {

public String name = "Tom";

}

简单的解释下代码意义:HelloWord和HelloName分别为A,B两个包内的类在运行A.HelloWord时需要调用B.HelloName类(实际是生成HelloName的实例)。

我们先将这两个文件保存在E:\下,当我们使用javac编译时:javac HelloWord.java马上会发现无法编译,原因是查找不到B.HelloName的类。根据前面讲述的classpath我们很容易知道该怎么解决这个问题:将他们分别放置到各自相对应的目录中去。

然后我们再来编译:javac A\HelloWord.java。ok,一切都正常,在用java A.HelloWord 运行一遍,显示出“Hello Word Tom”说明编译成功且可以运行。

现在我们删除所有的class文件将B目录(包括里面的HelloName.java)文件移入到F:\下,如此一来,当我们再次编译javac HelloWord.java时依然无法查找到B.HelloName类,这时我们可以试试-sourcepath这个参数了,在E:\下编译:javac –soucepath f:\ A\HelloWord.java。编译将正常进行且无任何错误抛出。而且可以查看到,每个java源文件相同的目录下都生成了其对应的class文件。

最后当我们想运行和发布时会发现,凌乱的class和java源文件的不同目录造成运行和发布的操作困难,此时我们应当再次了解javac 的-d参数。再次在E:\目录下(先建立classes目录)使用一下命令编译:javac –soucepath f:\ -d e:\classes A\HelloWord.java。这时E:\classes下会按照java类路径需求自动生成相应的目录。此例中你会看到classes下有两个目录A和B,而A,B目录下则存放着所需要的class文件。

没有评论: