三、我对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结构的,编译时系统直接产生类文件存放的目录结构(针对package所指定,注意一定要明确指定编译后的路径喔)

    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机制,下一个专题再尝试谈谈. 

        以上错漏之处,请大伙提出,先谢过

摘自:http://topic.csdn.net/u/20090331/11/0D5E721C-0F61-4F60-9C0A-C643F649022D.html

本文链接 https://yanbin.blog/understand-java-classpath/, 来自 隔叶黄莺 Yanbin Blog

[版权声明] Creative Commons License 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。

Subscribe
Notify of
guest

3 Comments
Inline Feedbacks
View all comments
eric
eric
13 years ago

面试问得最多的就是类似的这东西,我估计面试官自己都不清楚。

GreatGhoul
15 years ago

文章很不错,很适合我们读

隔叶黄莺
15 years ago

我也觉得很实用,好理解,所以从 CSDN 里摘了过来