# 抽象方法和类

> 原文： [https://docs.oracle.com/javase/tutorial/java/IandI/abstract.html](https://docs.oracle.com/javase/tutorial/java/IandI/abstract.html)

_ 抽象类 _ 是一个声明为`abstract`的类 - 它可能包含也可能不包含抽象方法。抽象类无法实例化，但可以进行子类化。

_ 抽象方法 _ 是一个声明没有实现的方法（没有大括号，后跟分号），如下所示：

```
abstract void moveTo(double deltaX, double deltaY);

```

如果一个类包含抽象方法，则类本身 _ 必须 _ 声明为`abstract`，如：

```
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&lt;K, V&gt;`。通过读取此接口列表，您可以推断出`HashMap`的实例（无论是实现该类的开发人员或公司）是否可以克隆，是可序列化的（这意味着它可以转换为字节流;请参阅部分[可序列化对象](../../jndi/objects/serial.html)），并具有地图的功能。此外，`Map&lt;K, V&gt;`接口已经增强了许多默认方法，例如`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`类看起来像这样：

```
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`](../IandI/createinterface.html) 的部分中，注意到实现接口的类必须实现 _ 接口方法的所有 _。但是，如果该类声明为`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()`）。