第三章:设计问题之封装
天下维客,你可以修改的网络知识库
目录 |
什么是封装
库应该是一种紧凑的自适应单元,而不是一种功能和关系不明确的对象的松散集合。
使库变成自适应的操作被称作封装。
什么是包
Java 语言为类文件级别封装提供了一个显式机制:包。包是一组存储在一个单独目录中的 Java 类;包有它自己的名称空间。
给一组类其自己的名称空间的优点是不必担心名称空间冲突。
在这个示例中,主类有一个相当普通的名称 -- Server。如果我们最后遇到另一个库中同名的类,不要感到惊奇。将类放到它自己的名称空间中可以解决由于名称引起的冲突。
在以后几屏中,我将说明如何将一个类放入包中。
包具有名称
每个包都有一个名称,这个名称由一组用点分隔的字符串组成,如 java.lang 或 javax.swing.plaf.basic。
实际上,任何类的全名都包含了它的包名称,后面跟着它自己的名称,如 java.lang.Object 或 javax.swing.plaf.basic.BasicMenuBarUI。
请注意,有一个特殊包称作缺省包。如果没有将类放到某个特定包中,那么会假设这个类在缺省包中。
包名称对应于目录
每个包都直接映射到文件系统中的一个子目录。这种对应关系让 Java 虚拟机 (JVM) 可以在运行时找到类。
通过将点替换成 "/"(或者操作系统用于分隔目录名的符号),可以将包名称转换成子目录路径。例如,java.lang.Object 存储在文件 java/lang/Object.java 中。
缺省包中的类被放置在当前目录中。
类声明了它们的包
为确保类在正确的包和正确的目录中,类必须声明它所在的包。
声明如下:
// Server.java
package mylib;
public class Server implements Runnable {
// ...
其它类可以导入包
如果要使用另一个包中的类,可以利用其全名来引用它,如 mylib.Server。例如:
mylib.Server server = new mylib.Server( portNum );
输入类的完整包名称可能很麻烦,因此可以使用快捷方式,按以下方式导入包:
import mylib.*;
// ...
Server server = new Server( portNum );
还可以导入单个类:
import mylib.Server;
// ...
Server server = new Server( portNum );
选择公有类
Java 语言还可以让您决定在包外部可以看见包中的哪些类。
公有类可以被任何其它包中的代码访问,而私有类只能在其自己的包中使用。
只应该使那些需要人们直接使用的类成为公有类。
为公有类设计接口需要比为私有类设计接口更小心,因为必须精心设计公有类的接口,以使用户可以清楚地了解这个接口。私有类则不必有一个清楚的接口。
要使类成为公有类,需要在类声明的第一行中使用 public 关键字:
// Server.java
package mylib;
import java.io.*; import java.net.*;
public class Server implements Runnable {
要使类成为私有类,只要去掉 public 关键字。在 Server 示例中,在称为 Reporter 的相同包中有一个私有类,它定期报告 Server 对象的情况。以下就是它的声明:
// Reporter.java
package mylib;
class Reporter implements Runnable {
封装总结
可以看到,Java 语言提供了一些特别为定义代码边界而创建的功能。
通过将代码划分到各个包中,并将类定义成公有类或私有类,可以确切地决定当用户使用库时他们必须处理什么问题。


