我们使用应用程序编程接口(API)来说明抽象数据类型的行为。它将列出所有 构造函数 和 实例方法(即操作)并简要描述它们的功用,如表 1.2.1 中 Counter 的 API 所示。
尽管数据类型定义的基础是一组值的集合,但在 API 可见的仅是对它们的操作,而非它们的意义。因此,抽象数据类型的定义和静态方法库(请见 1.1.6.3 节)之间有许多共同之处:
两者的实现均为 Java 类;
实例方法可能接受 0 个或多个指定类型的参数,由括号括起并由逗号分隔;
它们可能会返回一个指定类型的值,也可能不会(用 void 表示)。
当然,它们也有三个显著的不同。
API 中可能会出现若干个名称和类名相同且没有返回值的函数。这些特殊的函数被称为 构造函数。在本例中, Counter 对象有一个接受一个 String 参数的构造函数。
实例方法不需要 static 关键字。它们 不是 静态方法——它们的目的就是操作该数据类型中的值。
某些实例方法的存在是为了尊重 Java 的习惯——我们将此类方法称为 继承的方法 并在 API 中将它们显示为灰色。
表 1.2.1 计数器的 API
public class Counter`` Counter(String id)创建一个名为 id 的计数器 void increment()将计数器的值加 1 int tally()该对象创建之后计数器被加 1 的次数 String toString()对象的字符串表示
和静态方法库的 API 一样,抽象数据类型的 API 也是和用例之间的一份契约,因此它是开发任何用例代码以及实现任意数据类型的起点。在本例中,这份 API 告诉我们可以通过构造函数 Counter()、实例方法 increment() 和 tally(),以及继承的 toString() 方法使用 Counter 类型的对象。
1.2.1.2 继承的方法
使用引用类型的赋值语句将会创建该引用的一个副本。赋值语句不会创建新的对象,而只是创建另一个指向某个已经存在的对象的引用。这种情况被称为 别名:两个变量同时指向同一个对象。别名的效果可能会出乎你的意料,因为对于原始数据类型的变量,情况不同,你必须理解其中的差异。如果 x 和 y 是原始数据类型的变量,那么赋值语句 x = y 会将 y 的值复制到 x 中。对于引用类型,复制的是 引用(而非实际的值)。在 Java 中,别名是 bug 的常见原因,如下例所示(图 1.2.4):