《编程导论(Java)·4.3Java接口》
随着Java8的出现,本节面临尴尬的局面。这里首先按照原有的Java语言设计思路(Java8之前)介绍Java接口,再看看Java8对Java语言设计思路的破坏。
强大而有用的机制
【p142:类甚至是abstract class,理论上都包含实现,因此类是接口和实现的综合体,如[3.1.3 接口与实现分离]所述。如果说抽象方法是纯粹的接口、脱离了实现的接口,那么Java接口就是这些纯粹的接口组成的数据抽象。Java接口只能够拥有抽象方法,它不涉及任何实现,也不能创建其对象(这一点和抽象类一致)。因此,Java接口纯粹是契约的集合,是一种程序设计的表达方式。从数据抽象的角度看,能够在不定义class的同时又可以定义type,将是程序设计中强大而有用的机制。】
按照接口与实现分离原则,用户仅需要了解接口。每一个抽象方法都是一个纯粹的接口,它不得不与实现相分离。抽象方法是功能抽象的最高形式。在抽象方法的基础上,有了abstract class——类层次的元素,它理论上是接口和实现的综合体;而Java接口纯粹是契约的集合,它以跨越类层次的方式定义type,是一种程序设计中强大而有用的机制。
【p144
接口具有下述性质。
(1)接口不提供代码重用性。接口并不能使你获得代码继承的好处,它没有代码重用能力。接口的意义在于获得程序设计上的高度可维护性。
(2)接口能够通过多继承进行扩展父接口。Java支持接口多继承。interface A extends B, C, D{}
(3)接口不能升级。定义接口时要考虑周全,因为接口有个十分尴尬的限制:如果定义了接口,将接口送给客户程序员使用,这时定义的接口就不能修改。因为在接口中添加一个方法,会导致老版本接口的所有实现类的中断。为了达到在接口中增加一个方法的目的,只能派生/创建一个新的接口。(所以,Java接口天然符合OCP/开放封闭原则)】
常量接口问题
在一个Java接口中定义一系列静态常量,其它类通过import static语句引入和使用这些常量,这一“常量接口模式”在《Effective Java(第2版)·第19条》中被批评——常量接口模式是对接口的不良使用。
当然,《Effective Java(第2版)·第19条》的理由有些牵强。为了使用常量接口A,只有最愚蠢的人会让自己的类B implements A,而他提供的方案——不可实例化的工具类,通过类名访问常量(包括使用static import),与使用常量接口模式,并没有本质的区别。
在我们所使用的常量不会发生变化的情况下,使用常量接口和不可实例化的工具类事实上都可以;
在我们所使用的常量会发生变化——比如公司名为Sun后来改为oracle,所有使用了其常量的类都需要重新编译。因为命名常量不需要占用本类的内存空间。它可能保存在客户类型的常量池中或方法的字节码中(p40,表1-2).
package semantics; /** * 常量接口/不可实例化的工具类 */ public class Const{ public static final int X = 100; private Const() { } }
在另外的包中有用户类
package semantics.staticDemo; import static semantics.Const.*; public class UseConst{ static void test(){ System.out.println("semantics.Const.X is "+X); } }
两者都编译后,执行UseConst.test, 输出为:semantics.Const.X is 100
将Const的X变化为200,编译Const后,直接执行UseConst.test,输出为:semantics.Const.X is 100
重新编译UseConst,再执行UseConst.test, 输出为:semantics.Const.X is 200
虽然我也认为:常量接口模式是对接口的不良使用。但是原因不是技术上的,而是感觉上的。既然可以使用不可实例化的工具类——抽象类或者仅有private构造器的类,那么就不要使用常量接口,让Java接口作为纯粹的契约的集合。
所以,【语法上,Java接口(interface)是定义abstract方法和静态命名常量的Java程序单元。因为接口中命名常量的应用非常有限,通常的讨论中一般忽略它。】
Java8的破坏
Java8(通过默认方法)抹杀了Java接口与抽象类的本质区别。接口的性质1和3,不再成立;而“接口不能升级”正是Java8需要突破的地方。
《4.3.2 多重继承问题3. 问题仍然存在》Java8在Java接口方面的唯一好处,反证了“接口能够多继承,并不意味着Java是为了解决多继承问题而引入接口机制,也不意味着接口机制能够解决程序设计对多继承的需求”。
【为什么Java接口能够避免多继承的复杂性,关键在于它仅仅包含abstract方法。】
【p147 从设计的角度看,Java接口放弃了多继承的内在/固有目标,而显得是一个权宜之计。】
.....................
返回 导航