Java 教程是为 JDK 8 编写的。本页中描述的示例和实践未利用在后续版本中引入的改进。
abstract class (抽象类) 是一个声明为 abstract
的类,它可能包含也可能不包含抽象方法。抽象类无法实例化,但可以进行子类化。
abstract method (抽象方法) 是一个没有实现的情况下声明的方法(没有大括号,后跟分号),如下所示:
abstract void moveTo(double deltaX, double deltaY);
如果一个类包含抽象方法,那么类本身 必须 声明为 abstract
,如下所示:
public abstract class GraphicObject { // declare fields // declare nonabstract methods abstract void draw(); }
当抽象类被子类化时,子类通常为其父类中的所有抽象方法提供实现。但是,如果没有,则子类也必须声明为 abstract
。
abstract
修饰符不用于接口方法。(可以使用,但不需要。)
抽象类与接口类似。你无法实例化它们,并且它们可能声明一些包含或不包含实现的混合方法。但是,使用抽象类,你可以声明非静态和 final 的字段,并定义 public,protected 和 private 具体方法。使用接口,所有字段都自动为 public,static 和 final,并且你声明或定义的所有方法(作为默认方法)都是 public 的。此外,你只能继承一个类,无论它是否是抽象的,而你可以实现任意数量的接口。
你应该使用抽象类还是接口?
Comparable
和 Cloneable
由许多不相关的类实现。JDK 中抽象类的一个示例是 AbstractMap
,它是集合框架的一部分。它的子类(包括 HashMap
,TreeMap
和 ConcurrentHashMap
)共享许多方法(包括 get
,put
,isEmpty
,containsKey
和containsValue
),这些方法由 AbstractMap
定义。
JDK 中实现多个接口的类的示例是 HashMap
,它实现接口 Serializable
,Cloneable
,和 Map<K, V>
。通过阅读这个接口列表,你可以推断出 HashMap
的实例(无论实现该类的开发人员或公司)是可以克隆的,是可序列化的(这意味着它可以转换为字节流;请参阅 Serializable Objects 部分),并具有 map 的功能。此外,Map<K, V>
接口已经增强了许多默认方法,例如 merge
和 forEach
已经实现这个接口的旧类不必定义。
请注意,许多软件库都使用抽象类和接口; HashMap
类实现了几个接口,并且还继承了抽象类 AbstractMap
。
在面向对象的绘图应用程序中,你可以绘制圆形,矩形,线条,贝塞尔曲线和许多其他图形对象。这些对象都具有某些状态(例如:位置,方向,线条颜色,填充颜色)和行为(例如:moveTo,rotate,resize,draw)。所有图形对象中的一些状态和行为都是相同的(例如:位置,填充颜色和 moveTo)。其他需要不同的实现(例如,调整大小或绘制)。所有 GraphicObject
必须能够自己绘制或调整大小;他们只是在做不同的事情上有所不同。这是抽象超类的完美情况。你可以利用相似性并声明所有图形对象都从相同的抽象父对象继承(例如,GraphicObject
),如 下图所示。
Classes Rectangle, Line, Bezier, and Circle Inherit from GraphicObject
首先,声明一个抽象类 GraphicObject
,以提供由所有子类完全共享的成员变量和方法,例如当前位置和 moveTo
方法。GraphicObject
还声明方法的抽象方法,例如 draw
或 resize
,这些方法需要由所有子类实现,但必须以不同的方式实现。GraphicObject
类看起来像这样:
abstract class GraphicObject { int x, y; ... void moveTo(int newX, int newY) { ... } abstract void draw(); abstract void resize(); }
GraphicObject
的每个非抽象子类,例如 Circle
和 Rectangle
,必须提供 draw
和 resize
方法:
class Circle extends GraphicObject { void draw() { ... } void resize() { ... } } class Rectangle extends GraphicObject { void draw() { ... } void resize() { ... } }
在 Interfaces
的部分中,注意到实现接口的类必须实现接口的 所有 方法。但是,如果声明该类声明为 abstract
,则可以定义一个不实现所有接口方法的类。例如,
abstract class X implements Y { // implements all but one method of Y } class XX extends X { // implements the remaining method in Y }
在这种情况下,类 X
必须是 abstract
,因为它没有完全实现 Y
,但是类 XX
,实际上,它完全实现 Y
。
抽象类可以包含 static
字段和 static
方法。你可以将这些静态成员与类引用一起使用(例如,AbstractClass.staticMethod()
),就像使用任何其他类一样。