1.飞马座

让我们更深入地了解一下OOP的第三个原则:继承。这是一个非常有趣的主题,您将经常使用它。对于外行来说,编程与魔术没有区别。因此,让我们从一个有趣的类比开始……;

假设您是一位想要创造一匹飞马的巫师。一方面,你可以试着召唤飞马。但由于天马在自然界中不存在,这将是非常困难的。你将不得不自己做很多事情。骑马并召唤它的翅膀要容易得多。

在编程中,这个过程被称为“继承”。假设您需要编写一个非常复杂的类。从头开始编写代码然后长时间测试所有内容以查找错误需要很长时间。为什么要走艰难的路?最好看看这样的类是否已经存在。

假设您找到一个类,其方法实现了您需要的 80% 的功能。接下来你会用它做什么?您可以将其代码复制到您的班级中。但是这个解决方案有几个缺点:

  1. 您找到的类可能已经编译成字节码,您可能无法访问其源代码。
  2. 该类的源代码是可用的,但你为一家公司工作,即使使用别人的 6 行代码也可能被起诉数十亿美元。然后你的雇主会起诉你。
  3. 大量代码的不必要的重复。此外,如果外部类的作者发现其中的错误并修复它,您仍然会遇到错误。

有一个更优雅的解决方案,它不需要获得对原始类代码的合法访问权。在 Java 中,您可以简单地将那个类声明为您的类的父类。这相当于将该类的代码添加到您自己的代码中。您的类将看到父类的所有数据和所有方法。例如,您可以这样做:我们继承“马”,然后添加“翅膀”以获得“飞马座”


2.公共基类

继承也可以用于其他目的。假设您有十个非常相似的课程。他们有相同的数据和方法。您可以创建一个特殊的基类,将数据(和关联的方法)移动到这个基类中,并将这十个类声明为后代。也就是说,在每一个类中都标明其父类就是这个基类。

正如抽象的优点只有通过侧面封装才能体现出来一样,在使用多态性时继承的优点也会大大增强。但是你稍后会了解到这一点。今天我们将看几个使用继承的例子。

棋子

假设我们正在编写一个与人类用户下棋的程序。因此,我们需要类来表示棋子。他们会是什么班级?

如果您曾经下过国际象棋,那么显而易见的答案就是国王、王后、象、马、车和兵。

但是类本身仍然需要存储关于每件作品的信息。例如,x 和 y 坐标,以及棋子的值。毕竟,有些作品比其他作品更有价值。

此外,棋子的移动方式不同,这意味着类将实现不同的行为。以下是如何将它们定义为类:

class King
{
   int x;
   int y;
   int worth;

   void kingMove()
   {
     // Code that decides
     // how to move
     // the king
   }
}
class Queen
{
   int x;
   int y;
   int worth;

   void queenMove()
   {
     // Code that decides
     // how to move
     // the queen
   }
}
class Rook
{
   int x;
   int y;
   int worth;

   void rookMove()
   {
     // Code that decides
     // how to move
     // the rook
   }
}
class Knight
{
   int x;
   int y;
   int worth;

   void knightMove()
   {
     // Code that decides
     // how to move
     // the knight
   }
}
class Bishop
{
   int x;
   int y;
   int worth;

   void bishopMove()
   {
     // Code that decides
     // how to move
     // the bishop
   }
}
class Pawn
{
   int x;
   int y;
   int worth;

   void pawnMove()
   {
     // Code that decides
     // how to move
     // the pawn
   }
}

这是对棋子的非常原始的描述。

公共基类

下面介绍如何使用继承来减少代码量。我们可以把通用的方法和数据放到一个通用的类中。我们称之为ChessItem. 创建的对象ChessItem class没有意义,因为该类不对应于任何棋子。也就是说,该课程将证明非常有用:

class King extends ChessItem
{
   void kingMove()
   {
     // Code that decides
     // how to move the king
   }
}
class Queen extends ChessItem
{
   void queenMove()
   {
     // Code that decides
     // how to move the queen
   }
}
class Rook extends ChessItem
{
   void rookMove()
   {
     // Code that decides
     // how to move the rook
   }
}
class ChessItem
{
   int x;
   int y;
   int worth;
}
class Knight extends ChessItem
{
   void knightMove()
   {
     // Code that decides
     // how to move the knight
   }
}
class Bishop extends ChessItem
{
   void bishopMove()
   {
     // Code that decides
     // how to move the bishop
   }
}
class Pawn extends ChessItem
{
   void pawnMove()
   {
     // Code that decides
     // how to move the pawn
   }
}

这是简化类似对象代码的好方法。 当项目中有数千个不同的对象和数百个类时,好处尤其明显。所以正确选择父(基)类让你不仅可以大大简化逻辑,还可以将代码减少十倍。


3.类继承——extends

那么继承一个类需要什么呢?一个类要继承另一个类,需要extends在子类声明后写上关键字,然后写上父类的名字。它通常看起来像这样:

class Descendant extends Parent

这是您在声明 Descendant 类时需要编写的内容。顺便说一句,一个类只能继承一个类。

在图片中,我们看到一头牛继承了猪,猪继承了鸡,鸡继承了鸡蛋。只有一个父母!这种继承并不总是合乎逻辑的。但是当你只有一头猪而你真的需要一头牛时,程序员往往无法抗拒将猪变成牛的冲动。

Java没有多重继承:一个类不能继承两个类。每个类只能有一个父类。如果未指定父类,则父类为Object.

也就是说,Java 确实具有接口的多重继承。这稍微缓解了这个问题。我们稍后会讨论接口,但现在让我们继续探索继承。