java不支持多继承思考

Q:Java不支持多继承?

A:很不幸,的确是的。几乎任何一本教科书上都是这么写的:Java遵循单根继承结构。

 

Q:为什么一定要多继承?

A:老掉牙的例子:沙发床既是沙发又是床。

 

Q:继承意味着什么?

A:继承意味着“is-a”关系。但这个说法不准确。很多“古老”的C++书上这么说:继承意味着两种关系:is-a和like-a。

 

Q:like-a意味着什么?

A:不要忘了,对于早期那些刚从C迁移到C++的程序员,也就是刚从面向过程转向面向对象程序设计的程序员而言,继承最显眼之处在于:代码重用。有理由相信,一个C++程序员继承了一个类,并不是因为“A is a B”,而只是因为“A 看上去和B很像,二者只有细微的差别”,通过继承和重写可以节省很多代码。

事实上,即使在Java程序设计中我仍然常常这么做。

 

Q:还有必要like-a吗?

A:当面向对象的理论和语言都已经成熟到了今天这样。我们已经有足够的理由把like-a的继承关系扫进垃圾堆了。通过仔细、严谨的设计和分析,我们可以构造出严格满足is-a关系的继承结构。例如,我们将A和B中“看上去很像”的公共部分剥离出来,作为一个抽象类C。然后A和B分别继承自C,这样多好!

但很不幸这只是理论。现实是:即使在最权威的Java程序——J2SE的标准API中,仍然存在这这种like-a的继承关系。例如java.sql.Data类。

 

Q:like-a做错了什么?

A:like-a的邪恶之处在于:它破坏了继承的可替代性。

基于is-a的继承具备可替代性,即凡是可以出现父类的地方,都能用子类来替代。因为子类“是一个”父类,所以父类能做的一切,子类都可以做。

like-a破坏了这种约定。因为like-a关系的两端只是“看上去很像”,并不具备逻辑上的“是一个”的关系。所以不保证子类能做父类能做的任何事。

毕竟,like-a的继承只是为了代码重用的方便,它不保证二者逻辑上的真正关系!

 

Q:对接口(interface)的继承(实现)意味着什么?

A:很明显,对接口的实现一定是is-a的“继承”。如果允许我把implements当作一种继承的话。

理由:因为like-a继承的目的仅是代码重用。而接口中只有方法声明没有方法体,不存在代码重用的可能性。

 

Q:对接口的is-a继承和对父类的is-a继承有区别吗?

A:有区别。

当继承(实现)一个接口时,我们的动机是"单纯"的:继承接口。

当继承一个父类时,我们不仅继承了父类的全部接口,还继承了父类的实现。也就是说,这里包含了代码重用的目的,即潜在的包含了like-a的继承。

 

Q:继承接口和继承实现,有什么区别,有什么关系?

A:首先,实现是对接口的实现。因此如果继承了实现,必须先继承了接口。

这也解释了为什么Java中只有单纯对接口的继承(implememnts),同时对接口和实现的继承(extends),却没有单纯对实现的继承。

同时,is-a的目标是继承接口,但可能附带继承可接口的实现。

like-a的目的是继承实现(代码重用),虽然继承了接口,却纯属不得已而为之。对继承而来的接口也可能不加保护得修改破坏。这也就是为什么like-a破坏了继承的可替换性。

 

Q:这么说,对接口的完好继承保证了继承的可替换性?

A:完全正确。

 

Q:是否会有一天,我们可以把对接口的继承,和对实现的继承明确区分开来?

A:我期待有一天,一门新的语言会提供这样的功能。如果在Java上增加这一语言机制,我想可能是这样。(注意:是语言机制,而不是通过API!)

public class A implements (interface of B){ ...}

也就是说,允许我们直接将一个类的接口从这个类中剥离出来。也许这样,java基于接口和内部类的多继承解决方案才会更完美

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值