当前位置: 首页 > 科技观察

随笔:如何向女友解释为什么Java不支持多重继承?

时间:2023-03-22 11:48:45 科技观察

要说多重继承,首先要从继承说起。继承面向对象编程语言具有三个重要的基本特征:封装、继承和多态。许多人认为继承是Java面向对象编程技术的基石。继承是指子类继承父类的特性和行为,使子类对象(实例)具有父类的属性和方法,或者子类继承父类的方法,使子类具有与父类相同的行为。Java继承是一种使用现有类的定义作为基础来创建新类的技术。新类的定义可以添加新数据或新函数,也可以使用父类的函数,但不能有选择地继承父类。Join,我们定义了一个Car类,里面有轮胎、发动机、底盘、方向盘等属性,还有行走、加油、开窗等行为。而如果我们想定义一个Bus,并重用这些属性和行为,我们可以通过继承来实现。通过继承,我们在Bus类和Car类之间建立了一定的关系,我们通常称Car为Bus的父类,Bus为Car的子类。在Java中,继承是使用extends关键字实现的。对于上面的Car和Bus,在写继承语句的时候,classBusextendsCar{}其中Bus类是子类,Car类是父类。多重继承我们上面提到的Bus和Car的关系其实是单继承的,也就是一个类只继承一个父类。在软件开发中,也存在多重继承(multipleinheritance)的情况。顾名思义,一个类同时继承多个父类。例如,维基百科给出了一个关于多重继承的例子:比如,你可以创建一个“哺乳动物”的类别,具有进食、繁殖等功能;然后定义一个子类型“猫”,它可以从父类继承上述功能,无需重新编程,同时添加自己的新功能,比如“追老鼠”。不过,“cat”也可以作为“pet”的子类,具有一些宠物特有的能力。作为一种面向对象的语言,C++支持多重继承。然而,多重继承多年来一直是一个敏感话题,反对者称它增加了程序的复杂性和歧义。Java不支持多重继承。很多人都知道Java不支持多重继承。这里要提一下,这里的继承特指使用extends关键字的继承行为。那么为什么Java不支持多重继承呢?对于这个问题,Java的创始人JamesGosling曾这样回答,“Java之所以不支持一个类继承多个类,主要是因为我们在设计之初就听了C++和Objective-C在阵营。因为多重继承会造成很多二义性问题。”Gosling老头说的二义性问题,其实就是C++支持多重继承后带来的菱形继承问题。假设我们有B类和C类,它们都继承自同一个A类。此外我们还有D类,D类通过多重继承机制继承了B类和C类。这时因为D同时继承了B和C,而B和C又同时继承了A,那么D就会因为多重继承而继承了A的两个属性和方法。这时候在使用D的时候,如果要调用A中定义的方法,就会出现歧义。因为这样的继承关系的形状类似于菱形,所以这个问题被形象地称为菱形继承问题。为了解决菱形继承问题,C++引入了虚继承。因为支持多重继承,所以引入了菱形继承问题,又因为要解决菱形继承问题,所以引入了虚继承。经过分析,人们发现我们真正想要使用多重继承的情况并不多。因此,在Java中,不允许“多重继承”,即不允许一个类继承多个父类。但是Java允许“声明多重继承”,即一个类可以实现多个接口,一个接口也可以继承多个父接口。由于接口只允许方法声明而不允许方法实现(Java8之前),这避免了C++中多重继承的歧义。Java8支持多重继承。Java不支持多重继承,但支持多重实现。也就是说同一个类可以同时实现多个类。我们知道,在Java8之前,方法不能在接口中实现。所以如果一个类同时实现了多个接口,在C++中就不会出现歧义。因为所有的方法都没有方法体,真正的实现还是在子类中。那么问题来了。Java8支持默认函数(defaultmethod),即可以在接口中定义一个带有方法体的方法。publicinterfacePet{publicdefaultvoideat(){System.out.println("PetIsEating");}}又因为Java支持同时实现多个接口,这相当于通过implements从多个接口继承多个方法。这不是变相支持多重继承吗?那么,Java是如何解决菱形继承问题的呢?让我们定义一个哺乳动物接口和一个eat方法。publicinterfaceMammal{publicdefaultvoideat(){System.out.println("MammalIsEating");}}然后定义一个Cat分别实现两个接口:publicclassCatimplementsPet,Mammal{}这时候编译会报错:error:classCatinheritsunrelateddefaultsforeat()FromtypesMammalandPet这时候要求必须在Cat类中重写eat()方法。publicclassCatimplementsPet,Mammal{@Overridepublicvoideat(){System.out.println("CatIsEating");}}所以你可以看到Java并没有帮我们解决多重继承的二义性问题,而是把这个问题留给了开发者。重写方法自己解决。参考:https://www.zhihu.com/question/24317891作者简介:漫画编程,是以漫画+音频的形式讲解枯燥编程知识的公众号。致力于让编程变得更有趣。本文转载自微信公众号“漫花编程”,可通过以下二维码关注。转载本文请联系漫花编程公众号。