3.接口

3.接口

(1)接口的定义

接口-1

接口-2

接口是一种特殊的类,不用class关键字,用interface关键字。

成员变量默认有public、static、final修饰符,这三个修饰符是可以略写的;成员变量必须赋初值。

成员方法默认有public、abstract修饰符,这两个修饰符是可以略写的。

接口定义的语法格式如下:

可以看到,接口中的所有成员变量必须是公共的(public)、静态的(static)常量(final);接口中的所有成员方法都是抽象方法(abstract),没有实现体。接口只定义一批类需要遵守的规范,即必须提供的方法有哪些,至于这些方法的具体实现细节,接口是不关心的。接口只是提供一些相似类的规范,并不提供任何实现,这体现了规范和实现分离的设计思想。

接口可以继承多个父接口,体现了多继承,而类只能继承一个父类。

(2)接口的使用

①作为一种规范,被其他类实现。

接口是抽象的,不能用来创建对象。接口主要用来被其他类实现,一个类可以实现多个接口,语法形式如下:

接口的意义-1

类实现接口要用implements关键字。类实现接口可以理解为是一种特殊的继承,父接口中的所有成员变量和成员方法都会来到子类中,由此,在子类中需要实现父接口中所有的抽象方法(可以理解为重写父接口中的所有方法),否则,如果子类中保留了来自父接口的抽象方法,那么这个类就成了不能创建对象的抽象类。

②作为一种引用类型,用来定义对象。

【代码16.15】接口两种使用情况的案例

在代码16.15的第59行中,Shape作为引用类型,可以引用实现了Shape接口的Circle类的实例。s1可以说有两种类型:引用类型是Shape接口;实际对象类型是Circle类。在第60行和第61行中,当对s1进行实际操作时,需按照实际运行时的对象类型,这叫作“动态绑定”。

代码16.16模拟了计算机生产的过程,让我们通过代码来体会一下“面向接口编程”的思想。

【代码16.16】模拟计算机生产组装的程序

接口的意义-2

在代码16.16的第2行,Memory接口规定了内存的规范:所有内存必须提供cache()方法。而cache()的具体实现方式是没有确定的,是抽象方法。

在第4行,DispCard接口规定了显卡的规范:所有显卡必须提供display()方法。而display()的具体实现是没有的,是抽象方法。

在第7行,Computer类需要内存和显卡,第10行的构造方法传入的是Memory和Disp Card接口类型(只要符合接口的内存和显卡的实例,都可以装配起来)。第15行通过调用Memory的cache()方法来提供内存功能,第18行通过调用DispCard的display()方法来提供显示功能。

第22行的AMemory类是实现Memory接口的一种具体内存类,第27行的ADispCard类是实现Disp Card接口的一种具体显卡类。

在第32行的主类Test Computer中,用AMemory的实例和ADispCard的实例组装了一台计算机computer,那么computer提供的内存功能来自AMemory类,computer提供的显示功能来自ADispCard类。

这样的程序结构的优点如下。

第一,在Memory接口和Display接口定义好之后,Computer类是面向接口编程的,Computer类和各种内存实现类、显卡实现类可以同步开发,这样有利于多人合作。

第二,可以用任意的其他内存类来替换AMemory类,如BMemory类,只要BMemory类实现了Memory接口即可,对显卡类也是如此。替换具体的内存、显卡后,整个程序的结构是不变的,其他模块也是不受影响的,这有利于软件的可扩展性和可维护性。

下面用另外的内存BMemory或者显卡BDisp Card的实现类来替换原有的内存和显卡,内存类实现Memory接口,显卡类实现DispCard接口,见代码16.17。

【代码16.17】

用另外的Memory的实现类BMemory和DispCard的实现类BDispCard类“组装”计算机。

接口制定了规范,规定了接口的实现类必须提供的方法,而不同的实现类可以有不同的实现细节。在项目开发中,经常采用“面向接口编程”,这意味着系统的主体架构使用接口搭建。这样实现类的实现细节以及实现类的更换都不会影响到系统的主体架构,提高了程序的可维护性、可扩展性。另外,接口提供了多继承途径,一个接口可以继承多个接口,一个类可以实现多个接口。