“你好,阿米戈!我要和你说一个很有趣的新话题。”
“今天是有趣话题日呢!”
“谢谢你。”
“不客气。”
还记得我们之前为简化所有棋子类而引入的 ChessItem 基类吗?”
“记得。”
“现在,假如每个棋子都有一个方法可以渲染屏幕上的棋子。我们调用此方法,棋子就会在它当前的坐标上自我描画。那如果把这个方法改用到基类里,会对我们有帮助吗?”
“会。”学习了多态后,我可以对所有棋子调用渲染方法,而不受棋子类型限制。就像下面这样:”
class ChessBoard
{
public void drawAllChessItems()
{
//draw them regardless of their type.
ArrayList <ChessItem> items = new ArrayList<ChessItem>();
items.add(new King());
items.add(new Queen());
items.add(new Bishop());
//draw them regardless of their type.
for (ChessItem item: items)
{
item.draw();
}
}
}
“做得不错。完全正确。ChessItem 类本身应用 draw 方法会发生什么呢?”
“我不知道。国际象棋里没有这个棋子。这就意味着,它没有可视化的形象。”
“正是。而且创建 ChessItem 对象也没有什么意义。世界上没有这个棋子。它只是一个抽象 — 我们为了方便而创造的一个类。这就是抽象在 OOP 里的运作方式:我们把所有重要的(全部棋子共享的)数据和方法移入基类,但是我们保留了与每个特定棋子相对应的类的不同之处。”

对此,Java 有一个特别的类类型:抽象类。关于抽象类,有 3 点要牢记。
1) 抽象类可以声明方法,而无需实现它。这种方法我们称之为抽象方法。
public abstract class ChessItem
{
public int x, y; //coordinates
private int value; //the piece's "value"
public int getValue() //an ordinary method, returns value
{
return value;
}
public abstract void draw(); //abstract method. There is no implementation.
}
2) 抽象方法会带有关键字 abstract 标记。
如果一个类有多个抽象方法,那这个类也可以标为 abstract。
3) 我们无法给抽象类创建对象。有如此意图的代码将无法编译。
Java 语言代码 | 说明 |
---|---|
|
此代码将无法编译。 |
|
但是你可以这样做。 |
4) 如果你的类继承自抽象类,就需要重写此继承类的所有方法,换言之,你要实现它们。否则,你的类也要声明为抽象类。如果类有多个未实现的方法直接在类中声明或继承自父类,那么这个类也可以认为是抽象类。
“但是为什么一定要做这些?为什么需要抽象类?不可以改用普通类吗?相较于抽象方法,我们能不能创建一个空的实现,只有左右两个括号?”
“当然可以。但是这些限制条件就像是 private
修饰符。我们使用 private
修饰符来特意拦截对数据的直接访问,如此,其他程序员和他们的类只能用我们的 public
方法。”
抽象类也是同样的道理。无论这个类是谁写的,都不希望任何人给他们的类创建实例。相反,作者会希望他或她的抽象类可以得到继承和重写。
“我还是不明白为什么我们要用这个方法来让事情变得复杂。”
“大项目里更容易说明这个功能的优点。类越多,你就越能清楚地认识到划定类的角色的重要性。不久,你会发现此举的优点。这个过程每个人都会经历。”
GO TO FULL VERSION