Java中的包

Java包是一种将彼此相关的Java类组合成同一个“模块”(包)的机制。当Java项目(例如一个应用程序或API)变得越来越大时,将代码拆分成多个Java类,再将这些类拆分成多个Java包是非常有用的。当你将类分成多个Java包时,你很容易找出某个类。

Java包就像文件系统中的一个目录。实际上,在磁盘上一个包就是一个目录。属于同一个包的所有Java源文件和类文件都位于相同的目录中。

Java包可以包含子包。 Java包可以组成所谓的包结构。Java包结构就像一个目录结构。它是由包,子包和类构成的树。 Java包结构就像硬盘上的目录或者是在压缩文件(zip/jar)中目录。

以下是一个Java包结构示例的截图:

在顶部你会看到一个名为“src”的目录。这是源根目录。它本身不是Java包。在这个目录下,所有的子目录都对应Java包。因此,“collections”,“com”,“concurrency”等都是Java包(也是磁盘上的目录)。在上面的截图中,Java软件包用文件夹图标来表示。

我已经扩展了两级Java程序包,所以你可以看到里面的类。在上面的屏幕截图中,这些类用一个带有C的小蓝圈来表示。

一个子包的完整路径是它的名字,所有的祖先包名都在它的前面,用点分开。例如,“navigation”子包的完整路径是:

com.jenkov.navigation

同样,Java类的完全限定名称也包含它的包名称。例如,“Page”类的完全限定名称是:

com.jenkov.navigation.Page

创建一个Java包结构

要创建Java包,你必须首先在你的硬盘上创建一个源根目录。根目录本身不是包结构的一部分。根目录包含所有需要进入包结构的Java源代码。

一旦你创建了一个源代码根目录,你可以开始向它添加子目录。每个子目录对应一个Java包。你可以在子目录中添加子目录以创建更深层次的包结构。

在包里面添加类

为了把Java类添加到包中,你必须做两件事:

  1. 将Java源文件放进与要放入类的Java包相匹配的目录中。
  2. 将该类声明为包的一部分。
  3. 将Java源文件放入与包结构相匹配的目录结构中,非常简单。只需创建一个源代码根目录,并在其中递归地为每个包和子包创建目录。将类文件放到与要添加到的包相匹配的目录中。

当你把你的Java源文件放到正确的目录(匹配类应该属于的包)时,你必须在那个类文件中声明它属于那个Java包。以下是如何在Java源文件中声明包的示例:

package com.jenkov.navigation;

public class Page {
    ...
}

上面的代码的第一行是声明类Page属于包com.jenkov.navigation

Java包命名约定

Java包总是以小写字母命名。也不像Java类那样第一个字母需要大写字母。

为避免创建的包与其他公共Java包重名,建议你使用公司的反向域名作为包层次结构的开始部分。例如,由于我公司的域名是jenkov.com,我应该从一个名为com.jenkov的包结构开始。换句话说,一个名为com的顶层包,里面有一个叫做jenkov的子包。

从其他Java包中导入类

如果A类需要使用类B,则必须在类A中引用类B.如果类A和B位于相同的Java包中,则Java编译器将接受这两个类之间的引用。示例如下:

public class B {

    public void doIt() {
        // do something...
    }
}
public class A {

    public static void main(String[] args){
        B theBObj = new B();

        b.doIt();
    }
}

如果类A和类B位于相同的Java包中,则上面的代码没有问题。但是,如果A类和B类位于不同的Java包中,则A类必须导入B类才能使用它。示例如下:

import anotherpackage.B;

public class A {

    public static void main(String[] args){
        B theBObj = new B();

        b.doIt();
    }
}

示例代码中的第一行导入类B.该示例假定类B位于名为anotherpackage的Java包中。

如果B类位于另一个包的子包中,则必须列出完整的包和B类的子包路径。例如,如果B类位于包anotherpackage.util中,那么导入语句如下所示:

import anotherpackage.util.B;

从其他包中导入所有类

如果你需要使用某个Java包中的许多类,则一次导入一个类会导致大量的导入语句。可以使用*字符而不是类名来导入所有类的包。示例如下:

import anotherpackage.util.*;

通过完全限定类名使用类

可以不用导入语句来使用另一个包中的类。你可以通过书写其完全限定的类名,而不仅仅是类本身的名称来使用它。完全限定的类名由完整的包路径到包含该类的子类组成,还包括类名称本身。完全限定的类名也是你在导入语句中写的那样。例如:

anotherpackage.util.TimeUtil;

你可以使用这个完全合格的类名来引用它里面的TimeUtil类,如下所示:

public class A {

    public static void main(String[] args){

        anotherpackage.util.TimeUtil timeUtil = 
            new anotherpackage.util.TimeUtil();

        timeUtil.startTimer();
    }
}

怎样将你的类拆分进合适的包中

你可能想知道如何确定创建哪些Java包,以及如何将你的类划分进这些包。对此没有官方的标准,但有两种常用的方法。

按层拆分

第一种方法是根据类所属的应用程序的“层”划分。例如,你的应用程序可能有一个数据库层。然后你会创建一个database包。所有涉及与数据库通信的类都将位于database包中。

按程序功能划分

第二种方法是根据它们属于应用程序的功能来划分。如果你的应用程序具有计算养老金的功能部分,可以创建一个名为pension的Java包。所有与养老金计算相关的类都可以划分到该包中。

结合我的域名,pension包的结构将是:

com.jenkov.pension

共有三个包,其中两个嵌套在其他包内(jenkov在com包里面,pension包在jenkov包里面)。

随着你的应用程序中的类不断增加,按功能划分会比按层划分更好。在固定数量的层次包中不断增加类的做法并不好,相反在不断增加的功能包里面添加少量的类的做法更为合适。按功能拆分类是我和我大多数同事采取的做法。

内建的Java包

Java平台带有许多内置的Java软件包。这些软件包包含程序员经常需要的各种用途的类,比如从本地硬盘读写文件,通过网络和互联网发送和接收数据,连接到数据库以及许多其他的东西。我已经在单独的教程中介绍了许多这些包(API)。如果你去我的教程网站的首页查看。

下一篇:Java访问修饰符

results matching ""

    No results matching ""