这些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())。