Java、Javac、Javadoc查找class路径总结

这两天在用Eclipse编译文件的时候遇到些class无法找到的问题,于是想重新学习java查找class的机制。本文内容参考官方文档Java Tuturial How Classes are Found和Setting the Class Path。

1、Java加载类

Java 按照加载顺序将类分为三种:引导类、扩展类和用户类,分别依次载入。

  • 引导类是如rt.jar等共同构成Java平台的关键Jar文件
  • 扩展类是通过Java扩展机制创建的Jar文件,位于$JAVA_HOME/jre/lib/ext
  • 用户类是开发者或第三方未按照Java扩展机制创建的类(大部分情况属于此)

引导类与扩展类一般不必设置加载路径,所以本文重点讨论用户类。

注意: tools.jar现在必须在包含在用户类路径中,否则无法使用。

用户类路径设置

用户类在使用时必须引用用户类路径(user class path),以完成后缀为jar、class、zip的类文件的引用。用户类路径有以下几种设置方式:

  • 默认值 . 表示当前编辑文件路径。(不必设置,只要当前编辑路径下的同包或非包类文件都可以自动加载)
  • CLASSPATH环境变量可以覆盖前者,这个就不多说了,Linux和Windows系统环境变量设置在网上都可以查到。
  • -cp/-classpath选项 Java程序选项,可以覆盖CLASSPATH,用户在命令行状态下使用Java程序时可以作为一些非包类查找路径。
  • -jar选项 这个比较特殊,在该选项下,所有使用的类必须包含在该jar文件中。

下面详细说下 -cp选项 设置要点。
-cp选项可以在不更改环境变量的情况下配置用户类查找路径。jar文件、zip文件和class文件设置方法不尽相同。

  • jar文件或zip文件 路径必须以文件名结尾,如需引用当前目录下mydir文件夹下的myclass.jar文件,则命令为 java -cp ./mydir/myclass xx。
  • 非包class文件 路径必须为包含该类文件的文件夹路径,如需引用当前目录下mydir文件夹下的myclass.class,则命令为 java -cp ./mydir xx。
  • 包class文件 路径必须为该包的根目录,如该包为online.sanbao,则命令为 java -cp ./online xx

2、Javac和Javadoc加载类

Javac和Javadoc以相似的方式加载类,不过有以下几点不同:

  • 如果在类文件和源文件中均定义了引用的类,javadoc总是使用源文件而javac使用类文件,但根据既定规则自动重新编译它认为过时的任何类文件。自动重新编译的规则记录在用于Windows或Unix的javac文档中。
  • 默认情况下,javac和javadoc会在用户类路径下查找待加载的源文件和类文件。但如果指定了-sourcepath选项,javac和javadoc仅在指定的源文件路径上搜索源文件,而在用户类路径中搜索类文件。

3、举例说明

本机CLASSPATH变量设置如图1,主要包括.(当前编辑目录)、dt.jar文件、tools.jar文件和/root/workspace(工作目录)四个类路径。
Java、Javac、Javadoc查找class路径总结_第1张图片

情况一:当两个文件都是非包且位于同一个文件夹下
首先,在test目录下建立Test.java和myclass.java文件,如图2所示。
Java、Javac、Javadoc查找class路径总结_第2张图片

Test.java 内容如下:

public class Test{
     public static void main(String[] args){
        Myclass myclass =  new Myclass();
        System.out.println("本例用来测试用户类是否试着成功。");  
   }
}

Myclass.java内容如下:

 public class Myclass{
    Myclass(){
        System.out.println("这是一个Myclass实例。");
    }
}

运行结果如图3所示:
Java、Javac、Javadoc查找class路径总结_第3张图片

简单分析:当运行 javac Test.java 时,由于没有-cp和-sourcepath选项,此时CLASSPATH变量生效,javac依次在CLASSPATH变量所指的路径查找Myclass类和源码,因此在当前目录(找到Myclass会不会停止查找有待考证)下找到Myclass源码,但并未找到Myclass类,于是分别对Test.java和Myclass.java文件进行编译,生成Myclass.class和Test.class文件,这里有个细节,仔细查看Myclass.class和Test.class文件修改时间可以发现,先生成Test.java然后生成Myclass.class,这点是和C++不同的地方。然后java依据相同逻辑查找类并运行。

情况二:当非包文件属于两个不同文件夹
首先,在当前目录下创建子文件夹 subDirectory,然后将Myclass.java移动至该子文件夹。
有两种解决方案:一是利用设置-cp选项,这样可以指定classpath,类似情况一,具体如图4。
Java、Javac、Javadoc查找class路径总结_第4张图片

注意:-cp选项下,对于.class文件需选择该文件所在文件夹,不包含文件名;另外,在运行java命令时,需指明所有类路径,包括当前路径和Myclass.class文件所在路径。

二是java命名空间查找class路径。
此时,如果直接用javac编译会提示错误,如图5所示。因为这违反了java关于命名空间的规则,在不使用-cp选项的情况下,若想引用其他文件夹的类,必须使用package/import规则。
Java、Javac、Javadoc查找class路径总结_第5张图片

因此,修改Myclass.java文件和Test.java文件。

//定义包名;
package subDirectory;
public class Myclass{
    //注意修改构造函数权限为public,因为已属于不同的包;
    public Myclass(){
    System.out.println("这是Myclass的一个实例。");
    } 
}
import  subDirectory.Myclass;
public class Test{
     public static void main(String[] args){
        Myclass myclass =  new Myclass();
        System.out.println("本例用来测试用户类是否试着成功。");  
   }
}

再次运行结果如图6。
Java、Javac、Javadoc查找class路径总结_第6张图片


[1]http://docs.oracle.com/javase/8/docs/technotes/tools/findingclasses.html
[2]https://docs.oracle.com/javase/8/docs/technotes/tools/windows/classpath.html#CBHHCGFB

你可能感兴趣的:(生活)