# 抽象方法和类 > 原文: [https://docs.oracle.com/javase/tutorial/java/IandI/abstract.html](https://docs.oracle.com/javase/tutorial/java/IandI/abstract.html) *抽象类*是一个声明为`abstract`的类 - 它可能包含也可能不包含抽象方法。抽象类无法实例化,但可以进行子类化。 *抽象方法*是一个声明没有实现的方法(没有大括号,后跟分号),如下所示: ```java abstract void moveTo(double deltaX, double deltaY); ``` 如果一个类包含抽象方法,则类本身*必须*声明为`abstract`,如: ```java public abstract class GraphicObject { // declare fields // declare nonabstract methods abstract void draw(); } ``` 当抽象类被子类化时,子类通常为其父类中的所有抽象方法提供实现。但是,如果没有,那么子类也必须声明为`abstract`。 * * * **Note:** Methods in an _interface_ (see the [Interfaces](../IandI/createinterface.html) section) that are not declared as default or static are _implicitly_ abstract, so the `abstract` modifier is not used with interface methods. (It can be used, but it is unnecessary.) * * * 抽象类与接口类似。您无法实例化它们,并且它们可能包含使用或不使用实现声明的混合方法。但是,对于抽象类,您可以声明非静态和最终的字段,并定义 public,protected 和 private 具体方法。使用接口,所有字段都自动为 public,static 和 final,并且您声明或定义的所有方法(作为默认方法)都是公共的。此外,您只能扩展一个类,无论它是否是抽象的,而您可以实现任意数量的接口。 你应该使用哪些,抽象类或接口? * 如果任何这些语句适用于您的情况,请考虑使用抽象类: * 您希望在几个密切相关的类之间共享代码。 * 您希望扩展抽象类的类具有许多常用方法或字段,或者需要除公共之外的访问修饰符(例如 protected 和 private)。 * 您想声明非静态或非最终字段。这使您可以定义可以访问和修改它们所属对象的状态的方法。 * 如果任何这些语句适用于您的情况,请考虑使用接口: * 您希望不相关的类可以实现您的接口。例如,接口 [`Comparable`](https://docs.oracle.com/javase/8/docs/api/java/lang/Comparable.html) 和 [`Cloneable`](https://docs.oracle.com/javase/8/docs/api/java/lang/Cloneable.html) 由许多不相关的类实现。 * 您希望指定特定数据类型的行为,但不关心谁实现其行为。 * 您希望利用类型的多重继承。 JDK 中的抽象类的一个示例是 [`AbstractMap`](https://docs.oracle.com/javase/8/docs/api/java/util/AbstractMap.html) ,它是 Collections Framework 的一部分。其子类(包括`HashMap`,`TreeMap`和`ConcurrentHashMap`)共享`AbstractMap`定义的许多方法(包括`get`,`put`,`isEmpty`,`containsKey`和`containsValue`)。 JDK 中实现多个接口的类的示例是 [`HashMap`](https://docs.oracle.com/javase/8/docs/api/java/util/HashMap.html) ,它实现接口`Serializable`,`Cloneable`和`Map<K, V>`。通过读取此接口列表,您可以推断出`HashMap`的实例(无论是实现该类的开发人员或公司)是否可以克隆,是可序列化的(这意味着它可以转换为字节流;请参阅部分[可序列化对象](../../jndi/objects/serial.html)),并具有地图的功能。此外,`Map<K, V>`接口已经增强了许多默认方法,例如`merge`和`forEach`,实现此接口的旧类不必定义。 请注意,许多软件库都使用抽象类和接口; `HashMap`类实现了几个接口,并且还扩展了抽象类`AbstractMap`。 ## 抽象类示例 在面向对象的绘图应用程序中,您可以绘制圆形,矩形,线条,贝塞尔曲线和许多其他图形对象。这些对象都具有某些状态(例如:位置,方向,线条颜色,填充颜色)和行为(例如:moveTo,rotate,resize,draw)。对于所有图形对象,这些状态和行为中的一些是相同的(例如:位置,填充颜色和 moveTo)。其他需要不同的实现(例如,调整大小或绘制)。所有`GraphicObject`必须能够自己绘制或调整大小;他们只是在做不同的事情上有所不同。这是抽象超类的完美情况。您可以利用相似性并声明所有图形对象继承自相同的抽象父对象(例如,`GraphicObject`),如下图所示。 ![Classes Rectangle, Line, Bezier, and Circle Inherit from GraphicObject ](img/a96478bc843eccbcb74710d8257ae4bd.jpg) 类 Rectangle,Line,Bezier 和 Circle 从 GraphicObject 继承 首先,声明一个抽象类`GraphicObject`,以提供由所有子类完全共享的成员变量和方法,例如当前位置和`moveTo`方法。 `GraphicObject`还声明方法的抽象方法,例如`draw`或`resize`,它们需要由所有子类实现,但必须以不同的方式实现。 `GraphicObject`类看起来像这样: ```java abstract class GraphicObject { int x, y; ... void moveTo(int newX, int newY) { ... } abstract void draw(); abstract void resize(); } ``` `GraphicObject`的每个非抽象子类,如`Circle`和`Rectangle`,必须提供`draw`和`resize`方法的实现: ```java class Circle extends GraphicObject { void draw() { ... } void resize() { ... } } class Rectangle extends GraphicObject { void draw() { ... } void resize() { ... } } ``` ## 当抽象类实现接口时 在 [`Interfaces`](../IandI/createinterface.html) 的部分中,注意到实现接口的类必须实现*接口方法的所有*。但是,如果该类声明为`abstract`,则可以定义一个不实现所有接口方法的类。例如, ```java 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()`)。