这些Java教程是针对JDK 8编写的。本页中描述的示例和实践不利用后续版本中引入的改进,并且可能使用不再可用的技术。
请参阅Java语言更改以了解Java SE 9及其后续版本中更新的语言功能的摘要。
请参阅JDK发行说明以了解所有JDK版本的新功能、增强功能以及已删除或已弃用选项的信息。
一个抽象类是一个被声明为abstract
的类,它可以包含抽象方法,也可以不包含。抽象类不能被实例化,但可以被子类继承。
抽象方法是一个没有实现的方法(没有大括号,并且跟着一个分号),像这样:
abstract void moveTo(double deltaX, double deltaY);
如果一个类包含抽象方法,那么这个类本身必须被声明为abstract
,像这样:
public abstract class GraphicObject { // 声明字段 // 声明非抽象方法 abstract void draw(); }
当一个抽象类被子类继承时,子类通常为父类的所有抽象方法提供实现。但是,如果没有提供实现,那么子类也必须被声明为abstract
。
抽象类与接口相似。它们都不能被实例化,并且可以包含有实现或没有实现的方法。然而,抽象类可以声明非静态和非最终的字段,并定义公共的、受保护的和私有的具体方法。接口中的所有字段都自动是公共的、静态的和最终的,你所声明或定义的所有方法(作为默认方法)也都是公共的。此外,你只能扩展一个类(无论是否为抽象类),而你可以实现任意数量的接口。
在使用抽象类或接口时,应该选择哪个?
Comparable
和Cloneable
被许多不相关的类实现。JDK中抽象类的一个示例是AbstractMap
,它是集合框架的一部分。它的子类(包括HashMap
、TreeMap
和ConcurrentHashMap
)共享许多方法(包括get
、put
、isEmpty
、containsKey
和containsValue
),这些方法是由AbstractMap
定义的。
JDK中实现多个接口的类的一个示例是HashMap
,它实现了接口Serializable
、Cloneable
和Map<K, V>
。通过阅读这些接口的列表,您可以推断出HashMap
的实例(不论是哪个开发者或公司实现了该类)可以被克隆,是可序列化的(这意味着它可以被转换为字节流;请参阅可序列化对象部分),并且具有映射的功能。此外,Map<K, V>
接口已经通过许多默认方法(如merge
和forEach
)进行了增强,而早期实现了此接口的类不需要定义这些方法。
请注意,许多软件库同时使用抽象类和接口;HashMap
类实现了多个接口,并且还继承了抽象类AbstractMap
。
在面向对象的绘图应用程序中,您可以绘制圆圈、矩形、线条、贝塞尔曲线和许多其他图形对象。这些对象都有一些共同的状态(例如:位置、方向、线条颜色、填充颜色)和行为(例如:移动到、旋转、调整大小、绘制)。其中一些状态和行为对所有图形对象都是相同的(例如:位置、填充颜色和移动到)。其他状态和行为则需要不同的实现(例如,调整大小或绘制)。所有的GraphicObject
都必须能够自我绘制或调整大小;它们只是在如何执行这些操作上存在差异。这是使用抽象超类的完美情况。您可以利用这些相似之处,并声明所有图形对象都继承自同一个抽象父对象(例如,GraphicObject
),如下图所示:
矩形、线条、贝塞尔曲线和圆圈继承自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(); }
每个非抽象子类,例如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 { // 实现了除了Y中一个方法之外的所有方法 } class XX extends X { // 实现了Y中剩余的方法 }
在这种情况下,类X
必须是abstract
,因为它没有完全实现Y
,但是类XX
确实实现了Y
。
抽象类可以有static
字段和static
方法。您可以像使用其他类一样,使用类引用调用这些静态成员(例如,AbstractClass.staticMethod()
)。