![Java语言程序设计教程](https://wfqqreader-1252317822.image.myqcloud.com/cover/725/31729725/b_31729725.jpg)
3.4 接口
在面向对象程序设计中,许多程序设计语言采用多重继承机制,一个类可以从多个超类中继承相似的操作,从而在编程时可以灵活地设计程序,但是许多数据结构是不采用多重继承的,这容易使内存开销增大,给系统的维护和移植带来很大的不便。Java语言支持单重继承,为了兼容多重继承的优势,引入了接口的概念。比如编程时经常提到计算机实现了显示器接口、鼠标接口等,而不能说计算机继承了显示器接口、鼠标接口等。
3.4.1 概述
1.接口的定义
接口(Interface)是指一系列常量和方法协议的集合,它提供了多个类共同行为的方法,但并不限制这些类如何实现这些方法。Java语言使用interface关键字定义接口,它的一般书写格式为:
![](https://epubservercos.yuewen.com/1D447A/17180253504507306/epubprivate/OEBPS/Images/img00090002.jpg?sign=1739530193-CgYGw9KspK98ed7PiJgZVmn9l3UO35Ab-0-c765b101eba33ac2a20b3e025ae3a097)
例如:
![](https://epubservercos.yuewen.com/1D447A/17180253504507306/epubprivate/OEBPS/Images/img00090003.jpg?sign=1739530193-fDRaSDFPVTn6Nn9FquSaS4kmFwWO3aG8-0-e77723011406e9874689d10b59c6ef78)
说明:
(1)接口声明中的修饰符一般为public或者缺省。
(2)接口体中通常只包含常量的定义和抽象方法的声明。常量的定义可以缺省public、static和final修饰符,抽象方法的定义可以缺省public和abstract修饰符。
(3)接口体中可以由多个常量的定义和多个抽象方法的声明。例如:
![](https://epubservercos.yuewen.com/1D447A/17180253504507306/epubprivate/OEBPS/Images/img00090004.jpg?sign=1739530193-OzE67yTUopxIXmMld5WqexrelPX26w5T-0-4b577df9ce167c19b6823b938934dde2)
![](https://epubservercos.yuewen.com/1D447A/17180253504507306/epubprivate/OEBPS/Images/img00091001.jpg?sign=1739530193-mV7X8fAtGCqwCUixexVNdyVruAf38aA5-0-861c2e655f5ad981c1f4a6fbeafe194a)
(4)接口名和类名的命名规则相同,第一个字母通常要大写。接口可以存放在由package语句指定的包中,源文件名与接口名相同,扩展名为.java。
(5)Java SE的API提供了若干定义好的接口以方便程序设计,这些接口可存放在相应的包中,使用时必须要使用import语句将其导入。
(6)接口也可以实现继承,使用extends关键字声明一个接口是另一个或另一些接口的子接口。与类的单重继承不同,接口可以实现多重继承。由于接口中的常量和方法都是public修饰的,子接口将同时继承一个或多个超接口的全部常量和方法。例如:
![](https://epubservercos.yuewen.com/1D447A/17180253504507306/epubprivate/OEBPS/Images/img00091002.jpg?sign=1739530193-ShBST2k4dIrVloBryeVvPs6b3I2u35LY-0-d52b22e17d68baf63c2f818a3da49b21)
2.接口的实现
一个接口只是声明了一系列常量和抽象方法,这些方法并不知道提供哪些功能,如果不实现它,该接口是没有意义的。这个任务由提供实例数据字段和实例方法的某一个类来实现,类通过关键字implements实现一个或多个接口。它的一般书写格式为:
![](https://epubservercos.yuewen.com/1D447A/17180253504507306/epubprivate/OEBPS/Images/img00091003.jpg?sign=1739530193-6xIfvyfiybpXuP9G5VErPTJvZ7nY2S5q-0-99b5099dac2207436cb7ac17dc6ece54)
说明:
(1)修饰符和前面提到的类的修饰符相同。
(2)接口名列表是指一个类可以同时实现一个或多个接口。当实现多个接口时,接口名之间以英文半角的逗号隔开。
(3)类体中必须实现该接口或其超接口中定义的所有方法,并可直接使用其中的所有常量。如果不实现其中的某个或多个方法,该类必须被声明为抽象类。
(4)在实现接口方法时,必须将方法修饰为public,并且方法的名字、参数列表和返回类型应该与接口中定义的保持一致。
(5)如果超类实现了某个接口,其子类默认就实现了该接口,子类就不用再显式地使用implements来实现该接口了。
例题3.24 封装了接口和实现接口的类的程序。
![](https://epubservercos.yuewen.com/1D447A/17180253504507306/epubprivate/OEBPS/Images/img00091004.jpg?sign=1739530193-YBoE5QsY6oyy8uL65E4J2J6hPMsv38KJ-0-76c776396a0a7848d72a9a8c573fd73f)
![](https://epubservercos.yuewen.com/1D447A/17180253504507306/epubprivate/OEBPS/Images/img00092001.jpg?sign=1739530193-DahF6rltyrkP3StFj97Cqyp1iHrackyz-0-e9e8105af318ee0a25c2f749ac2ef4b9)
例题3.25 封装了接口继承与实现的程序。除了接口的定义方法不同,执行入口类与例题3.24相同。
![](https://epubservercos.yuewen.com/1D447A/17180253504507306/epubprivate/OEBPS/Images/img00092002.jpg?sign=1739530193-lGrI3qD7Mu3c3ZDEKeWsebJoIdcuS1IR-0-59f879438e489f5925b76b9ab77eb380)
![](https://epubservercos.yuewen.com/1D447A/17180253504507306/epubprivate/OEBPS/Images/img00093001.jpg?sign=1739530193-tqASuleFfCb0sKkX5YxQH03lYglK6Ei6-0-dba92809c24f15244286c022ff5b36fe)
3.接口与抽象类
从接口的定义上看,接口是一种引用数据类型,它的地位和class的地位是相同的。在实现方式上,接口是面向对象程序设计中典型的多态性,它完美诠释了多态的代码实现。
结合前面提到的抽象类来看,接口和抽象类在书写格式上有些类似。例如:
![](https://epubservercos.yuewen.com/1D447A/17180253504507306/epubprivate/OEBPS/Images/img00093002.jpg?sign=1739530193-IMIb0R9EP0MDT2bIkuNqQDuoLHFKpaw3-0-22da0a1784499388b56b4779d2126e90)
但二者是完全不同的两种引用类型:
(1)抽象类中的抽象方法修饰符public和abstract是不可缺省的,接口中可以缺省,默认是存在的。
(2)抽象类中既可以有常量也可以有变量,接口中只能有常量。
(3)抽象类中除了抽象方法外,还可以有非抽象方法,接口中只能有抽象方法。
(4)抽象类被继承时,只能在extends关键字后跟一个直接超类,接口被实现时,在implements关键字后可以同时跟多个接口,从形式上兼容了多重继承的优势。
例题3.26 对例题3.22中的SuperMonitor类修改成接口,CRTMonitor、PlasmaMonitor类的修改方法与LCDMonitor类似,而Test3_221可以不做任何修改。与类的向上转型对象相比,程序更容易表达面向对象的多态性,接口的通用性更强。
![](https://epubservercos.yuewen.com/1D447A/17180253504507306/epubprivate/OEBPS/Images/img00093003.jpg?sign=1739530193-pK3K0EFf1ooIOoQhsfPfAb6qiPGmKM33-0-57b967fb91784b5f0112ece505ecec47)
![](https://epubservercos.yuewen.com/1D447A/17180253504507306/epubprivate/OEBPS/Images/img00094001.jpg?sign=1739530193-Wqos4WzQgrb2Ij40T6wqtej0ygKqi29i-0-4df3ea1a0a18f0561085284991cdf23f)
3.4.2 接口的回调
接口也是一种引用数据类型,它也可以声明对象,但由于接口没有构造方法,该对象不能用关键字new初始化,它只能存放实现该接口的类的一个实例的内存引用地址。
1.接口回调
接口回调类似于C语言中的指针回调,表示一个变量的地址在某一时刻存放在一个指针变量中,该指针变量就可以操作该变量中存放的数据。Java语言中的接口回调是指把实现某一接口的类创建的对象引用赋值给该接口声明的对象,该接口对象就可以调用被类实现的接口方法。设MyCom是一个接口,MyImpleCom是实现MyCom接口的一个类,有如下语句:
![](https://epubservercos.yuewen.com/1D447A/17180253504507306/epubprivate/OEBPS/Images/img00094002.jpg?sign=1739530193-MHmHRnjWDqsccjV8DA2AJd3Mdo0Zd6ok-0-2bac364593b6db10d4cbc1ddfbedb9bd)
对象mic、mc和mc2的内存引用如图3-8所示。
![](https://epubservercos.yuewen.com/1D447A/17180253504507306/epubprivate/OEBPS/Images/img00094003.jpg?sign=1739530193-uOURq4CuBdI05Nz6rQhLTJjPXKAlqNjF-0-1df8560033d438c77e3e4d228d7c5841)
图3-8 接口回调的内存引用示意图
与上转型对象的应用相类似,接口声明的对象只能调用类中实现的接口方法,不能调用类中其他非接口方法。
例题3.27 封装了接口回调的程序。
![](https://epubservercos.yuewen.com/1D447A/17180253504507306/epubprivate/OEBPS/Images/img00094004.jpg?sign=1739530193-9JW9eem2odrWJoZhh8c1yum8N6CL8hBE-0-06f5ef3d7a11f33fd100d2df63edd0cc)
![](https://epubservercos.yuewen.com/1D447A/17180253504507306/epubprivate/OEBPS/Images/img00095001.jpg?sign=1739530193-13HdgEbCi3ocTs5yWvEMSeWaIoMSzh28-0-8446c2d9de2f8057a8a775c785a7f36c)
2.接口回调的多态性
由接口产生的多态性是指不同的类在实现同一个接口时可能具有不同的结果,接口声明的对象在回调接口方法时就可能具有多种形态。
例题3.28 封装了接口多态实现的程序。
![](https://epubservercos.yuewen.com/1D447A/17180253504507306/epubprivate/OEBPS/Images/img00095002.jpg?sign=1739530193-zV8Rz0HfZANPTyJNBwv9EBI3Jwzm0Pfg-0-5ca754d9c400e8fee8266c45b2a2629a)
![](https://epubservercos.yuewen.com/1D447A/17180253504507306/epubprivate/OEBPS/Images/img00096001.jpg?sign=1739530193-jku6gKUqL34KuKXZ0aGY0URi7jBoL60Z-0-406abe202e2da587e25d6353bd19277d)