Java 为什么不支持多继承?

手册/FAQ (480) 2015-10-01 15:04:13

  先从Java 8之前说起。要区分“声明多继承”与“实现多继承”。Java是不允许“实现多继承”,简称不允许“多继承”。但是Java支持“声明多继承”——Java的接口的多继承。接口只允许有方法声明而不允许有实现,因而不会出现像C++那样的实现多继承的决议问题;抽象类可以有方法实现,但要遵循Java类的单继承限制,也避免了实现多继承的问题。然后,从Java 8开始,接口允许为方法提供“默认实现”了——默认方法,因而实质上Java 8的接口多继承其实也会涉及到实现多继承,并且语言层面有专门规定去解决实现多继承时选择哪个版本的问题——哪个都不选择,而是在发现会继承多个默认方法实现并且没有override时报错,逼使用户显式override可能冲突的方法。

 

  举一个多重继承的例子,我们定义一个动物(类)既是狗(父类1)也是猫(父类2),两个父类都有“叫”这个方法。那么当我们调用“叫”这个方法时,它就不知道是狗叫还是猫叫了,这就是多重继承的冲突。

 

  而java对此的解决方法是,一个物体的本质只能有一个。一个动物只能是狗或只能是猫,如果你想创造一个会玩毛线球会玩激光(被激光玩?)的狗,那么只需要创造一个描述这类行为的接口(就叫玩耍吧),然后在自己的类里面实现“玩耍”接口,具体实现这些玩的行为,最终你同样会得到一个既像狗又像猫的动物。如果你想让这个动物叫起来像猫而不是狗,那么使用覆写(override)机制,子类里重新定义“叫”这个行为即可。但是无论如何,这样得到的类是绝对不会有多重继承的冲突的。

 

  再来说说abstract class和interface的区别。

 

  abstract class的核心在于,我知道一类物体的部分行为(和属性),但是不清楚另一部分的行为(和属性),所以我不能自己实例化。还是刚才那个例子,如果你有个abstract class叫哺乳动物,那么你可以定义他们胎生,恒定体温等共同的行为,但是具体“叫”这个行为时,你得留着让非abstract的狗和猫等等子类具体实现。

 

  interface的核心在于,我只知道这个物体能干什么,具体是什么不需要遵从类的继承关系。比如上述的“玩耍”interface,狗有狗的玩法,猫有猫的玩法,妖魔鬼怪机器人都可以玩耍,只要你告诉我这个物体有玩耍接口,我就能让它玩起来。

 

  所以abstract class和interface是不能互相替代的,interface不能定义(它只做了声明)共同的行为,事实上它也不能定义“非常量”的变量。而abstract class只是一种分类的抽象,它不能横跨类别来描述一类行为,它使得针对“别的分类方式”的抽象变得无法实现(所以需要接口来帮忙)。而多重继承不但会造成冲突,还让一个类变得不伦不类,看不出这个类的本质,所以java毅然舍弃掉了这个祸害。

THE END