14.3 继承

至此,我们定义了一个表示扑克牌集合的类,下面用它定义 DeckHand 类。Deck 类的完整定义如下:

  1. public class Deck extends CardCollection {
  2. public Deck(String label) {
  3. super(label);
  4. for (int suit = 0; suit <= 3; suit++) {
  5. for (int rank = 1; rank <= 13; rank++) {
  6. cards.add(new Card(rank, suit));
  7. }
  8. }
  9. }
  10. }

第 1 行用关键词 extends 指出 Deck 类扩展了 CardCollection 类,这意味着 Deck 对象将包含 CardCollection 对象的所有实例变量和方法。换而言之,Deck“继承”了 CardCollection。我们还可以说 CardCollection 是一个超类(superclass),而 Deck 是其子类。

在 Java 中,类只能扩展一个超类。没有用 extends 指定超类的类将自动继承 java.lang.Object。因此,在这个实例中,Deck 扩展了 CardCollection,而 CardCollection 扩展了 ObjectObject 类提供了默认方法 equalstoString 等。

构造函数不被继承,但所有其他的公有属性和方法都被继承。到目前为止,Deck 中新增的唯一一个方法是构造函数,因此你可像下面这样创建 Deck 对象:

  1. Deck deck = new Deck("Deck");

Deck 构造函数的第 1 行使用了以前没有介绍过的 super,这是一个关键词,指的是当前类的超类。像这里这样将 super 用作方法时,将调用超类的构造函数。

因此在这里,super 调用 CardCollection 的构造函数,而这个构造函数初始化属性 labelcards。这个构造函数返回后,将接着执行 Deck 的构造函数:用 Card 对象填充原本为空的 ArrayList

这就是 Deck 类。我们还需要表示一手牌和一堆牌,其中前者是玩家手里的扑克牌集合,而后者是桌子上的扑克牌集合。为此,我们可定义两个类,分别用于表示一手牌和一堆牌,但它们的差别不大。因此,我们将用同一个类 Hand 来表示一手牌和一堆牌。这个类的定义类似于下面这样:

  1. public class Hand extends CardCollection {
  2. public Hand(String label) {
  3. super(label);
  4. }
  5. public void display() {
  6. System.out.println(getLabel() + ": ");
  7. for (int i = 0; i < size(); i++) {
  8. System.out.println(getCard(i));
  9. }
  10. System.out.println();
  11. }
  12. }

Deck 一样,Hand 也扩展了 CardCollection,因此它继承了 getLabelsizegetCard 等方法,并在方法 display 中使用了这些方法。Hand 也提供了一个构造函数,就只是调用 CardCollection 的构造函数,除此之外什么都没有做。

总之,Deck 类似于 CardCollection,但提供的构造函数不同。且 Hand 也类似于 CardCollection,但提供了一个额外的方法——display