包:库单元
在 Java 开发中,开发者不仅仅会使用自己写好的类,也会使用一些别人写好的类库中的类,那么当我们自己写的类名与别人写的类名冲突时,该如何处理呢?或者说如何避免类名的冲突。
首先,了解一下 Java 是如何组织代码的,当编译一个.java
文件时,这个文件中的所有的类都会被编译并且各自生成一个.class
文件,文件名与每个类名一致。所以,可能编译了很少的类,但是生成了大量的.class
类。
Java 的可运行程序是将所有.class
文件打包成一个Jar包
,Java 解释器负责这些.class
文件的查找,装载和解释。
我们将这样的一组java
文件组合成的类库,其中每个文件都有一个 public 类和一些非 public 类。为了声明这些文件为同一组,使用package
来声明:
package access;
public class firstClass{
}
package
语句一定是在java文件的开头第一行,这样,就声明了这个类是在 access 下的,当其他位置要调用这个类的方法时,必须使用 access,或使用import
导入,例如:
//用法1:
public class test(){
public static void main(String [] args){
access.firstClass first = new access.firstClass();
}
}
//用法2
import access.*
public class test2(){
public static void main(String [] args){
firstClass first = new firstClass();
}
}
总结一下 package 和 import 解决的问题
将单一的全局名字空间分割开,如此一来,不管多少人在开发,都不会出现类名冲突。
创建包名
既然上文中说使用关键字package
和import
可以解决类名冲突的问题,那么在创建包的时候,如何命名才能实现所有人开发的类名都不冲突呢?
答案是以Internet
域名作为package
的第一部分,当然,如果没有域名的话,尽量创造不可能与其他人重复的组合。
在确定合理的包名后,需要解决存储的问题,比较合理的做法是将包名映射到操作系统的层次化的文件结构中。因此,第二部分是将包名解析为系统中的一个目录,例如cn.ucc.controller
,对应文件系统中目录:cn/ucc/controller
CLASSPATH 的作用
要理解CLASSPATH
的作用,首先需要清楚 Java 解释器的运行过程:
- 找出环境变量
CLASSPATH
- 编译器将编译时遇到的
import
语句的包名解析成路径 - 将的到的路径与
CLASSPATH
中存储的路径结合 - 得到完整的
.class
文件的路径
由此可以发现,CLASSPATH
的作用是记录类库编译后的文件的根目录,并且可以有多个根目录。如:
CLASSPATH = .;D:\java\lib;C:\develop\simple
值得注意的是,在使用jar包时需要将jar包的完整路径写上,如:
CLASSPATH = .;D:\java\lib;C:\develop\test.jar
举个例子:
package cn.ucc.simple;
public class Vector{
public Vector(){
System.out.println("Vector");
}
}
package cn.ucc.simple;
public class List{
public List(){
System.out.println("List");
}
}
上述两个 Java 类均是在包cn.ucc.simple
中,此时CLASSPATH
的值是:
CLASSPATH = .;D:\java\lib;C:\doc\javat
利用import
关键字使用上述两个类:
import cn.ucc.simple.*;
public class Test{
public static void main(String [] args){
Vector v = new Vector();
List l = new List();
}
}
当编译器遇到import cn.ucc.simple.*;
时,就开始在CLASSPATH
中的根目录下查找子目录cn\ucc\simple
,找出符合的已编译的文件(Vector.class 和 List.class)。
类名冲突
import cn.ucc.simple.*;
import java.util.*
public class Test{
public static void main(String [] args){
Vector v = new Vector();//冲突
List l = new List();
}
}
上面段代码中,Vector 类在 import 的两个包下都存在,因此编译器无从知晓具体是使用哪个,便会报错,这个时候如果需要保留导入的一个包并使用另一个包下的 Vector,可以使用带包名的类:
import cn.ucc.simple.*;
public class Test{
public static void main(String [] args){
java.util.Vector v = new java.util.Vector();//不冲突
List l = new List();
}
}