Java 简明教程

Java - Packages

Java Packages

在 Java 中使用 *Packages*是为了防止命名冲突、控制访问权限、使查找/定位和使用类、接口、枚举和注释等更轻松。

可以 将 Java package 定义为相关类型( classesinterfacesenumerations 和注释)的分组,提供访问保护和命名空间管理。

Types of Java Packages

Java 包分为两种类型:

  1. Built-in Java Packages

  2. User-defined Java Packages

Java 中一些现存的包有:

  1. java.lang − 汇集基本类

  2. java.io − 此包中汇集输入输出函数类

User-defined Java Packages

你可以定义自己的包来汇集类/接口等等。按你实现的相关类进行分组是一种好做法,以便程序员可以轻松确定类、接口、枚举和注解是相关的。

由于包创建了一个新的名称空间,因此不会与其他包中的名称发生名称冲突。使用包,可以更轻松地提供访问控制,也可以更轻松地找到相关类。

Creating a Java Package

创建包时,你应当为包选择一个名称,并在包中想要包含的类、接口、枚举和注解类型的每个源文件的顶部包含一条 package 语句。

包语句应当是源文件中的第一行。每个源文件中只能有一个包语句,它适用于文件中的所有类型。

如果未使用包语句,则类、接口、枚举和注解类型将放置在当前默认包中。

Compiling with Java Package

若要编译带包语句的 Java 程序,你必须按如下所示使用 -d 选项。

javac -d Destination_folder file_name.java

然后在指定的目标位置创建一个带有给定包名称的文件夹,并将编译的类文件放置在该文件夹中。

Java Package Example

我们来看一个创建名为 animals 的包的示例。最好使用小写字母作为包的名称,以避免与类和接口的名称发生冲突。

以下包示例包含名为 animals 的接口:

/* File name : Animal.java */
package animals;

interface Animal {
   public void eat();
   public void travel();
}

现在让我们在同一包 animals 中实现上述接口:

package animals;
/* File name : 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();
   }
}

interface Animal {
   public void eat();
   public void travel();
}

现在按如下所示编译 java 文件:

$ javac -d . Animal.java
$ javac -d . MammalInt.java

现在在当前目录中将创建一个名称为 animals 的包/文件夹,并将这些类文件放置其中,如下所示。

packages

你可以在包中执行类文件并获取如下所示的结果。

Mammal eats
Mammal travels

Importing Java Package

如果某个类想要使用同一包中的另一个类,则不必使用包名称。同一包中的类可在没有任何特殊语法的条件下找到彼此。

Example

在这里,名为 Boss 的一个类被添加到已包含 Employee 的 payroll 包中。然后 Boss 可引用 Employee 类,而无需使用 payroll 前缀,如下面的 Boss 类所示。

package payroll;
public class Boss {
   public void payEmployee(Employee e) {
      e.mailCheck();
   }
}

如果 Employee 类不在 payroll 包中会发生什么?现在 Boss 类必须使用以下技巧之一来引用一个在另一个包中的类。

  1. 可以使用该类的完全限定名称。例如 −

payroll.Employee
  1. 该包可使用 import 关键字和通配符 (*) 导入。例如 −

import payroll.*;
  1. 可以使用 import 关键字导入该类本身。例如 −

import payroll.Employee;

Example

package payroll;

public class Employee {
   public void mailCheck() {
      System.out.println("Pay received.");
   }
}

Example

package payroll;

import payroll.Employee;

public class Boss {
   public void payEmployee(Employee e) {
      e.mailCheck();
   }

   public static void main(String[] args) {
      Boss boss = new Boss();
	   Employee e = new Employee();
      boss.payEmployee(e);
   }
}
Pay received.

Note − 一个类文件可包含任意数量的 import 语句。这些 import 语句必须出现在 package 语句之后并出现在类声明之前。

Directory Structure of a Java Package

将一个类放入一个包中时,会产生两个主要结果 −

  1. 正如我们在上一节中讨论的,该包的名称变成该类的名称的一部分。

  2. 包的名称必须与包含相应字节码的目录结构匹配。

下面是一种管理你在 Java 中的文件的简单方法 −

将类的源代码、接口、枚举或注释类型放入一个文本文件中,其名称是该类型的简单名称,其扩展名为 .java

例如 -

// File Name :  Car.java
package vehicle;

public class Car {
   // Class implementation.
}

现在,将该源文件放到一个目录中,其名称反映了该类所属的包的名称 −

....\vehicle\Car.java

现在,限定类名和路径名如下 −

  1. Class name → vehicle.Car

  2. 路径名 → vehicle/Car.java(在 Windows 中)

通常情况下,一家公司会使用它反转的互联网域名作为其包名称。

Example − 一家公司的互联网域名是 apple.com,那么它所有的包名称都将以 com.apple 开头。包名的每个部分对应于一个子目录。

Example − 该公司有一个 com.apple.computers 包,它包含一个 Dell.java 源文件,它会被包含在这个一系列的子目录中 −

....\com\apple\computers\Dell.java

在编译时,编译器会为其中定义的每个类、接口和枚举创建一个独立的输出文件。该输出文件的基名是该类型的名称,而它的扩展名为 .class

例如 -

// File Name: Dell.java
package com.apple.computers;

public class Dell {
}

class Ups {
}

现在,使用 -d 选项编译这个文件,如下 −

$javac -d . Dell.java

文件将按如下方式编译 −

.\com\apple\computers\Dell.class
.\com\apple\computers\Ups.class

你可以按如下方式导入在 \com\apple\computer\ 中定义的所有类或接口 −

import com.apple.computers.*;

与 .java 源文件类似,编译的 .class 文件应位于一系列反映包名的目录中。但是,通往 .class 文件的路径不必与通往 .java 源文件的路径相同。你可以单独排列你的源文件和类目录,如下 −

<path-one>\sources\com\apple\computers\Dell.java

<path-two>\classes\com\apple\computers\Dell.class

通过执行此操作,可以在不透露你的源代码的情况下,让其他程序员访问 classes 目录。你同样需要管理源代码和类文件,以便编译器和 Java 虚拟机 (JVM) 可以找到你的程序所使用的所有类型。

classes 目录的完整路径 <path-two>\classes 称为类路径,并使用 CLASSPATH 系统变量进行设置。编译器和 JVM 都通过向类路径中添加包名称,来构建到 .class 文件的路径。

假设 <path-two>\classes 是类路径,并且包名称为 com.apple.computers,那么编译器和 JVM 会在 <path-two>\classes\com\apple\computers 中寻找 .class 文件。

一个类路径中可包含多个路径。多个路径应使用分号(Windows)或冒号(Unix)分隔。默认情况下,编译器和 JVM 会搜索当前目录和包含 Java 平台类的 JAR 文件,以便这些目录自动位于类路径中。

Set CLASSPATH System Variable

要显示当前的 CLASSPATH 变量,请在 Windows 和 UNIX(Bourne shell)中使用以下命令:

  1. 在 Windows 中 → C:> set CLASSPATH

  2. 在 UNIX 中 → % echo $CLASSPATH

要删除 CLASSPATH 变量的当前内容,请使用:

  1. 在 Windows 中 → C:> set CLASSPATH =

  2. 在 UNIX 中 → % unset CLASSPATH; export CLASSPATH

要设置 CLASSPATH 变量,请使用:

  1. 在 Windows 中 → set CLASSPATH = C:\users\jack\java\classes

  2. 在 UNIX 中 → % CLASSPATH = /home/jack/java/classes; export CLASSPATH