Java的import和package机制

在编译的java源文件(.java)时,编译器会根据环境变量或者javac的-cp属性指出的参数建立类路径引用表。其中环境变量和-cp参数不会叠加,如果指定了cp参数,环境变量将失效。如果两者都没有,则默认以当前目录(.)为类引用表的路径.

 

如果源文件中有import指令,则会检查类引用表有没有指定的目录。如果没有则会报错,如果,则会根据import的是具体的类,则会建立类引用表,如果导入的是整个包(*,则会建立相对类引用表

 

有了以上三张表,在编译的源文件时,出现的类会有下面几种情况:

 

1)类的全名。直接在类引用表中查找这个类,如果存在源文件,而不存在*.class文件,就对源文件进行编译(这就是类似make的机制);如果存在类文件,就继续编译。如果类引用表中没有这个类,则会对相对类引用表中相应的项与类路径引用表组合,查找这个类。如果找到源文件还要对其进行编译。

 

2)只是单独的一个类名。则会搜索类路径引用表下的存在相对类引用表中路径的类,如果找到源文件,进行编译,找到类文件继续编译,找不到报错。

 

 

使用相对类引用表,也有人称为按需导入,只有使用到的类才会用到,但是在搜索的时候会把所有可能的路径都进行搜索,以确定是否有类冲突。对于使用效率,说法不一,《java深度历险》一书上说,java有相应的算法,不会影响到使用效率,而在网上看到的一些资料,说会影响效率。不知道哪一种是对的,但是有一点是确定的,使用按需导入命名冲突是有可能发生的。

 

 

编译之后class文件中已经没有了importpackage,所以的类都以类全名出现。

 

java的import机制与C++中的#include是不同的,而是相当于namespace。因为import导入的是路径不会递归,所以只能使用一个*作为通配符,而不能使用import some.*.*;

 

如果一个类文件中写了package,如:

 

package hk;

public class HK {

public static void main(String[] args) {

         HK hk = new HK();

         System.out.println("HK is a good boy");

}

}

 

这样即使HK.java不在hk这个目录下,直接在HK.java所在的目录下进行编译,也不会有问题,因为此时只是对HK中的代码进行解析并不会加载HK这个类,即使在类中创建了HK的对象,在编译的时候也只会简单的把HK替换成hk/HK。但是如果试图运行java HK,则会报错,找不到hk\HK,因为此时会在hk的目录下寻找HK.class

 

java中的动态,如果一个类A引用了另一个类B,在编译之后,可以把B.class随便替换,而不需要重新编译A,就可以直接运行。在《超越Java》中针对这种动态对Java进行了批判,说Java不够动态,Ruby会好很多。

 

一个简单的例子:

源文件开始的注释有文件所在的路径,所有源文件都在在test目录及其子目录下

 

//:test/Test.java

import com.hk.*;

import com.hk.hking.HKing;

public class Test {

    public static void main(String[] args) {

        HK hk = new HK();

        System.out.println("HK:");

        hk.say();

      

        HKing hking = new HKing();

        System.out.println("HKing:");

        hking.say();

    }

}

 

 

//:test/package/com/hk/HK.java

package com.hk;

public class HK {

    public void say() {

        System.out.println("I am a good boy!");

    }

}

 

 

//:test/package/com/hk/hking/HKing.java

package com.hk.hking;

public class HKing {

    public void say() {

        System.out.println("I am HK's nickname!");

    }

}

 

如果直接在Test.java所在路径下用javac Test.java则会出错,此时必须指明cp路径

即:javac -cp . ; package Test.java  //表示有2cp路径用;隔开

其中当前目录(.)也可以省略,因为Test中没有引用当前目录下的类,如果有,当前路径是必须的。

首先,通过-cp指定的路径建立类路径引用表

 

++++++++++++

+ .                  +

++++++++++++

+ package    +

++++++++++++

 

然后通过import分别建立类引用表

 

+++++++++++++++++++++

+ com.hk.hking.HKing      +

+++++++++++++++++++++

 

 

对类引用表:

 

+++++++++++++++

+ com.hk.*           +

+++++++++++++++

 

这三个表都是有顺序的。

 

遇到HK,首先去当前目录package目录下查找,没有;然后查看类引用表,没有HK这个类;然后到./com/hk/下查找,因为当前目录下没有com,所以找不到;然后到./package/com/hk/查找,找到HK.java编译为HK.class.

 

遇到HKing,还是先到当前目录和package目录下查找,没有;然后查看类引用表,然后把HKing.java编译为HKing.class。

 

运行则需要用java -cp .;package Test,此时的(.)是必须的

运行时.class文件中的类都已经成了全名HKcom/hk/HK,,HKingcom/hk/hking/HKing,这种只是给出了相对路径,-cp指定的路径是指明去哪里搜索这些相对路径。

 

总结:

 

1、类文件一定要放在所在的包指出的目录下

 

2、编译时直接到源文件所在目录编译即可但是要指明-cp

 

3、运行编译后的文件也要指明-cp如果运行的类是在包里,编译时应该指明包名。(这一点未作说明,如:java com.test.Test)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值