文章目录
- 介绍
- 接口的种类
- 接口的作用
- Java中的接口
- 实现一个接口
- Servlet接口的使用模式
- 总结
介绍
上篇文章提到Servlet继承层次的最顶端就是Servlet
接口,那么本篇就来介绍Java里面这个重中之重的基础概念,就是接口(英文是interface)。
接口的种类
所谓接口,就是指两个东西连接的那一部分,现实生活中存在大量的例子,比如我们老祖宗发明的榫和卯之间的接口、各种管道与管道之间的接口、螺丝与螺帽之间的接口、插头与插座之间的接口、灯与电线之间的接口、USB设备与电脑之间的接口等等。
具体到计算机领域,那接口更是多如牛毛(有点夸张了),首先暴露在外面我们能看到的就有PS/2鼠标和键盘接口、USB接口、串行接口、并行接口、网口、耳麦接口、电源接口等;里面更是有CPU接口、内存接口、IDE接口、PCI接口、AGP接口等等。这些都是两个硬件之间的接口,所以叫硬件接口。
这里我们能发现接口有一个很重要的特点,就是某个硬件坏了或者不够用了,可以换一个拥有同样接口的好的或者性能更强劲的或者别的厂商生产的质量更好的硬件即可,而不必把整个机器给扔了,这就是可插拔,就是解耦。
上面是硬件接口,人要操作机器,那么连接人与机器的那一部分也需要接口,最常见的就是ATM取款机或者智能手机上的触屏了。实际上,真正起到连接作用的是触屏上的画面内容部分,它们才能告诉人们如何操作机器,所以,人们很形象的称这些画面内容为图形用户界面(英文是Graphical User Interface,简称GUI)。从这可以看出,interface还可以翻译成界面,也是起到接口的作用。当然,还有不是那么友好的命令行的界面/接口,就是人们需要输入命令来与机器交互的一种界面/接口。
同样的道理,两个软件要交互也需要有接口来连接,这就是软件接口。比如操作系统和应用程序之间的交互就是通过应用程序编程接口(英文是Application Programming Interface,简称API),它是由操作系统提供给应用程序开发人员使用的,应用程序开发人员使用API就可以使用操作系统提供的各种功能,而这些功能就是访问CPU、内存、磁盘、网络、鼠标键盘、显示器等硬件设备的。
接口的作用
综上所述,接口就是连接两个东西的那个公共的部分,起到交互、通信、信息交换、传输(总之是某种东西的传输、比如力、电、数据等等)的作用,是东西连接外部的边界。这样,只要接口不变,东西内部无论如何修改都不会影响外部对它的使用。
比如,有一种灯泡接口是螺纹的,它提供获得灯光的能力,而且那些螺纹或引脚都是标准的,具有一定规范的,只要符合螺纹或引脚接口标准的灯泡,不管它是白炽灯、日光灯、节能灯;不管是发什么颜色的灯光,不管是什么形状的,都可以插在外部的按照该螺纹或引脚接口规范来使用的灯座上,以此获得灯光。我们说各种各样的灯泡都实现了那个螺纹接口,每一种实现都不同,而外部插座使用这个接口的方式是相同的(就是跟螺纹要匹配)。我们可以不断开发新的灯泡,可以在灯座上不断更换灯泡,而不需要修改灯座。它们之间的关系如下:
在软件领域也是如此,接口就是一组标准和规范,它描述了一段程序应该具有的某种行为特征和能力,比如一个排序接口,描述的就是一段程序可以将输入的一组数据按照某种顺序排列的能力,不管程序(相当于是各种各样的灯泡)是使用什么方法(选择排序、插入排序、快速排序、合并排序等等)来排列该组数据,只要实现了这个接口,外部程序(相当于插座)就可以使用这个接口来将某些数据进行排序,如果不满意当前的实现,要么改造这个实现的内部逻辑,要么直接拿一个第三方开发的实现,直接配置到外部程序中即可。而外部程序仍旧是使用这个接口来排序的,因此不需要做任何改变。它们之间的关系如下:
所以说,接口的作用就是能达到实现(这里是名词,指的是实现该接口的程序)内部的修改不影响外部使用(当然是通过使用接口),这就叫解耦,就是降低耦合性。耦合性就是描述两个东西相互影响的程度。
接口就是其中一种很重要的解耦的技术,所以人们总结出一条面向接口编程的原则。该原则就要求外部程序尽量使用接口来实现逻辑,就包括三个步骤:
- 抽象出接口;
- 实现该接口;
- 为外部程序配置一个实现。
Java中的接口
Java语言中专门为接口这个概念提供了关键字interface
,正如前面的文章所提到的Servlet
就是一个接口,它的定义如下:
package javax.servlet;
import java.io.IOException;
public interface Servlet {
public void init(ServletConfig config) throws ServletException;
public ServletConfig getServletConfig();
public void service(ServletRequest req, ServletResponse res) throws ServletException,IOException;
public String getServletInfo();
public void destroy();
}
可以看到,定义一个接口类似于定义一个类,使用关键字interface
就可以了,当然,接口名称要遵从的命名规范也跟类名差不多。下面是我定义的一个示例接口,
public interface SomeInterface {
//这里是接口的成员,举例:
int i = 0;
void m();
default void f() {}//jdk1.8后的特性
}
如果在Eclipse中查看上述接口的大纲视图,可以看到,成员i
自动变成public、static、final的公有静态常量;成员方法m()
也自动变成public、abstract的公有的抽象方法,即便没有这些修饰符,这是Java语法规定的。
当然,这也符合接口这个概念的语义的,既然接口描述了一个标准或规范,当然就应该是公有的,而该标准或规范描述的某种能力就是接口中的抽象方法,它们自然是要由实现该接口的类来实现。不过,自Java 8之后,可以为接口添加默认方法,关键字是default
,这些默认方法具有方法体,因此可以不被实现。
可以说,接口就是抽象方法的集合,它是最高级的抽象,但它跟类其实是两个概念,它不是特殊的类,而是对类的一组需求描述,这些类要遵从接口描述的统一格式进行定义。通常这些需求都是指的某种行为特征的能力,比如可以为飞行这个行为抽象成一个接口:
public interface Flyable {
void fly();
}
实现一个接口
Java提供implements
关键字来表示实现,在定义类的时候使用该关键字即可,而且一个类可以同时实现多个接口,比如GenericServlet
这个类就实现了Servlet
、ServletConfig
、Serializable
这三个接口:
public abstract class GenericServlet implements Servlet, ServletConfig, java.io.Serializable {
}
当然,GenericServlet
这个类仍旧是一个抽象类,它还需要再被继承,HttpServlet
就是继承它,总之,最终被我们的具体类继承,因此,我们的具体类最终也就实现了Servlet
这个接口,假设我们的具体类就是HelloWorld
,那么就可以生成HelloWorld
的对象,然后可以像下面这样使用我们的这个对象:
HelloWorld hello = new HelloWorld();//生成具体类的对象-------相当于是配置部分
Servlet s = hello;//用Servlet接口的引用来指向一个具体类的对象-------相当于是配置部分
s.service();//使用接口-------相当于是外部程序面向接口编程
ServletConfig sc = hello;//用ServletConfig接口的引用来指向一个具体类的对象
sc.getServletName()//使用接口
可见,接口、抽象类、类都是一种类型,接口类型的变量可以引用实现该接口的类的对象,抽象类和类的变量可以引用继承它们的类的对象。
只不过,Java里面一个类只能继承一个抽象类或类,而一个类可以同时实现多个接口,就像GenericServlet
那样,于是那些接口类型的变量都可以引用那个类的对象,反过来说,那个实现多个接口的类是一个混合类型。这是接口的一大优势,也是抽象类不能取代接口存在的原因。
Servlet接口的使用模式
最后,我们来看看Servlet接口的使用模式:
可见,接口的使用模式都是类似的,都是上面所述的三个步骤:
- 抽象出接口,这里是
Servlet
接口,由Servlet规范抽象出来了,而Tomcat的servlet-api.jar里面定义了它; - 实现该接口,我们需要开发的
HelloWorld
、WorldHello
、OtherServlet
等等具体类; - 为外部程序配置一个实现,这里外部程序就是Tomcat,配置Servlet的实现可以用部署描述符web.xml,或者使用注解
@WebServlet
。
这样,一旦Tomcat运行,它就会根据配置生成相应的某个Servlet实现类的对象,然后赋值给Servlet引用类型的变量,而其他代码逻辑都是通过该变量来使用Servlet接口的某个抽象方法,运行时会根据引用的具体类来决定实际调用的是哪个实现类的具体方法,这就是多态。
总结
好了,现在我们知道接口的要义了,以后我们遇到了也就清楚什么含义了,我们也可以并且需要使用它来解耦我们的程序。
- 接口有硬件接口、人机接口、软件接口;
- 接口就是连接两个东西的那个公共的部分,起到交互、通信、信息交换、传输(总之是某种东西的传输、比如力、电、数据等等)的作用;
- 接口就是一组标准和规范,它描述了一段程序应该具有的某种行为特征和能力;
- 接口另外一个作用就是能达到实现(这里是名词,指的是实现该接口的程序)内部的修改不影响外部使用(当然是通过使用接口),这就叫解耦;
- Java里面,接口使用
interface
定义,实现使用implements
定义; - 一个类可以实现多个接口;
- 一个接口也是使用extends来扩展其他接口,不过可以同时扩展多个接口;
- 一个类只能继承一个类;
- 接口里的方法只能是公有的抽象方法,Java 8之后也可以有默认方法;
- 接口跟类是两个概念,它不是特殊的类,而是对类的一组需求描述,这些类要遵从接口描述的统一格式进行定义,通常这些需求都是指的某种行为特征的能力;
- 实现多个接口的类可以看作是一个混合类型;
- 抽象类可以添加具体方法,而它的子类不用任何修改;
- 我们要尽量面向接口编程;
- 接口设计要良好,保持稳定性,因为一旦需要添加方法或修改方法,那么该接口的所有实现类都需要修改,否则编译器将不让通过编译,除非添加的是默认方法。