在Java中使用包是为了防止命名冲突,控制访问,使类,接口,枚举和注释的搜索/定位和使用更容易等。
可以将包定义为提供访问保护和命名空间管理的相关类型(类,接口,枚举和注释)的分组。
Java中的一些现有常用包是 -
java.lang
- 捆绑基础类。java.io
- 输入,输出函数的类捆绑在此包中。
程序员可以定义自己的包来捆绑类/接口组等。最好对实现的相关类进行分组,以便程序员可以轻松确定类,接口,枚举和注释是否相关。
由于包创建了一个新的命名空间,因此与其他包中的名称不会有任何名称冲突。 使用包将提供访问控制更容易,并且更容易找到相关的类。
1. 创建包
创建包时,应该为包选择一个名称,并在每个源文件的顶部包含一个包语句以及该名称,该文件包含要包含在包中的类,接口,枚举和注释类型。
package
语句应该是源文件中的第一行。 每个源文件中只能有一个package
语句,它适用于文件中的所有类型。
如果未使用package
语句,则类,接口,枚举和注释类型将放在当前的默认包中。
要使用package
语句编译Java程序,必须使用-d
选项,如下所示。
javac -d Destination_folder file_name.java
在指定的目标中创建具有给定包名称的文件夹,并将编译的类文件放在该文件夹中。
示例
下面来看看创建一个名为animals
包的示例。 包的名称最好使用小写字母,以避免与类和接口的名称发生冲突。
以下包示例中有一个animals
的接口 -
/* 文件 : Animal.java */
package animals;
interface Animal {
public void eat();
public void travel();
}
接下来,在同一个包(animals
)中实现上面的接口 -
package animals;
/* 文件 : MammalInt.java */
public class MammalInt implements Animal {
public void eat() {
System.out.println("Mammal eats");
}
public void travel() {
System.out.println("Mammal travels");
}
public int noOfLegs() {
return 0;
}
public static void main(String args[]) {
MammalInt m = new MammalInt();
m.eat();
m.travel();
}
}
将上面两个文件保存在目录:D:\worksp\java\package 下,然后编译上面两个java文件,如下所示 -
D:\worksp\java\package>javac -d . Animal.java
D:\worksp\java\package>javac -d . MammalInt.java
将在当前目录中创建名为animals
的包/文件夹,这些类编译后生成的文件将放在这个目录中,如下所示 -
可以在包中执行类文件,并得到如下结果 -
D:\worksp\java\package>java animals.MammalInt
Mammal eats
Mammal travels
2. import关键字
如果某个类想要在同一个包中使用另一个类,则不需要使用包名。同一个包中的类相互引用不需要特殊语法。
示例
在下面示例中,将Boss
类添加到已包含Employee
类的payroll
包中。 然后,Boss
可以在不使用payroll
前缀的情况下引用Employee
类,如下面的Boss
类所示。
package payroll;
public class Boss {
public void payEmployee(Employee e) {
e.mailCheck();
}
}
如果Boss
类不在payroll
包中,会发生什么? Boss
类必须使用以下一种方法来引用不同包中的类。
使用该类的完全限定名称。例如 -
payroll.Employee
使用
import
关键字和通配符(*
)导入包。例如 -import payroll.*;
使用
import
关键字导入类名称。例如 -import payroll.Employee;
注 - 类文件可以包含任意数量的
import
语句。import
语句必须出现在package
语句之后和类声明之前。
3. 包的目录结构
将类放入包时会出现两个主要结果 -
- 包的名称成为类名称的一部分,如在上面讨论的那样。
- 包的名称必须与相应字节码所在的目录结构相匹配。
以下是使用Java管理文件的简单方法 -
将类,接口,枚举或注释类型的源代码放在文本文件中,文件的名称是类的名称,扩展名为.java
。
例如 -
// 文件名称 : Car.java
package vehicle;
public class Car {
// 类的实现
}
现在,将源文件放在一个目录中,该目录的名称反映了类所属的包的名称 -
....\vehicle\Car.java
现在,限定类名和路径名如下 -
- 类名称 ->
vehicle.Car
- 路径名称 ->
vehicle\Car.java
(在windows中)
通常,公司或组织使用它们的反向域名作为包名。
示例 - 公司的域名是:yiibai.com
,那么所有包名都将以com.yiibai
开头。包名称的每个组件对应一个子目录。
示例 - 公司有一个包含Dell.java
源文件的com.yiibai.computers
包,它将包含在这样的一系列子目录中 -
....\com\yiibai\computers\Dell.java
在编译时,编译器为其中定义的每个类,接口和枚举创建不同的输出文件。 输出文件的基本名称是类的名称,其扩展名为.class
。
例如 -
// 文件名称: Dell.java
package com.yiibai.computers;
public class Dell {
}
class Ups {
}
使用-d
选项编译此文件如下 -
D:\worksp\java\package> javac -d . Dell.java
编译成功后,创建以下文件 -
D:\worksp\java\package\com\yiibai\computers\Dell.class
D:\worksp\java\package\com\yiibai\computers\Ups.class
可以导入com\yiibai\computers\
中定义的所有类或接口,如下所示 -
import com.yiibai.computers.*;
与.java
源文件一样,已编译的.class
文件应位于一系列反映包名称的目录中。 但是,.class
文件的路径不必与.java
源文件的路径相同。可以单独指定源代码和类目录,如下所示 -
<path-one>\sources\com\yiibai\computers\Dell.java
<path-two>\classes\com\yiibai\computers\Dell.class
通过这样做,可以在不泄露源代码的情况下向其他程序员提供对classes
目录的访问。还需要以这种方式管理源文件和类文件,以便编译器和Java虚拟机(JVM)可以找到程序使用的所有类型。
classes
目录的完整路径<path-two>\classes
,称为类路径,并使用CLASSPATH
系统变量进行设置。编译器和JVM都通过将包名称添加到类路径来构造.class
文件的路径。
假设<path-two>\classes
是类路径,包名是com.yiibai.computers
,那么编译器和JVM将在<path-two>\classes\com\apple\computers
中查找.class
文件。
类路径可以包括多个路径。应使用分号(Windows)或冒号(Unix)分隔多个路径。 默认情况下,编译器和JVM搜索当前目录和包含Java平台类的JAR文件,以便这些目录自动位于类路径中。
4. 设置CLASSPATH系统变量
要显示当前的CLASSPATH
变量,请在Windows和UNIX(Bourne shell)中使用以下命令 -
- 在Windows系统中,使用:
set CLASSPATH
- 在UNIX系统中,使用:
echo $CLASSPATH
要删除CLASSPATH
变量的当前内容,请使用 -
- 在Windows系统中,使用:
set CLASSPATH =
- 在UNIX系统中,使用:
unset CLASSPATH; export CLASSPATH
要设置CLASSPATH
变量,请使用 -
- 在Windows系统中,使用:
set CLASSPATH = C:\users\yiibai\java\classes
- 在UNIX系统中,使用:
CLASSPATH = /home/yiibai/java/classes; export CLASSPATH