Why Multiple Inheritance is not Supported in Java?

2025年3月27日 | 阅读 6 分钟

在 Java 中,面向对象特性使得类可以继承其他类的特性和属性。在本节中,我们将讨论Java 中的多重继承,并讨论Java 为何不支持多重继承。

什么是多重继承?

从多个父类继承行为和功能的类被称为多重继承。许多面向对象编程语言(如 C++)都支持多重继承,Java 不支持它

复杂性管理、歧义解决和代码管理问题是导致此设计决策的一些因素。

为什么 Java 不支持多重继承?

设计理念是 Java 不支持多重继承的主要原因。设计理念优先考虑代码的清晰度和简洁性,而不是代码的复杂性。为了克服这种混乱和代码的清晰度,Java 决定禁止多重继承。

在单重继承中,子类仅从一个父类继承,即直接的超类。它保证了清晰的层次结构。它还可以使代码维护更简单,更不容易导致冲突。但在多重继承的情况下,情况并非如此。

多重继承示例

为了更好地理解,请参考下图。

Why Multiple Inheritance is not Supported in Java?

在上图中,我们有一个子类、两个父类(Parent1 和 Parent2)和一个基类。父类和基类都有一个名为 print() 的方法。

子类继承自两个父类(Parent1 和 Parent2),这两个父类都继承自一个共同的基类。两个父类都重写了基类中的一个方法(print())。

在这种情况下,当子类尝试继承 print() 方法时会出现歧义。

由于两个父类都提供了它们自己的 print() 方法的实现。因此,如果子类没有提供自己的重写,它应该继承哪个版本就存在歧义。

这种歧义使得代码更难理解、维护和调试。

Java 通过不支持类的多重继承来避免这种情况。让我们看看如何解决这个问题。

如何在 Java 中实现多重继承?

Java 仅通过接口支持多重继承,其中一个类可以实现多个接口。Java 中类的多重继承是不可能的,但通过接口是可以实现的,其中一个类可以实现多个接口。接口允许类继承来自各种类或来源的方法和功能。

使用接口

Java 接口是抽象方法的集合,它指定了实现类必须遵循的行为。它通过勾勒出每个类的类的方法来充当类的蓝图。

接口在指定行为方面提供了一定程度的抽象,但不能像类一样被实例化。在 Java 中,一个可以成功地实现多个接口以实现多重继承。

语法

使用接口的多重继承 Java 程序

示例

编译并运行

输出

 
Hello

接口并非在 Java 中实现多重继承的唯一方法。我们还可以通过使用组合方法来实现多重继承。

使用组合

这种方法使用目标类来创建适当类的对象,然后将方法调用分配给这些对象,以在不涉及继承的复杂性的情况下实现代码重用。它可以促进更好的封装和代码的灵活性。让我们通过一个插图来讨论这种方法。

使用组合的多重继承 Java 程序

示例

编译并运行

输出

 
An animal is eating.
The vehicle is being driven. 

解释

在上面的例子中,Animal 和 Vehicle 两个类代表了两种不同的行为。为了整合这些行为,AnimalVehicle 类从这两种类型创建对象。AnimalVehicle 类的 eat() 和 drive() 方法将相应的方法调用转移到相关的 Animal 和 Vehicle 实例。

通过利用组合,可以实现一种多重继承,其中一个类从多个来源继承行为。通过这种方法,我们能够在不遇到问题的情况下合并其他类的功能。

需要注意的是,虽然组合提供了一种实现类似多重继承的行为的方式,但它不像接口那样具有灵活性和模块化程度。方法调用必须手动委托,在某些情况下可能会很麻烦。

菱形问题

Java 中,菱形问题与多重继承有关。有时,它也称为致命菱形问题死亡菱形。菱形问题就是其中一个挑战,它出现在多重继承的上下文中。

当一个类继承自两个或多个类,而这两个类又共享一个共同的超类时,就会出现菱形问题。这种情况在继承层次结构中造成了歧义,如图所示的菱形依赖关系图,因此得名菱形问题。

这是多重继承允许的结果而可能出现的歧义。它对其他 OOP 语言来说是一个严重的问题。它有时被称为死亡菱形

解决方案策略

为了在涉及默认方法的场景中解决菱形问题,Java 提供了几种策略。

  • 重写默认方法:类 D 可以重写默认的 display() 方法并提供其实现。这确保了清晰度并消除了歧义。
  • 调用所需方法:类 D 可以使用接口名称从其中一个接口调用方法的所需实现。
  • 接口继承:如果接口 B 和 C 本身扩展了接口 A,则类 D 可以从接口 A 继承默认方法的实现,从而缓解了冲突。

菱形问题的解决方案

菱形问题的解决方案是默认方法接口。我们可以使用这两样东西来实现多重继承。

默认方法类似于抽象方法。唯一的区别是它在接口内部定义,并带有默认实现。我们不需要重写这些方法,因为它们已经实现了这些接口。

接口的好处是它们可以具有两个不同接口中具有相同名称和签名的相同默认方法。它允许我们从一个类实现这两个接口。我们必须使用接口名称显式重写默认方法。

语法

菱形问题 Java 程序

示例

输出

 
the display() method of DemoInterface1 invoked
the display() method of DemoInterface2 invoked

在上面的示例中,我们看到两个接口具有相同的名称和签名。我们通过接口名称调用了该方法,这并没有在方法之间造成任何歧义。