类路径

Classpath

Java路径


import java.io.File;

/**

 * @description <p>java 路径</p>

 * @author swandragon

 * @date Nov 5, 2009

 */

public class FilePath{

    /**

     * 开发中不要使用System.getProperty("user.dir")获取当前用户目录的相对路径

     * 也尽可能不要使用绝对路径,使用绝对路径时可以在配置文件中配置,项目中读取配置文件

     * 应尽可能的使用相对路径,推荐使用当前类的classpath的URI目录路径

     * 使用相对于classpath的路径而不是相对于源文件的路径,因为项目运行的是类文件

     */

    public static void main(String[] args){

        //用户当前工作目录,绝对路径

        System.out.println(System.getProperty("user.dir"));

         

        //java类路径 ,包括路径中的jar包

        System.out.println(System.getProperty("java.class.path"));

         

        //加载库时搜索路径(jdk bin目录,当前目录,系统目录/WINDOWS;/WINDOWS/system32,环境变量path目录)

        System.out.println(System.getProperty("java.library.path"));

         

        //用户当前目录 (项目跟目录绝对路径)

        File file = new File("");

        System.out.println(file.getAbsolutePath());

         

        //用户当前目录 (项目跟目录绝对路径)

        file = new File(".");

        System.out.println(file.getAbsolutePath());

         

        //用户当前目录 (项目跟目录绝对路径)

        file = new File(".//");

        System.out.println(file.getAbsolutePath());

         

        //用户当前目录的上级目录 (项目跟目录绝对路径的上级目录)

        file = new File("..");

        System.out.println(file.getAbsolutePath());

         

        //用户当前目录的上级目录 (项目跟目录绝对路径的上级目录)

        //(..//images) images与当前目录的上级目录为同级目录

        file = new File("..//");

        System.out.println(file.getAbsolutePath());

         

         

        //当前类FilePath的类文件的URI目录 包括FilePath类所在的包

        System.out.println(FilePath.class.getResource(""));

        //当前类的classpath的URI目录

        System.out.println(FilePath.class.getResource("/"));

        //当前类的classpath的URI目录

        System.out.println(FilePath.class.getClassLoader().getResource(""));

        //当前类的classpath的URI目录

        System.out.println(Thread.currentThread().getContextClassLoader().getResource(""));

        //当前类的classpath的URI目录

        System.out.println(ClassLoader.getSystemResource(""));

file:/D:/Eclipse_IDE/eclipse%20DS%203.7.0/EShop_workspace/Collection_20140922/bin/lisuxuan/

file:/D:/Eclipse_IDE/eclipse%20DS%203.7.0/EShop_workspace/Collection_20140922/bin/

file:/D:/Eclipse_IDE/eclipse%20DS%203.7.0/EShop_workspace/Collection_20140922/bin/

file:/D:/Eclipse_IDE/eclipse%20DS%203.7.0/EShop_workspace/Collection_20140922/bin/

file:/D:/Eclipse_IDE/eclipse%20DS%203.7.0/EShop_workspace/Collection_20140922/bin/

 

    }

}

 

 

 

