Java为什么不支持多继承
前面我们提到过“继承则好比武侠中的传承血脉,子类可以继承父类的属性和方法,并且可以根据需要进行自我扩展,这样就不用从头造轮子,提高了代码的重用性和可维护性。”,在java中支持接口实现多继承,类却不能多继承,但是这个问题在Java 8之后也不绝对了。
那么,是不是又很很想知道,为什么Java中不支持同时继承多个类呢?
多继承
一个类,只有一个父类的情况,我们叫做单继承。而一个类,同时有多个父类的情况,叫做多继承。
在Java中,一个类,只能通过extends关键字继承一个类,不允许多继承。但是,多继承在其他的面向对象语言中是有可能支持的。
像C++就是支持多继承的,主要是因为编程的过程是对现实世界的一种抽象,而现实世界中,确实存在着需要多继承的情况。比如维基百科中关于多继承举了一个例子:
例如,可以创造一个“哺乳类动物”类别,拥有进食、繁殖等的功能;然后定义一个子类型“猫”,它可以从父类继承上述功能。
但是,"猫"还可以作为"宠物"的子类,拥有一些宠物独有的能力。
所以,有些面向对象语言是支持多重继承的。
但是,多年以来,多重继承一直都是一个敏感的话题,反对者指它增加了程序的复杂性与含糊性。
菱形继承问题
假设我们有类B和类C,它们都继承了相同的类A。另外我们还有类D,类D通过多重继承机制继承了类B和类C。
这时候,因为D同时继承了B和C,并且B和C又同时继承了A,那么,D中就会因为多重继承,继承到两份来自A中的属性和方法。
这时候,在使用D的时候,如果想要调用一个定义在A中的方法时,就会出现歧义。
因为这样的继承关系的形状类似于菱形,因此这个问题被形象地称为菱形继承问题。
而C++为了解决菱形继承问题,又引入了虚继承。
因为支持多继承,引入了菱形继承问题,又因为要解决菱形继承问题,引入了虚继承。而经过分析,人们发现我们其实真正想要使用多继承的情况并不多。
所以,在 Java 中,不允许“实现多继承”,即一个类不允许继承多个父类。但是 Java 允许“声明多继承”,即一个类可以实现多个接口,一个接口也可以继承多个父接口。由于接口只允许有方法声明而不允许有方法实现(Java 8以前),这就避免了 C++ 中多继承的歧义问题。
但是,Java不支持多继承,在Java 8中支持了默认函数(default method )之后就不那么绝对了。
虽然我们还是没办法使用extends同时继承多个类,但是因为有了默认函数,我们有可能通过implements从多个接口中继承到多个默认函数,那么,又如何解决这种情况带来的菱形继承问题呢?
为了解决菱形继承的问题,Java采用了“接口解决繁琐的继承,实现类解决多重继承”的原则,提供了多种机制来避免冗余代码和不确定性的问题:
- 接口:Java允许一个类实现多个接口,这样就避免了子类继承两个父类的情况。
- 默认方法:Java 8引入了默认方法,在接口中提供具体的方法实现,从而避免了重复实现同一个方法。
- 接口的继承:Java允许一个接口继承另一个接口,这样就可以将公共的代码提取到接口中进行复用。
- 组合:Java推荐使用组合而不是继承来完成代码复用。在组合中,一个类包含另一个类的对象作为成员变量,从而可以利用其它类的功能,而不必继承其所有的属性和方法。
更多内容,敬请关注公众号“代码教父”