每个学过Java的程序员,当学到“接口”这一章节时,教科书里一般都会写这样一句话:“Java没有多继承,但引入了接口,通过接口可以实现类似C++中的多重继承的目的。”然后……我们就陷入了无限的纠结,至少我是这样的。这句话很容易让初学者理解成“使用接口的目的是为了实现类似于C++中的多重继承”,然后我们就一直会耿耿于怀与“究竟接口是如何实现多重继承的?Java既然不允许多重继承,咋还能通过接口实现多重继承的?到底是怎么实现的?而且实现多个接口与继承多个类完全不是一回事啊???”。
有经验的程序员都会说,对于接口以及其它的一些概念的理解及运用,只有通过实践才会逐渐有深入的体会。说的很正确。但是对于刚入门的又热爱思考的同学们来讲,遇到此类矛盾至少要给人一个完美的解释吧。下面,我就讲一下我的理解,可能理解的有偏颇或不到位的地方,欢迎批评指正。
一、Java不支持多继承
Java不支持多继承! Java不支持多继承! Java不支持多继承!(这里是针对类,不是接口,接口允许多继承。)不要再去纠结究竟Java是如何实现类似于C++里的多继承的了,Java压根不鼓励、不支持、不允许这样做。为什么?
1、最常见的问题就是继承的成员同名而产生的二义性问题。两个基类中有同名方法的时候,你不得不在子类的调用中指明此方法出自哪个基类,这样会很麻烦。
2、钻石问题/菱形问题:假如类A派生了B和C,而B和C共同派生了D,麻烦就出现了。A是D的父类没错,但是有两条路径,这就导致了D类中有很多重复的方法和名字相同的数据成员。这样保留多份数据成员的拷贝,不仅占用较多的存储空间,还增加了访问这些成员时的困难,容易出错。
3、使用父类指针指向子类对象变成了一件复杂的事情。
关于这方面详细的解释,可以参考谭浩强老师写的C++的那本书。
二、接口的作用
通过前面的讲解我们知道了,Java中的接口根本不是为了继承而设计的,那它存在的意义是什么呢?
1、接口是一种规范,是一种协议,你的任务只要符合这个标准,我的程序就可以处理。总结来说:按照接口规范进行方法调用,就能获得所期望的功能;按照接口规范实现接口的方法,就能提供所期望的功能。
2、解耦。作为接口定义者来说:定义接口这个动作将会规定一个协议,并可将此协议提供给其他提供者进行实现,实现内容也可随意变化,而接口实例使用者不必关心接口实现的细节。总结就是:接口和接口的实现分离,在更换实现类的时候,不用更换接口。
3、实现(运行时)多态。多态的实现方式有两种:函数的重载和覆盖。重载是针对同一个类里的函数来说的, 而覆盖是针对父类和子类而言的。我们知道,Java建议尽量少用继承,如果不继承,又怎么覆盖呢?不过有了接口,我们就可以通过实现接口,来实现多态了。在多态中,需要将子类的引用赋给父类对象,只有这样该引用才能够调用父类的方法和子类的方法,这也就是“向上转型”。
三、接口中定义的成员变量为什么默认为public static final的?
public:这个很好理解,成员变量就是要给实现它的类使用的,如果实现类不能使用它,则就没有了存在的意义。
static:static是要确保该变量只有一份,因为一个类可以实现多个接口,如果出现重名的变量该怎么区分呢?这就又出现了在继承中存在的问题:继承的成员同名产生的二义性问题。
final:想想,如果不是final的,那么意味着每一个实现了该接口的子类都可以去修改这个变量。我们定义的接口是定义给大家用的,是static的,如果允许更改,那凡是实现了该接口的类都会跟着受影响,因此不能给你修改的权限。
以上是我关于一点疑惑的一个小总结,自己水平有限,暂时先写这么多。等以后有了新的理解和收获,会继续更新。











网友评论