抽象方法和类
抽象方法和类
抽象类是声明为abstract的类 - 它可能包含也可能不包含抽象方法。抽象类不能被实例化,但可以被子类化。
抽象方法是声明没有实现(没有大括号,后面跟着分号)的方法,如下所示
abstract void moveTo(double deltaX, double deltaY);
如果类包含抽象方法,那么类本身必须声明为abstract,如下所示
public abstract class GraphicObject {
// declare fields
// declare nonabstract methods
abstract void draw();
}
当抽象类被子类化时,子类通常为其父类中的所有抽象方法提供实现。但是,如果它没有这样做,那么子类也必须声明为abstract。
注意:接口中的方法(参见接口部分)如果没有声明为默认或静态,则隐式为抽象方法,因此抽象修饰符不用于接口方法。(可以使用,但没有必要。)
抽象类与接口的比较
抽象类类似于接口。您不能实例化它们,并且它们可能包含声明有或没有实现的方法的混合。但是,对于抽象类,您可以声明非静态和非最终字段,并定义public、protected和private具体方法。对于接口,所有字段自动为public、static和final,并且您声明或定义(作为默认方法)的所有方法都为public。此外,您只能扩展一个类,无论它是否为抽象类,而您可以实现任意数量的接口。
您应该使用抽象类还是接口?
如果您的情况符合以下任何一项,请考虑使用抽象类
- 您希望在几个密切相关的类之间共享代码。
- 您预计扩展抽象类的类具有许多共同方法或字段,或者需要除 public 之外的访问修饰符(例如
protected和private)。 - 您希望声明非静态或非最终字段。这使您能够定义可以访问和修改它们所属对象的 state 的方法。
如果您的情况符合以下任何一项,请考虑使用接口
- 您预计不相关的类将实现您的接口。例如,接口
Comparable和Cloneable由许多不相关的类实现。 - 您希望指定特定数据类型的行为,但不关心谁实现其行为。
- 您希望利用类型的多重继承。
- 您预计不相关的类将实现您的接口。例如,接口
JDK 中抽象类的示例是AbstractMap,它是集合框架的一部分。它的子类(包括HashMap、TreeMap和ConcurrentHashMap)共享许多方法(包括get()、put()、isEmpty()、containsKey()和containsValue()),这些方法由AbstractMap定义。
JDK 中实现多个接口的类的示例是HashMap,它实现了接口Serializable、Cloneable和Map<K, V>。通过阅读此接口列表,您可以推断出HashMap的实例(无论开发人员或公司是谁实现的类)都可以克隆,是可序列化的(这意味着它可以转换为字节流;参见可序列化对象部分),并且具有 map 的功能。此外,Map<K, V>接口已通过许多默认方法(例如merge()和forEach())进行了增强,这些方法不需要以前实现此接口的类定义。
请注意,许多软件库同时使用抽象类和接口;HashMap类实现多个接口,并且还扩展了抽象类AbstractMap。
抽象类示例
在面向对象的绘图应用程序中,您可以绘制圆形、矩形、线条、贝塞尔曲线以及许多其他图形对象。这些对象都具有某些状态(例如:位置、方向、线条颜色、填充颜色)和行为(例如:移动到、旋转、调整大小、绘制)的共同点。其中一些状态和行为对于所有图形对象都是相同的(例如:位置、填充颜色和移动到)。其他需要不同的实现(例如,调整大小或绘制)。
所有 GraphicObjects 都必须能够绘制或调整自身大小;它们只是在如何做到这一点方面有所不同。这非常适合抽象超类。您可以利用这些相似之处,并声明所有图形对象都从同一个抽象父对象继承,例如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() {
...
}
}
当抽象类实现接口时
在接口部分,我们注意到实现接口的类必须实现接口的所有方法。但是,可以定义一个不实现接口所有方法的类,前提是该类声明为abstract。例如,
abstract class X implements Y {
// implements all but one method of Y
}
class XX extends X {
// implements the remaining method in Y
}
在这种情况下,类X必须为抽象类,因为它没有完全实现Y,但类XX实际上实现了Y。
类成员
抽象类可以具有static字段和static方法。您可以使用类引用(例如,AbstractClass.staticMethod())使用这些static成员,就像使用任何其他类一样。
最后更新: 2021年9月14日