抽象方法和类
抽象类是一个声明为abstract
的类 — 它可能包括也可能不包括抽象方法,抽象类无法实例化,但可以进行子类化。
抽象方法是在没有实现的情况下声明的方法(没有大括号,后跟分号),如下所示:
abstract void moveTo(double deltaX, double deltaY);
如果一个类包含抽象方法,那么该类本身必须被声明为abstract
,如:
public abstract class GraphicObject {
// declare fields
// declare nonabstract methods
abstract void draw();
}
当抽象类被子类化时,子类通常为其父类中的所有抽象方法提供实现,但是,如果没有,那么子类也必须声明为abstract
。
注意:未声明为default
或static
的接口(参见接口部分)中的方法是隐式抽象的,因此abstract
修饰符不用于接口方法(可以使用,但不需要)。
抽象类与接口相比
抽象类与接口类似,你不能实例化它们,它们可能包含有或没有实现声明的方法的组合,但是,使用抽象类,你可以声明非静态和final
的字段,并定义public
、protected
和private
的具体方法。使用接口,所有字段都自动为public
、static
和final
,并且你声明或定义的所有方法(作为默认方法)都是public
,此外,你只能扩展一个类,无论它是否是抽象的,而你可以实现任意数量的接口。
你应该使用哪个,抽象类或接口?
-
如果任何这些语句适用于你的情况,请考虑使用抽象类:
- 你希望在几个密切相关的类之间共享代码。
- 你希望扩展抽象类的类具有许多公共方法或字段,或者需要非公共的访问修饰符(如
protected
和private
)。 - 你想声明非静态或非最终字段,这使你能够定义能够访问和修改它们所属的对象的状态的方法。
-
如果任何这些语句适用于你的情况,请考虑使用接口:
- 你希望不相关的类将实现你的接口,例如,Comparable和Cloneable接口由许多不相关的类实现。
- 你希望指定特定数据类型的行为,但不关心谁实现其行为。
- 你希望利用类型的多重继承。
JDK中的抽象类的一个示例是AbstractMap,它是集合框架的一部分,它的子类(包括HashMap
、TreeMap
和ConcurrentHashMap
)共享AbstractMap
定义的许多方法(包括get
、put
、isEmpty
、containsKey
和containsValue
)。
JDK中实现多个接口的类的一个示例是HashMap,它实现了Serializable
、Cloneable
和Map<K, V>
接口。通过阅读这个接口列表,你可以推断出HashMap
的实例(无论是实现该类的开发人员或公司)可以克隆,可序列化(这意味着它可以转换为字节流)。请参阅Serializable Objects
部分,并具有map的功能,此外,Map<K, V>
接口已经增强了许多默认方法,例如merge
和forEach
,实现此接口的旧类不必定义。
请注意,许多软件库都使用抽象类和接口,HashMap
类实现了几个接口,并且还扩展了抽象类AbstractMap
。
抽象类示例
在面向对象的绘图应用程序中,你可以绘制圆形、矩形、线条、贝塞尔曲线和许多其他图形对象,这些对象都具有某些状态(例如:位置、方向、线条颜色、填充颜色)和行为(例如:moveTo
、rotate
、resize
、draw
)。所有图形对象中的一些状态和行为都是相同的(例如:位置、填充颜色和moveTo
),其他需要不同的实现(例如,resize
或draw
)。所有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
必须是abstract
,因为它没有完全实现Y
,但实际上,类XX
实现了Y
。
类成员
抽象类可以具有静态字段和静态方法,你可以像使用任何其他类一样使用带有类引用的静态成员(例如,AbstractClass.staticMethod()
)。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。