本教程是针对JDK 8编写的。本页中描述的示例和实践不利用后续版本引入的改进,并且可能使用已不再可用的技术。
请参阅Java语言变更以了解Java SE 9及后续版本中更新的语言特性的摘要。
请参阅JDK发布说明以获取有关所有JDK版本的新功能、增强功能和已删除或已弃用选项的信息。
在软件工程中,有许多情况下,不同的程序员组必须就他们的软件如何交互达成一致的“契约”。每个组都应该能够编写他们的代码,而不需要了解其他组的代码是如何编写的。一般来说,接口就是这样的契约。
例如,想象一个未来社会,计算机控制的机器人汽车在城市街道上无需人为操作即可运输乘客。汽车制造商编写操作汽车的软件(当然是Java),比如停止、启动、加速、左转等。另一组工业人员,电子导航仪器制造商,制造计算机系统,接收GPS(全球定位系统)位置数据和交通状况的无线传输,并使用这些信息来驱动汽车。
汽车制造商必须发布一个行业标准的接口,详细说明可以调用哪些方法来控制汽车(任何制造商的汽车)。导航制造商可以编写软件来调用接口中描述的方法来控制汽车。两个工业组都不需要知道另一组的软件是如何实现的。事实上,每个组都认为自己的软件是高度专有的,并保留随时修改的权利,只要它继续遵守发布的接口。
在Java编程语言中,接口是一种引用类型,类似于类,可以只包含常量、方法签名、默认方法、静态方法和嵌套类型。方法体只存在于默认方法和静态方法中。接口不能被实例化,只能被类实现或其他接口扩展。接口的扩展将在本课程的后面讨论。
定义接口类似于创建一个新类:
public interface OperateCar { // 常量声明,如果有的话 // 方法签名 // 一个具有RIGHT和LEFT两个值的枚举 int turn(Direction direction, double radius, double startSpeed, double endSpeed); int changeLanes(Direction direction, double startSpeed, double endSpeed); int signalTurn(Direction direction, boolean signalOn); int getRadarFront(double distanceToCar, double speedOfCar); int getRadarRear(double distanceToCar, double speedOfCar); ...... // 更多方法签名 }
请注意,方法签名没有花括号,并以分号结尾。
要使用接口,您需要编写一个实现该接口的类。当一个可实例化的类实现了一个接口时,它为接口中声明的每个方法提供一个方法体。例如:
public class OperateBMW760i implements OperateCar { // OperateCar方法的签名和实现,例如: public int signalTurn(Direction direction, boolean signalOn) { // 打开宝马左转向指示灯的代码 // 关闭宝马左转向指示灯的代码 // 打开宝马右转向指示灯的代码 // 关闭宝马右转向指示灯的代码 } // 其他成员,如有需要的话,例如,对客户端不可见的辅助类 }
在上面的机器人汽车示例中,实现接口的是汽车制造商。当然,雪佛兰的实现与丰田的实现有很大不同,但两个制造商都会遵循相同的接口。作为接口的客户端,导航系统制造商将构建使用汽车的GPS数据、数字街道地图和交通数据来驱动汽车的系统。在这样做的过程中,导航系统将调用接口的方法:转向、变道、刹车、加速等等。
机器人汽车示例展示了接口作为行业标准的应用程序编程接口(API)的使用。API在商业软件产品中也很常见。通常,一家公司销售一个包含复杂方法的软件包,另一家公司希望在自己的软件产品中使用这些方法。一个例子是一个包含数字图像处理方法的软件包,该软件包销售给制作最终用户图形程序的公司。图像处理公司编写其类来实现一个接口,并将其公开给客户。然后,图形公司使用接口中定义的签名和返回类型来调用图像处理方法。虽然图像处理公司的API是公开的(对其客户来说),但其对API的实现被保持为严格保密的商业机密。事实上,它可能在以后的日期对实现进行修订,只要继续实现其客户所依赖的原始接口即可。