Java为什么不能继承多个父类

链接:https://www.zhihu.com/question/21476063/answer/18351313
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

多重继承是一件很复杂、很容易产生问题的功能。它跟Goto语句一样,利弊交织。
以下分两部分叙述,第一部分是Python多重继承遇到的麻烦,第二部分是Java和Ruby如何折中多重继承需求。

第一部分

Python是支持多重继承的,但为了解决多重继承的方法查找顺序问题(被称为MRO),有一场苦难史:

1. 传统模式

直接使用深度优先算法(并且,从左向右),每个类选择其第一次出现的位置。比如

class A:
  def save(self): pass
class B(A): pass
class C:
  def save(self): pass
class D(B, C): pass

作为D类的一个实例,它的成员寻找顺序是:D、B、A、C。
但当碰到如下这样一个“菱形继承”就麻烦了:

class A:
  def save(self): pass
class B(A): pass
class C(A):
  def save(self): pass
class D(B, C): pass

作为D类的一个实例,寻找顺序也是D、B、A、C,但调用其save方法时,到底是调用A中的呢?还是C中的呢?直观上看,应该是C。这里有产生矛盾了。

2. Python2.2的new-style class模式

Python2.2中引进了new-style class,说白了就像java一样,所有类都继承自最根本的object类。这就让“菱形继承”变成十分普遍,于是只能改变MRO策略。仍然使用深度优先搜索、从左向右,但是每个类选择其最后一次出现的位置。这样一来,对上面的“菱形继承”就处理比较完美了,形成的顺序是:D、B、C、A,越是公用基础类,越放在后面。但是,碰到交叉继承,就又懵了
这里写图片描述
这里,X和Y都继承自O,A继承(X,Y)(注意,有先后顺序),B继承(Y,X),再有个最下面的类继承(A,B)。
按照上述算法出来的结果是:?、A、B、Y、X、O。这就有些奇怪了,明明A在B前,A继承的X在Y前,可为啥X的优先级比Y要低呢?

3. C3算法

1996年,一帮牛人写了一篇文章A monotonic superclass linearization for Dylan,提供了一个基于层级计算的线性MRO算法,被称为C3,整体上比较合理了。(算法不详说了)在2012年被加入了Dylan语言,2007年加入了Python2.3,此外还有Perl 6、Parrot等语言之中。这样虽说基本解决了计算问题,但多重继承本身就有很多让人疑惑的地方,比如:
这里写图片描述

第二部

多重继承那么复杂,可单一继承又那么拘束,咋办呢?

1. 接口继承

Java就是那么做的,只允许单一继承类(方法的实现),但可以继承多个接口(方法的定义)。

Java的接口继承功能,既实现了静态语言的多重继承性,又避免了多重继承的数据构造的冲突和类层次的复杂性。但是,我们并不能说接口是解决问题的完美方案。接口也有不能共享实现的缺点。本来只是为了跨越继承层次来共享代码,现在却需要另外生成一个独立对象,而且每次方法调用都要委派给这个对象,这实在是不太合理,而且执行的效率也不高。——《松本行弘的程序世界》

2. Mix-in

这是Ruby所推崇的,最初在Lisp中开始使用。规则如下:
通常的继承都是单一继承。
第二个以及两个以上的父类必须是Mix-in的抽象类(即不能单独生成实例,不能继承普通类)。
这种规则下,既能够保持单一继承的结构,又能用Mix-in来共享方法的实现。

结论

对于多重继承的实现方式。其实并不应该像很多人说的那样使用实现多个接口实现的。如果这样,将产生大量的“CTRL C+CTRL V”,当你发现你大量的CTRL C+CTRL+V时,就几乎可以断定。你的代码写得不好了。首先,在Thinking in Java里面,作者已经指出——如果确定在不需要多态(把子类转为父类)的情况下,应该优先考虑组合而不是继承。至于原因,我认为是继承本身就是一件很复杂很麻烦很谨慎的事情。以致于多少大牛在吐槽面向对象?

“实现上的继承就跟过度使用goto语句一样,使程序拧巴和脆弱。结果就是,面向对象系统通常遭受复杂和缺乏复用的痛苦。” — John Ousterhout( Tcl and Tk 的创始人) Scripting, IEEE Computer, March 1998

“面向对象编程语言的问题在于,它总是附带着所有它需要的隐含环境。你想要一个香蕉,但得到的却是一个大猩猩拿着香蕉,而其还有整个丛林。” — Joe Armstrong(Erlang语言发明人)

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值