Java相对路径总结》 
[http://blog.csdn.net/swandragon/article/details/4770519

1.基本概念的理解 

绝对路径:绝对路径就是你的主页上的文件或目录在硬盘上真正的路径,(URL和物理路径)例如: 
C:xyz est.txt 代表了test.txt文件的绝对路径。http://www.sun.com/index.htm也代表了一个URL绝对路径。 

相对路径:相对与某个基准目录的路径。包含Web的相对路径(HTML中的相对目录),例如:在 
Servlet中,"/"代表Web应用的跟目录。和物理路径的相对表示。例如:"./" 代表当前目录,"../"代表上级目录。这种类似的表示,也是属于相对路径。 
另外关于URI,URL,URN等内容,请参考RFC相关文档标准。 

RFC 2396: Uniform Resource Identifiers (URI): Generic Syntax, 
(http://www.ietf.org/rfc/rfc2396.txt


2.关于JSP/Servlet中的相对路径和绝对路径。 

2.1服务器端的地址 

服务器端的相对地址指的是相对于你的web应用的地址,这个地址是在服务器端解析的(不同于html和javascript中的相对地址,他们是由客户端 浏览器解析的)也就是说这时候在jsp和servlet中的相对地址应该是相对于你的web应用,即相对于http: //192.168.0.1/webapp/的。 

其用到的地方有: 
forward:servlet中的request.getRequestDispatcher(address);这个address是在服务器端解析 的,所以,你要forward到a.jsp应该这么写:request.getRequestDispatcher(“/user/a.jsp”)这个/ 相对于当前的web应用webapp,其绝对地址就是:http://192.168.0.1/webapp/user/a.jsp sendRedirect:在jsp中<%response.sendRedirect("/rtccp/user/a.jsp");%>

2.22、客户端的地址 

所有的html页面中的相对地址都是相对于服务器根目录(http://192.168.0.1/)的,而不是(跟目录下的该Web应用的目录http://192.168.0.1/webapp/的。 Html中的form表单的action属性的地址应该是相对于服务器根目录(http://192.168.0.1/)的,所以,如果提交到a.jsp 为:action="/webapp/user/a.jsp"或action="<%=request.getContextPath()% >"/user/a.jsp;
提交到servlet为actiom="/webapp/handleservlet" Javascript也是在客户端解析的,所以其相对路径和form表单一样。 


因此,一般情况下,在JSP/HTML页面等引用的CSS,Javascript.Action等属性前面最好都加上 
<%=request.getContextPath()%>,以确保所引用的文件都属于Web应用中的目录。另外,应该尽量避免使用类似".","./","../../"等类似的相对该文件位置的相对路径,这样当文件移动时,很容易出问题。 


3. JSP/Servlet中获得当前应用的相对路径和绝对路径 
3.1 JSP中获得当前应用的相对路径和绝对路径 
根目录所对应的绝对路径:request.getRequestURI() 
文件的绝对路径 :application.getRealPath(request.getRequestURI()); 
当前web应用的绝对路径 :application.getRealPath("/"); 
取得请求文件的上层目录:new File(application.getRealPath(request.getRequestURI())).getParent() 

3.2 Servlet中获得当前应用的相对路径和绝对路径 
根目录所对应的绝对路径:request.getServletPath(); 
文件的绝对路径 :request.getSession().getServletContext().getRealPath 
(request.getRequestURI()) 
当前web应用的绝对路径 :servletConfig.getServletContext().getRealPath("/"); 
(ServletContext对象获得几种方式: 
javax.servlet.http.HttpSession.getServletContext() 
javax.servlet.jsp.PageContext.getServletContext() 
javax.servlet.ServletConfig.getServletContext() 


4.java 的Class中获得相对路径,绝对路径的方法 
4.1单独的Java类中获得绝对路径 
根据java.io.File的Doc文挡,可知
默认情况下new File("/")代表的目录为:System.getProperty("user.dir")。 
一下程序获得执行类的当前路径 
package org.cheng.file; 
import java.io.File; 

public class FileTest { 
public static void main(String[] args) throws Exception { 

System.out.println(Thread.currentThread().getContextClassLoader().getResource("")); 

System.out.println(FileTest.class.getClassLoader().getResource("")); 

System.out.println(ClassLoader.getSystemResource("")); 
System.out.println(FileTest.class.getResource("")); 
System.out.println(FileTest.class.getResource("/")); //Class文件所在路径 
System.out.println(new File("/").getAbsolutePath()); 
System.out.println(System.getProperty("user.dir")); 



4.2服务器中的Java类获得当前路径(来自网络) 
(1).Weblogic 

WebApplication的系统文件根目录是你的weblogic安装所在根目录。 
例如:如果你的weblogic安装在c:eaweblogic700..... 
那么,你的文件根路径就是c:. 
所以,有两种方式能够让你访问你的服务器端的文件: 
a.使用绝对路径: 
比如将你的参数文件放在c:yourconfigyourconf.properties, 
直接使用 new FileInputStream("yourconfig/yourconf.properties"); 
b.使用相对路径: 
相对路径的根目录就是你的webapplication的根路径,即WEB-INF的上一级目录,将你的参数文件放 

yourwebappyourconfigyourconf.properties, 
这样使用: 
new FileInputStream("./yourconfig/yourconf.properties"); 
这两种方式均可,自己选择。 

(2).Tomcat 

在类中输出System.getProperty("user.dir");显示的是%Tomcat_Home%/bin 

(3).Resin 

不是你的JSP放的相对路径,是JSP引擎执行这个JSP编译成SERVLET 
的路径为根.比如用新建文件法测试File f = new File("a.htm"); 
这个a.htm在resin的安装目录下 

(4).如何读相对路径哪? 

Java文件中getResource或getResourceAsStream均可 

例:getClass().getResourceAsStream(filePath);//filePath可以是"/filename",这里的/代表web 

发布根路径下WEB-INF/classes 

默认使用该方法的路径是:WEB-INF/classes。已经在Tomcat中测试。 

5.读取文件时的相对路径,避免硬编码和绝对路径的使用。(来自网络) 
5.1 采用Spring的DI机制获得文件,避免硬编码。 
参考下面的连接内容: 
http://www.javajia.net/viewtopic.php?p=90213& 
5.2 配置文件的读取 
参考下面的连接内容: 
http://dev.csdn.net/develop/article/39/39681.shtm 
5.3 通过虚拟路径或相对路径读取一个xml文件,避免硬编码 
参考下面的连接内容: 
http://club.gamvan.com/club/clubPage.jsp?iPage=1&tID=10708&ccID=8 

6.Java中文件的常用操作(复制,移动,删除,创建等)(来自网络) 
常用 java File 操作类 
http://www.easydone.cn/014/200604022353065155.htm 

Java文件操作大全(JSP中) 
http://www.pconline.com.cn/pcedu/empolder/gj/java/0502/559401.html 

java文件操作详解(Java中文网) 
http://www.51cto.com/html/2005/1108/10947.htm 

JAVA 如何创建删除修改复制目录及文件 
http://www.gamvan.com/developer/java/2005/2/264.html 

总结: 
通过上面内容的使用,可以解决在Web应用服务器端,移动文件,查找文件,复制 
删除文件等操作,同时对服务器的相对地址,绝对地址概念更加清晰。 
建议参考URI,的RFC标准文挡。同时对Java.io.File. Java.net.URI.等内容了解透彻 
对其他方面的理解可以更加深入和透彻。

 

Java类路径说明》


一、类路径   (class  path)

当你满怀着希望安装好java,然后兴冲冲地写了个“hello  world”,然后编译, 运行,就等着那两个美好的单词出现在眼前。可是不幸的是,只看到了“Can't  find  class  HelloWorld”或者“Exception  in  thread  "main"  java.lang.NoSuchMethodError: main。

为什么呢?编译好的class明明在呀。

我们一起来看一看java程序的运行过程。我们已经知道java是通过java虚拟机来解释运行的,也就是通过java命令—javac编译生成的.class文件就是虚拟机要执行的代码, 称之为字节码(bytecode),虚拟机通过classloader来装载这些字节码,也就是通常意义上的类。这里就有一个问题,classloader从哪里知道java本身的类库及用户自己的类在什么地方呢?或者有着缺省值(当前路径) ,或者要有一个用户指定的变量来表明,这个变量就是类路径(classpath),或者在运行的时候传参数给虚拟机。这也就是指明classpath的三个方法。编译的过程和运行的过程大同小异,只是一个是找出来编译,另一个是找出来装载。实际上java虚拟机是由java  luncher初始化的,也就是java (或java.exe) 这个程序来做的。虚拟机按以下顺序搜索并装载所有需要的类:

1、引导类:组成java平台的类,包含rt.jar和i18n.jar中的类。

2、扩展类:使用java扩展机制的类,都是位于扩展目录($JAVA_HOME/jre/lib/ext)
中的.jar档案包。

3、用户类:开发者定义的类或者没有使用java扩展机制的第三方产品。你必须在命令行中使用-classpath选项或者使用CLASSPATH环境变量来确定这些类的位置。

我们在上面所说的用户自己的类就是特指这些类。

这样,一般来说,用户只需指定用户类的位置,引导类和扩展类是“自动”寻找的。那么到底该怎么做呢?用户类路径就是一些包含类文件的目录,.jar, .zip文件的列表,至于类具体怎么找,因为牵扯到package的问题,下面将会说到,暂时可认为只要包含了这个类就算找到了这个类。根据平台的不同分隔符略有不同,类unix的系统基本上都是“:”,windows多是“;”。其可能的来源是
    *   “. ”, 即当前目录,这个是缺省值。

*   CLASSPATH环境变量,一旦设置,将缺省值覆盖。

*   命令行参数-cp或者-classpath,一旦指定,将上两者覆盖。

*   由-jar参数指定的.jar档案包,就把所有其他的值覆盖,所有的类都来自这个指定的档案包中。由于生成可执行的.jar文件,还需要其他一些知识,比如package,还有特定的配置文件,本文的最后会提到。可先看看jdk自带的一些例子。

我们举个HelloWorld的例子来说明。先做以下假设:

*   当前目录是/HelloWorld(或c:\HelloWorld, 以后都使用前一个)

*   jdk版本为1.2.2 (linux下的)

*   PATH环境变量设置正确。(这样可以在任何目录下都可以使用工具)

*   文件是HelloWorld.java,内容是:

    public   class   HelloWorld

    {

public   static   void   main(String[]   args)

{

System.out.println( "Hello   World!\n ");

System.exit(0);

 }

 }

首先这个文件一定要写对,如果对c熟悉的话,很有可能写成这样:

public   static   void   main(int   argc,String[]   argv)

{

  ....

}

这样是不对的,不信可以试一试。由于手头没有java的规范,所以作如下猜想: java的application程序,必须以public   static   void   main(String[])开始,其他不一样的都不行。

到现在为止,我们设置方面只设置了PATH。

1、当前路径就是指你的.class文件在当前目录下,

 [HelloWorld]$   javac   HelloWorld.java     //这一步不会有多大问题,

 [HelloWorld]$   java   HelloWorld            //   这一步可能就会有问题.。

如果出了象开头那样的问题,首先确定不是由于敲错命令而出错。如果没有敲错命令,那么接着做:

 [HelloWorld]$   echo   $CLASSPATH

或者   c:\HelloWorld> echo   %CLASSPATH%

看看CLASSPATH环境变量是否设置了, 如果设置了,那么用以下命令:

[HelloWorld]$   CLASSPATH=

或者   c:\HelloWorld>   set   CLASSPATH=

来使它为空,然后重新运行。这次用户类路径缺省的是". ",所以应该不会有相同的问题了。还有一个方法就是把". "加入到CLASSPATH中。

 [/]$   CLASSPATH=$CLASSPATH:.

或者  c:\HelloWorld>   set   CLASSPATH=%CLASSPATH%; 

同样也可以成功.   Good   Luck。

2、 当你的程序需要第三方的类库支持,而且比较常用,就可以采用此种方法。比如常用的数据库驱动程序,写servlet需要的servlet包等等。设置方法就是在环境变量中加入CLASSPATH。然后就可以直接编译运行了。还是以HelloWorld为例,比如你想在根目录中运行它,那么你直接在根目录下执行

$   java   HelloWorld

或者   c:\> java   HelloWorld

这样肯定会出错,如果你的CLASSPATH没有改动的话.。我想大家应该知道为什么错了吧,那么怎么改呢?前面说过,用户类路径就是一些包含你所需要的类的目录,.jar档案包,.zip包。现在没有生成包,所以只好把HelloWorld.class所在的目录加到CLASSPATH了,根据前面的做法,再运行一次,看看,呵呵,成功了,换个路径,又成功了!!不仅仅以直接运行其中的类,当你要import其中的某些类时,同样处理。

不知道你想到没有,随着你的系统的不断的扩充,(当然了,都是一些需要java的东西。 如果都加到这个环境变量里,那这个变量会越来越臃肿,虽然环境变量空间可以开很大,总 
觉得有些不舒服。看看下面一个方法。

3、在命令行参数中指明classpath。

还是和上面相同的目标,在任何目录下执行HelloWorld,用这个方法怎么实现呢?

[/]$   java   -cp   /HelloWorld   HelloWorld

或者 c:\> java   -cp   c:\HelloWorld   HelloWorld

就可以了。这是这种方法的最简单的应用了。当你使用了另外的包的时候,还可以采用用这种方法。例如:

 $   javac   -classpath   aPath/aPackage.jar:.   myJava.java

$   java     -cp   aPath/aPackage.jar:.   myJava

或者  c:\>   javac   -classpath   aPath\aPackage.jar;.   myJava.java

c:\>   java     -cp   aPath\aPackage.jar;.   myJava

这种方法也有一个不方便的的地方就是当第三方包所在的路径较长或者需要两个以上包包的时候,每次编译运行都要写很长,非常不方便,这时候可以写脚本来解决。 比如一个例子:

compile  (文件,权限改为可执行,当前目录)           

$   cat   compile

---------------------------

#!/bin/bash

javac   -classpath   aPath\aPackage.jar:anotherPath\anotherPackage.jar:.  myJavva.java

---------------------------

run   (文件,权限改为可执行,当前目录)

$cat   run

---------------------------

#!/bin/bash

java   -cp   aPath\aPackage.jar:anotherPath\anotherPackage.jar:.   myJava

---------------------------

或者:

compile.bat

c:\HelloWorld>   type   compile.bat

-------------------------

javac   -classpath   aPath\aPackage.jar:anotherPath\anotherPackage.jar:. myJavva.java

-------------------------

run.bat

c:\HelloWorld>   type   run.bat

------------------------

java   -cp   aPath\aPackage.jar:anotherPath\anotherPackage.jar:.   myJava

------------------------

就可以了。试试看。

前面提到了扩展类,扩展类是什么呢?java的扩展类就是应用程序开发者用来扩展核心平台功能的java类的包(或者是   native   code)。虚拟机能像使用系统类一样使用这些扩展类。有人建议可以把包放入扩展目录里,这样,CLASSPATH也不用设了,也不用指定了,岂不是很方便?确实可以正确运行,但是个人认为这样不好,不能什么东西都往里搁,一些标准的扩展包可以,比如,JavaServlet,Java3D等等。可以提个建议,加一个环境变量,比如叫JARPATH,指定一个目录,专门存放用户的jar 、zip等包,这个要等SUN公司来做了。windows98下,我原来安装的时候,一直装不上,总是死机,好不容易装上了,缺省的是不能运行正确的,然后把   tool.jar   放入   CLASSPATH   后工作正常。现在作测试,去掉仍然是正确的。经过多次测试,发现如果原来曾装过jdk的都很好,没有装过的装的时候会死机,多装几次就可以了。如果你发现正确安装后,不能正常工作,就把tools.jar加入CLASSPATH,试一下。

 

二、包 (package)

Java中的“包”是一个比较重要的概念,package是这样定义的: Definition: A package is a   collection   of   related   classes   and   interfaces that  provides  access protection   and   namespace   management。

也就是: 一 个包就是一些提供访问保护和命名空间管理的相关类与接口的集合。使用包的目的就是使类容易查找使用,防止命名冲突,以及控制访问。这里我们不讨论关于包的 过多的东西,只讨论和编译,运行,类路径相关的东西。至于包的其他内容,请自己查阅相关文档。简单一点来说,包就是一个目录,下面的子包就是子目录,这个 包里的类就是这个目录下的文件。我们用一个例子来说明。

首先建目录结构如下: PackageTest/source/,以后根目录指的是PackageTest目录,我们的源程序放在source目录下。源程序如下:

PackageTest.java

package   pktest;

import   pktest.subpk.*;

 public   class   PackageTest

{

private   String   value;

  public   PackageTest(String   s)

 {

value   =   s;

 }

public   void   printValue()

{

System.out.println( "Value   of   PackageTest   is   "   +   value);

}

public   static   void   main(String[]   args)

{

PackageTest   test   =   new   PackageTest( "This   is   a   Test   Package ");

test.printValue();

PackageSecond   second   =   new   PackageSecond( "I   am   in   PackageTest ");

second.printValue();

PackageSub   sub   =   new   PackageSub( "I   am   in   PackageTest ");

sub.printValue();

System.exit(0); 
        }

}

 

PackageSecond.java

package   pktest;

public   class   PackageSecond

{

private   String   value;

 public   PackageSecond(String   s)

 {

value   =   s;

 }

public   void   printValue()

{

System.out.println( "Value   of   PackageSecond   is   "   +   value);

}

}

 

PackageSub.java

package   pktest.subpk;

import   pktest.*;

public   class   PackageSub

{

private   String   value;

 public   PackageSub(String   s)

 {

value   =   s;

}

public   void   printValue()

{

PackageSecond   second   =   new   PackageSecond( "I   am   in   subpackage. ");

second.printValue();

System.out.println( "Value   of   PackageSub   is   "   +   value);

}




Main.java

import   pktest.*;

import   pktest.subpk.*;

public   class   Main()

{

 public   static   void   main()

{

PackageSecond   second   =   new   PackageSecond( "I   am   in   Main ");

second.printValue();

PackageSub   sub   =   new   PackageSub( "I   am   in   Main ");

sub.printValue();

System.exit(0);

}

}

其中,Main.java 是包之外的一个程序,用来测试包外的程序访问包内的类, PackageTest.java 属于 pktest 这个包,也是主程序. PackageSecond.java 也属于 pktest,PackageSub 属于 pktest 下的 subpk 包,也就是 pktest.subpk。详细使用情况,请参看源程序。

好了,先把源程序都放在 source 目录下,使 source 成为当前目录,然后编译一下,呵呵,出错了,

Main.java:1: Package pktest not found in import.

import pktest.*;

这里涉及到类路径中包是怎么查找的,前面我们做了一点假设: "只要包含了这个类就算找到了这个类 ",现在就有问题了。其实jdk的工具javac 、java 、javadoc都需要查找类,看见目录,就认为是包的名字,对于 import 语句来说,一个包对应一个目录。这个例子中,import pktest.*,我们知道类路径可以包含一个目录,那么就以那个目录为根,比如有个目录 /myclass,那么就会在查找/myclass/pktest 目录及其下的类. 所有的都找遍,如果没有就会报错。由于现在的类路径只有当前目录,而当前目录下没有 pktest 目录,所以就会出错。类路径还可以包含 .jar .zip文件,这些就是可以带目录的压缩包,可以把 .jar .zip文件看做一个虚拟的目录,然后就和目录一样对待了。

好了,应该知道怎么做了吧,修改后的目录结构如下:

PackageTest

|

|__source  Main.java

|

|__pktest  PackageTest.java  PackageSecond.java

|

|__subpk  PackageSub.java

然后重新编译,运行,哈哈,通过了。我们再来运行一下PackageTest。

[source]$   java   pktest/PackageTest

怎么又出错了?

Exception in  thread "main" java.lang.NoClassDefFoundError: pktest/PackageTest

是这样的,java所要运行的是一个类的名字,它可不管你的类在什么地方,就象我们前面所讨论的一样来查找这个类,所以它把pktest/PackageTest看成是一个类的名字了,当然会出错了,应该这么做,

 [source]$   java   pktest.PackageTest

大家应该明白道理吧,我就不多说了。注意javac不一样,是可以指明源文件路径的,javac只编译,不运行,查找类也只有在源文件中碰到import时才会做,与源文件所在的包没有关系。似乎还又些不好的地方,怎么生成的   .class   文件这么分散呀,看着真别扭。别急,javac有一个 -d 命令行参数,可以指定一个目录,把生成的 .class 文件按照包给你好好地搁在这个目录里面
        [source]$   mkdir   classes 
        [source]$   javac   -d   classes   pktest/PackageTest.java 
        [source]$   javac   -d   classes   Main.java

那么运行怎么运行呢
        [source]$   cd   classes 
        [classes]$   java   pktest.PackageTest 
        [classes]$   java   Main

就可以了。其实jdk的这一套工具小巧简单,功能强大,不会用或者用错其实不关工具的事,关键是明白工具背后的一些原理和必要的知识。集成环境是很好,但是它屏蔽了很多底层的知识,不出错还好,一旦出错,如果没有这些必要的知识就很难办,只好上bbs问,别人只告诉了你解决的具体方法,下一次遇到稍微变化一点的问题又不懂了。所以不要拘泥于工具,java的这一套工具组合起来使用,中小型工程(五六十个类),还是应付得下来的。

 

三、jar文件

以下把.jar.zip都看做是.jar文件。

1、从前面我们可以看出来jar文件在java中非常重要,极大地方便了用户的使用。我们也可以做自己的.jar包。

2、还是使用前面那个例子,Main.java是包之外的东西,用了pktest包中的类,我们现在就是要把pktest做成一个.jar包,很简单,刚才我们已经把pktest中的.class都集中起来了,

[classes]$   jar   -cvf   mypackage.jar   pktest

就会生成mypackage.jar文件,测试一下,刚才我们生成的Main.class就在classes目录下,所以,从前面可以知道:

[classes]$   java   -cp   mypackage.jar:.   Main

就可以运行了。

3、如果你看过jdk所带的例子,你就会知道,.jar还可以直接运行,

 [/demo]$   java   -jar   aJar.jar

那好,就那我们的试一试,

 [classes]$   java   -jar   mypackage.jar

Failed   to   load   Main-Class   manifest   attribute   from mypackage.jar

看来我们的jar和它的jar还不一样,有什么不一样呢?拿它一个例子出来,重新编译,生成.jar文件,比较后发现,是.jar压缩包中META-INF/MANIFEST.MF文件不一样,多了一行,Main-Class: xxxxx,再看看出错信息,原来是没有指定Main-Class,看看jar命令,发现有一个参数-m,

 -m     include   manifest   information   from   specified   manifest   file

和出错信息有点关系,看来它要读一个配制文件.   只好照猫画虎写一个了。

[classes]$   cat   myManifest

Manifest-Version:   1.0

Main-Class:   pktest.PackageTest

Created-By:   1.2.2   (Sun   Microsystems   Inc.)

[classes]$   jar   cvfm   mypackage.jar   myManifest   pktest

added   manifest

adding:   pktest/(in   =   0)   (out=   0)(stored   0%)

adding:   pktest/PackageSecond.class(in   =   659)   (out=   395)(deflated   40%)

adding:   pktest/subpk/(in   =   0)   (out=   0)(stored   0%)

adding:   pktest/subpk/PackageSub.class(in   =   744)   (out=   454)(deflated   38%)

adding:   pktest/PackageTest.class(in   =   1041)   (out=   602)(deflated 42%)

[classes]$   java   -jar   mypackage.jar

Value   of   PackageTest   is   This   is   a   Test   Package

Value   of   PackageSecond   is   I   am   in   PackageTest

Value   of   PackageSecond   is   I   am   in   subpackage.

Value   of   PackageSub   is   I   am   in   PackageTest

好了,成功了,这样就做好了一个可以直接执行的.jar文件。大家可以自己试一试 
做一个以Main为主程序的可执行的jar。

 

小结:

这篇文章中,我们讨论了java中的classpath,package,jar等基本但比较重要的东西,主要是classpath  并不是简单的一份CLASSPATH的完全功略,而是试图让读者明白其原理,自己思考,自己动手。其实大多数东西都在sun的java doc 中都有,我只不过结合例子稍微谈了一下,希望能有所帮助。由于条件所限,只测试了 jdk1.2.2在98及linux的情况,其他版本的jdk和平台请大家自己测试,错误在所难免,还请指正。

下面是一些需要注意的问题:

1、如果类路径中需要用到.jar文件,必须把jar文件的文件名放入类路径,而不是其所在的目录。

2、在任何时候,类名必须带有完全的包名。

3、". "   当前目录最好在你的类路径中。

下面是一些常见的编译和运行的模式:

1)To  compile  HelloWorld.java  app  in  the  default  package  in  C:\MyDir,

use  CD  \MyDir C:\jdk1.3\bin\Javac.exe  -classpath  .  HelloWorld.java

2)To  run  a  HelloWorld.class  app,in  the  default  package  in  C:\MyDir,

Use  CD  \MyDir C:\jdk1.3\bin\Java.exe  -classpath  .  HelloWorld

3)To  run  a  HelloWorld.class  app,in  the  default  package  in  a jar  in C:\MyDir,

use CD  \MyDir  C:\jdk1.3\bin\Java.exe  -classpath  HelloWorld.jar  HelloWorld

4)To  compile  a  HelloWorld.java  app  in  C:\MyPackage,in  package MyPackage,

use CD  \C:\jdk1.3\bin\Javac.exe  -classpath  .  MyPackage\HelloWorld.java

5)To  run  a  HelloWorld.class  app  in  C:\MyPackage,in  package  MyPackage,

use CD  \C:\jdk1.3\bin\Java.exe  -classpath  .  MyPackage.HelloWorld

6)To  run  a  HelloWorld.class  app  in  C:\MyPackage,in  a  jar  in package MyPackage,

use  CD  \MyDir  C:\jdk1.3\bin\Java.exe  -classpath  HelloWorld.jar  MyPackage.HelloWorld

(注:   default   package   指的是在程序中不指定任何包)。

最后一个小小的建议,把sun的jdk tools documentation好好地看一看,把jdk  的那些工具 java  javac  javadoc  jar javap  jdb......好好用一用,会有好处的。The  Simplest  Is  The  Best。

 

参考文献:

Java   Tools   Documentation.

Java   Glossary   http://mindprod.com

类路径(概念)


 

 

 

 

《了解Java类路径》



Java中的类路径分“编译后的存放路径 和 “运行时的查找路径”,下面分别谈谈

1. java编译后的类存放路径,

分两种:“源文件被直接编译”和“源文件被间接编译

        1-1源文件直接编译

          什么是源文件直接编译:即通过javac直接编译源文件

建立d:\my目录,在其目录下新建一个文件,如下:

Public class HelloWorld{

    Public static void main(String[] args){

        System.out.println(“HelloWorld”);

    }

}

在命令行输入: javac HelloWorld.java

这时在d:\my这个目录下就产生了一个类文件HelloWorld.class

在命令行输入: java HelloWorld

HelloWorld

正常输出



改变一:

把原文件中的输出内容改为”changeHelloWorld”

重新编译,运行,可以看到在控制台输出了

changeHelloWorld



改变二:

恢复一的改变,并删除之前生成的类文件, 在源文件中的头部加入

Package com.test;

然后在命令行输入: javac –d . HelloWorld.java

这时在d:\my这个目录下就产生了一个新的目录com\test,类文件HelloWorld.class就位于test下

注,如果不指明路径,则javac只会把生成的类文件放在默认包中,如同没包



改变三:

删除改变二中所产生的目录结构与类

然后在命令行输入: javac –d d:\ HelloWorld.java

这时在d:\ 这个根目录下就产生了一个新的目录com\test,类文件HelloWorld.class就位于test下

总结:对于源文件被直接编译的,其规则如下:

1. 每一次执行javac命令都会重新编译源文件,

2. 编译后的类文件的存放地址可以指定

3. 源文件带package结构并且指定编译后的路径的,编译后系统直接产生类文件存放的目录结构(如果不指定,产生的class文件会保存在与源文件同一目录下,但是没有包中指定的目录结构出现)。

 

    1-2源文件间接编译

          什么是源文件间接编译:放在A类中的B类,当A.java通过javac编译时,B也会被编译

建立d:\my1目录,在其目录下新建两个文件,如下:

A. java

public class A{

    public static void main(String[] args){

        B b1 = new B();

        b1.print();

    }

}

B. java

public class B{

    public void print(){

        System.out.println("package test");

    }

}

接着在命令行输入 javac A.java

这时在d:\my1这个目录下就产生了两个类文件A.class与B.class

执行java A

Package test



改变一:

删除以上所产生的类文件,修改两个文件的源代码,分别在头部加上import edu.nctu.*;和package edu.nctu;即

A. java

import edu.nctu.*;

public class A{

    public static void main(String[] args){

        B b1 = new B();

        b1.print();

    }

}

B. java

package edu.nctu;

public class B{

    public void print(){

        System.out.println("package test");

    }

}

在命令行输入:

Javac A.java

接着会出现一些错误提示,主要提示如下:

A. java:1:package edu.nctu does not exist

解决方式:把d:\my1目录下的B.java移到d:\my1\edu\nctu\下就可以了

注意: 如果d:\my1下仍然存在B.java则还会报错,因为编译器总是先到A.java本身所在的路径中寻找B.java,虽然编译器找到了B.java,可是对比其package声明之后,认为它应为位于edu\nctu目录下,不该在此目录,因此产生错误信息

结论,对于间接被编译的.java文件,遵从如下规则

1. 该间接文件没有包的,则被直接编译,生成的类文件存放地址和原文件相同

2. 带包的间接文件,要想正确编译,必须明确手动建立包目录结构并且把间接文件置于其内

3. 。。。



2. 运行时的查找路径

    java 是通过 java虚拟机来解释运行的, 也就是通过 java 命令。 javac 编译生成的 .class文件就是虚拟机要执行的代码, 称之为字节码(bytecode), 虚拟机通过 classloader来装载这些字节码, 也就是通常意义上的类. 这里就有一个问题, 类加载器classloader 从哪里知道 java 本身的类库及用户自己的类在什么地方呢? 或者有着缺省值(当前路径).

 

实际上 java 虚拟机是由 java luncher 初始化的, 也就是 java (或 java.exe)这个程序来做的. 虚拟机按以下顺序搜索并装载所有需要的类:

    1, 系统类: 组成 java 平台的类, 包含 rt.jar等类.

    2, 扩展类: 使用 java 扩展机制的类, 都是位于扩展目录($JAVA_HOME/jre/lib/ext)中的 .jar 档案包.

    3, 用户类: 开发者定义的类或者没有使用 java 扩展机制的第三方产品.

 

 

以上的类,程序运行时,是如何找到的? 下面做个说明:

当我们在命令行输入java XXX 的时候,java.exe的工作就是找到合适的JRE来执行类文件。Java.exe依照如下逻辑来寻找JRE:

1. 自己的目录下有没有JRE目录

2. 父目录下的JRE子目录

3. 查询windows Registry(HKEY_LOCAL_MACHINE\Software\JavaSoft\Java Runtime Environment\).

根据以上的逻辑,java找到JRE,进而找到系统类和扩展类(因为它们都位于JRE中,且位置固定),所以“系统类”和“扩展类”的类查找问题就解决了。

 

 

下面再谈谈用户类的查找,用户类路径就是一些包含类文件的目录, .jar, .zip 文件的列表,我们要使用它,必须在命令行中使用 -classpath 选项或者使用 CLASSPATH 环境变量来确定这些类的位置或则按缺省查找,规则如下:

 

* ".", 指当前目录, 是缺省值.

* CLASSPATH 环境变量, 一旦设置, 将缺省值覆盖

* 命令行参数 -cp 或者 -classpath, 一旦指定, 将上两者覆盖.

* 由 -jar 参数指定的 .jar 档案包, 就把所有其他的值覆盖, 所有的类都来自这个指定的档案包中. 由于生成可执行的.jar 文件, 还需要其他一些知识, 比如 package等,对于package,import机制,下一个专题再尝试谈谈.



 

JAVA类路径 - datouuupp的专栏 - 博客频道 - CSDN.NET》

[http://blog.csdn.net/datouuupp/article/details/5344849]

 

Java 类路径

Java 类路径告诉 java 解释器和 javac 编译器去哪里找它们要执行或导入的类。类(您可能注意到的那些 *.class 文件)可以存储在目录或 jar 文件中,或者存储在两者的组合中,但是只有在它们位于类路径中的某个地方时,Java 编译器或解释器才可以找到它们。

 

 Windows 中,类路径中的多个项是用分号分隔( ;)的,而在 UNIX 中,这些项是用冒号分隔( :)的。在以下实例中,类路径中包括两个 Cloudscape jar 文件( cs.jar 和cstools.jar ),以及一个存储 *.class 文件的目录位置( myDevDir ):

Windows 类路径:

c:/Cloudscape_10.0/lib/cs.jar;c:/Cloudscape_10.0/lib/cstools.jar;c:/myPath/myDevDir

 

UNIX 类路径:

/Cloudscape_10.0/lib/cs.jar:/Cloudscape_10.0/lib/cstools.jar:/myPath/myDevDir

 

本文中的其余实例使用的都是 Windows 语法,因此,如果您是在 UNIX 机器上,那么需要对语法进行相应的调整。

 

设置 Java 类路径

有三种方式设置 Java 类路径:

1.永久地,通过在系统级上设置 CLASSPATH 环境变量来实现。

使用控制面板的系统设置来添加名为 CLASSPATH 的新变量,从而永久性地设置 Windows 环境变量。

UNIX 用户可以通过向 .profile 或 .cshrc 文件添加 CLASSPATH 变量来永久设置类路径。

2.临时地,通过在命令窗口或 shell 中设置 CLASSPATH 环境变量来实现。

 Windows 命令窗口中临时设置 CLASSPATH

C:/>set CLASSPATH=%CLOUDSCAPE_INSTALL%/lib/cs.jar;.;

如果是临时设置类路径,那么每次打开新的命令窗口时,都需要再次设置它。

3.在运行时进行,每次启动 Java 应用程序和 JVM,都要指定类路径。

运行时使用 -cp 选项来指定类路径,这里的运行时是指启动应用程序和 JVM 时。

例如

C:/Cloudscape_10.0/demo/programs/simple>java -cp %CLOUDSCAPE_INSTALL%/lib/cs.jar; SimpleApp

 

 

检测问题

常见类路径错误

 

主要有两种类型的类路径问题。第一类问题发生在没有从类路径中找到您试图使用的 Java 类时,此时,它抛出一个 java.lang.ClassNotFoundException 异常。第二类问题发生在找到了您正试图使用的类,但没有找到它所导入的某个类时。本例中,在编译时显示了所导入的类,但在运行时,所导入的类没有包含在类路径中。这将抛出一个 java.lang.NoClassDefFoundError 异常。还有另一种考虑 NoClassDefFoundError 的方式,也就是说,在编译当前执行的类时,所搜索的类定义是存在的,但在运行时却再也无法找到该定义了

 

 

如何可以解决这类问题呢?首先,检查类路径,验证库是否真正位于您认为的地方。例如,在 Windows 中使用该命令来输出类路径:

C:/my_dir>echo %CLASSPATH%

c:/Cloudscape_10.0/lib/cs.jar;c:/Cloudscape_10.0/lib/cstools.jar

然后,在 CLASSPATH 变量中查看每个路径,并用 dir (Windows)或 ls (UNIX)命令查看这些文件是否存在。

如果不知道类位于哪个 jar 文件中,可以用以下命令来检查:

jar -tvf cs.jar | more

该命令产生许多输出。如果正使用 Linux 或 Unix,或者在 Windows 中使用 UNIX 使用程序,那么您可以用 grep 筛选您所查找的类。例如,以下命令将查找 com.ihost.cs.tools.sysinfo 类:

C:/Cloudscape_10.0/lib>jar -tvf cs.jar | grep -i com.ihost.cs.tools.sysin

 

 

posted @ 2015-07-03 23:56  Uncle_Nucky  阅读(681)  评论(0编辑  收藏  举报