文档

Java™ 教程
隐藏目录
抽象方法和类
路径: 学习Java语言
课程: 接口与继承
章节: 继承

抽象方法和类

一个抽象类是一个被声明为abstract的类,它可以包含抽象方法,也可以不包含。抽象类不能被实例化,但可以被子类继承。

抽象方法是一个没有实现的方法(没有大括号,并且跟着一个分号),像这样:

abstract void moveTo(double deltaX, double deltaY);

如果一个类包含抽象方法,那么这个类本身必须被声明为abstract,像这样:

public abstract class GraphicObject {
   // 声明字段
   // 声明非抽象方法
   abstract void draw();
}

当一个抽象类被子类继承时,子类通常为父类的所有抽象方法提供实现。但是,如果没有提供实现,那么子类也必须被声明为abstract


注意: 接口中的方法(参见接口部分)如果没有声明为默认方法或静态方法,则默认为抽象方法,因此不需要使用abstract修饰符。(虽然可以使用,但是是多余的。)

抽象类与接口的比较

抽象类与接口相似。它们都不能被实例化,并且可以包含有实现或没有实现的方法。然而,抽象类可以声明非静态和非最终的字段,并定义公共的、受保护的和私有的具体方法。接口中的所有字段都自动是公共的、静态的和最终的,你所声明或定义的所有方法(作为默认方法)也都是公共的。此外,你只能扩展一个类(无论是否为抽象类),而你可以实现任意数量的接口。

在使用抽象类或接口时,应该选择哪个?

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

JDK中实现多个接口的类的一个示例是HashMap,它实现了接口SerializableCloneableMap<K, V>。通过阅读这些接口的列表,您可以推断出HashMap的实例(不论是哪个开发者或公司实现了该类)可以被克隆,是可序列化的(这意味着它可以被转换为字节流;请参阅可序列化对象部分),并且具有映射的功能。此外,Map<K, V>接口已经通过许多默认方法(如mergeforEach)进行了增强,而早期实现了此接口的类不需要定义这些方法。

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

抽象类示例

在面向对象的绘图应用程序中,您可以绘制圆圈、矩形、线条、贝塞尔曲线和许多其他图形对象。这些对象都有一些共同的状态(例如:位置、方向、线条颜色、填充颜色)和行为(例如:移动到、旋转、调整大小、绘制)。其中一些状态和行为对所有图形对象都是相同的(例如:位置、填充颜色和移动到)。其他状态和行为则需要不同的实现(例如,调整大小或绘制)。所有的GraphicObject都必须能够自我绘制或调整大小;它们只是在如何执行这些操作上存在差异。这是使用抽象超类的完美情况。您可以利用这些相似之处,并声明所有图形对象都继承自同一个抽象父对象(例如,GraphicObject),如下图所示:

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

矩形、线条、贝塞尔曲线和圆圈继承自GraphicObject

首先,您声明一个抽象类GraphicObject,以提供所有子类共享的成员变量和方法,例如当前位置和moveTo方法。 GraphicObject还声明了抽象方法,用于需要所有子类实现但以不同方式实现的方法,例如drawresizeGraphicObject类可能如下所示:

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

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

class Circle extends GraphicObject {
    void draw() {
        ...
    }
    void resize() {
        ...
    }
}
class Rectangle extends GraphicObject {
    void draw() {
        ...
    }
    void resize() {
        ...
    }
}

当抽象类实现接口时

接口部分中指出,实现接口的类必须实现所有接口的方法。然而,如果类被声明为abstract,则可以定义一个不实现所有接口方法的类。例如:

abstract class X implements Y {
  // 实现了除了Y中一个方法之外的所有方法
}

class XX extends X {
  // 实现了Y中剩余的方法
}

在这种情况下,类X必须是abstract,因为它没有完全实现Y,但是类XX确实实现了Y

类成员

抽象类可以有static字段和static方法。您可以像使用其他类一样,使用类引用调用这些静态成员(例如,AbstractClass.staticMethod())。


上一页:编写最终类和方法
下一页:继承总结