文档

Java™ 教程-Java Tutorials 中文版
抽象方法和类
Trail: Learning the Java Language
Lesson: Interfaces and Inheritance
Section: Inheritance

抽象方法和类

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


注意: interface (接口) 中的方法(参见 Interfaces 部分),如果未声明为 default 或 static ,则都 implicitly (隐式) abstract,因此 abstract 修饰符不用于接口方法。(可以使用,但不需要。)

抽象类与接口相比

抽象类与接口类似。你无法实例化它们,并且它们可能声明一些包含或不包含实现的混合方法。但是,使用抽象类,你可以声明非静态和 final 的字段,并定义 public,protected 和 private 具体方法。使用接口,所有字段都自动为 public,static 和 final,并且你声明或定义的所有方法(作为默认方法)都是 public 的。此外,你只能继承一个类,无论它是否是抽象的,而你可以实现任意数量的接口。

你应该使用抽象类还是接口?

JDK 中抽象类的一个示例是 AbstractMap,它是集合框架的一部分。它的子类(包括 HashMapTreeMapConcurrentHashMap)共享许多方法(包括 getputisEmptycontainsKeycontainsValue),这些方法由 AbstractMap 定义。

JDK 中实现多个接口的类的示例是 HashMap,它实现接口 SerializableCloneable ,和 Map<K, V>。通过阅读这个接口列表,你可以推断出 HashMap 的实例(无论实现该类的开发人员或公司)是可以克隆的,是可序列化的(这意味着它可以转换为字节流;请参阅 Serializable Objects 部分),并具有 map 的功能。此外,Map<K, V> 接口已经增强了许多默认方法,例如 mergeforEach 已经实现这个接口的旧类不必定义。

请注意,许多软件库都使用抽象类和接口; HashMap 类实现了几个接口,并且还继承了抽象类 AbstractMap

抽象类示例

在面向对象的绘图应用程序中,你可以绘制圆形,矩形,线条,贝塞尔曲线和许多其他图形对象。这些对象都具有某些状态(例如:位置,方向,线条颜色,填充颜色)和行为(例如:moveTo,rotate,resize,draw)。所有图形对象中的一些状态和行为都是相同的(例如:位置,填充颜色和 moveTo)。其他需要不同的实现(例如,调整大小或绘制)。所有 GraphicObject 必须能够自己绘制或调整大小;他们只是在做不同的事情上有所不同。这是抽象超类的完美情况。你可以利用相似性并声明所有图形对象都从相同的抽象父对象继承(例如,GraphicObject),如 下图所示

Classes Rectangle, Line, Bezier, and Circle Inherit from GraphicObject

Classes Rectangle, Line, Bezier, and Circle Inherit from GraphicObject

首先,声明一个抽象类 GraphicObject,以提供由所有子类完全共享的成员变量和方法,例如当前位置和 moveTo 方法。GraphicObject 还声明方法的抽象方法,例如 drawresize,这些方法需要由所有子类实现,但必须以不同的方式实现。GraphicObject 类看起来像这样:

abstract class GraphicObject {
    int x, y;
    ...
    void moveTo(int newX, int newY) {
        ...
    }
    abstract void draw();
    abstract void resize();
}

GraphicObject 的每个非抽象子类,例如 CircleRectangle,必须提供 drawresize 方法:

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()),就像使用任何其他类一样。


Previous page: Writing Final Classes and Methods
Next page: Summary of Inheritance