我想知道在java中处理多重继承有什么问题?也就是说,当我需要在 Java 中继承几个抽象类时,我正在做一些事情,但我意识到这是不允许的,或者至少我尝试了一些我已经搜索了一段时间但我没有找到任何可以解释原因的东西。extends
extends CLaseA,ClaseB
所以有人可以帮我知道为什么吗?另外,既然不可能做到这一点,我还有什么其他选择?
我想知道在java中处理多重继承有什么问题?也就是说,当我需要在 Java 中继承几个抽象类时,我正在做一些事情,但我意识到这是不允许的,或者至少我尝试了一些我已经搜索了一段时间但我没有找到任何可以解释原因的东西。extends
extends CLaseA,ClaseB
所以有人可以帮我知道为什么吗?另外,既然不可能做到这一点,我还有什么其他选择?
简短的回答
可以说,基本上有两种类型的多重继承:类实现多重继承 和类型实现多重继承。
Java 的创建者明确禁止前者。因此,任何从多个类扩展一个类的尝试都会导致错误。这样做的主要原因是:
所有这些将在长答案中更详细地解释。
长答案
我们都知道继承意味着什么。简而言之,它是从像我们这样的人那里得到一些东西并能够享受它。
在 OOP中,继承意味着一个对象从另一个对象接收(继承)某些东西以便使用它。
在 Java 中表达这一点的词是
extends
. 当一个类扩展多个类时,这称为多重继承。例如,该类
VehiculoMotor
扩展了类VehiculoDiesel
和VehiculoGasolina
.现在,根据Java 文档,我们可以讨论两种类型的多重继承:实现多重继承(类的)和实现类型的多重继承(带有接口)。
1.多重实现继承(类)
实现多重继承是从多个类继承方法定义的能力。
这种类型的继承在 Java 中是不可能的。
为什么Java不支持多重继承?
相同的文档(上面的链接)解释了一些原因:
命名冲突和歧义。当支持这种多后继超类的编程语言的编译器包含同名的方法时,它们有时无法确定访问或调用哪个成员或方法。
此外,程序员可能会通过向超类添加新方法无意中引入命名冲突。
实现多重继承时会出现的一个典型问题就是所谓的菱形问题。
我们来看一张图:
如果类
VehiculoDiesel
和VehiculoGasolina
具有相同名称的方法,则会出现此问题。让我们假设两者都有一个方法llenar()
。到目前为止一切都很完美。但是,由于该类VehiculoMotor
是从这两个类扩展而来的。如果我们这样做:我们要填充什么
camion
,柴油或汽油?这是一个棘手的问题,不是吗?我们可以破坏卡车。这就是在 Java 中无法实现多重继承的主要原因。
2. 使用类型实现多重继承
从 Java 8 开始,由于引入了默认方法,可以使用接口来使用多继承形式的实现。也就是说,一个类可以实现 (
implements
) 多个接口,这些接口可以包含具有相同名称的默认方法。Java 编译器提供了一些规则来确定特定类使用的默认方法。Java 编程语言支持多类型继承,这是一个类实现多个接口的能力。一个对象可以有多种类型:它自己的类的类型和该类实现的所有接口的类型。这意味着如果一个变量被声明为接口的类型,那么它的值可以引用从任何实现该接口的类实例化的任何对象。这在 Java 文档的使用接口作为类型部分中进行了讨论。
与实现多重继承一样,一个类可以继承在它扩展的接口中定义(作为默认或静态)方法的不同实现。在这种情况下,编译器或用户必须决定使用哪一个。
这解决了上面提到的菱形问题,这是Java语言中防止类之间的多重继承的主要原因。
以图片中的相同示例为例,我们可以使该类
VehiculoMotor
实现两个接口LlenableGasolina
,并且LlenableDiesel
每个接口都有一个默认方法llenar()
。界面
LlenableDiesel
界面
LlenableGasolina
有了这样的两个接口,我们可以创建一个类,在该类
VehiculoMotor
中,程序员可以使用该类实现的任何接口的默认方法来覆盖llenar()
指示其中将调用两个方法中的哪一个的方法。因此,如果要调用柴油车对应的方法:llenar()
相反,在汽油车上调用该方法:此代码的输出:
班级
VehiculoMotor
那么它会是这样的:
更多细节
几年前(2002 年)在JavaWorld中讨论了这个主题。
Java 不允许多重继承的原因包括:
他们说选择使用多个接口作为解决方案:
如果您想更深入地了解,在那篇文章中有指向其他有趣文章和讨论的链接。
要添加到A.Cedano 的答案,还有两个额外的考虑因素:
Java 在接口级别支持多重继承。例子:
从 Java 8 开始,接口的功能通过默认方法得到了扩展,也就是说,接口可以提供其方法的实现。这意味着通过扩展/实现多个接口的接口/类现在可能陷入菱形问题。编译器通过要求具体类为冲突方法提供实现来解决这些情况。例子:
离开:
James Gosling 在创建 java 时排除了它。他指出,多重继承并没有给 C++ 带来很大的优势,而且通过正确使用接口可以更好地实现它。
我真的不明白这是什么问题?在我看来,解决方案就像必须指定我们要调用的方法来自哪个父类一样简单,只要它在其他父类中重复。Java、.Net、ruby... 和任何其他面向对象语言的开发环境应该在每次这种“冲突发生”时警告程序员,用聚光灯、红灯或他们想要的任何东西,就是这样!几十年来,他们已经被如此愚蠢的事情淹死了,看起来他们不想再呼吸了。多重继承是非常必要和有用的。