为什么 Java 没有多重继承,却允许实现多个接口?

Java 不支持多重继承,但允许实现多个接口。为什么?

207016 次浏览

因为接口只是一个契约,而类实际上是一个数据容器。

出于同样的原因,C # 不允许多重继承,但允许您实现多个接口。

从 C + + w/多重继承中学到的教训是,它导致的问题比它的价值还要多。

接口是类必须实现的事物的契约。您不会从接口获得任何功能。继承允许您继承父类的功能(在多重继承中,这可能会非常令人困惑)。

允许多个接口允许您使用设计模式(如 Adapter)来解决您可以使用多重继承解决的相同类型的问题,但是以一种更加可靠和可预测的方式。

因为接口只指定类正在做的 什么,而不是它正在做的 怎么做

多重继承的问题在于两个类可以定义做同样事情的 不同的方式,而子类不能选择选择哪一个。

因为即使在 不行说“嘿,那个方法看起来很有用,我也要扩展那个类”时,继承也会被过度使用。

public class MyGodClass extends AppDomainObject, HttpServlet, MouseAdapter,
AbstractTableModel, AbstractListModel, AbstractList, AbstractMap, ...

实现多个接口非常有用,并且不会给语言实现者和程序员带来太多问题。所以这是允许的。多重继承虽然也很有用,但会给用户带来严重的问题(可怕的 死亡之钻)。你用多重继承做的大多数事情也可以通过组合或者使用内部类来完成。因此,多重继承是被禁止的,因为它带来的问题多于收益。

我的一个大学老师是这样跟我解释的:

假设我有一个类,这是一个烤面包机,另一个类,这是核弹。他们可能都有“黑暗”设置。它们都有一个 on ()方法。(一个有关() ,另一个没有。)如果我想创建一个类,它是这两个类的子类,如你所见,这个问题可能会在我面前爆发。

因此,主要问题之一是,如果您有两个父类,它们可能具有相同特性的不同实现ーー或者可能具有相同名称的两个不同特性,如我的讲师的示例所示。然后你必须决定你的子类要使用哪一个。当然,有一些方法可以解决这个问题ーー C + + 就是这样做的ーー但 Java 的设计人员认为这会使事情变得过于复杂。

但是,使用接口,您描述的是类能够做的事情,而不是借用另一个类的方法来做某些事情。与多个父类相比,多个接口不太可能导致需要解决的棘手冲突。

例如,类 A 有一个 getSomething 方法,类 B 有一个 getSomething 方法,类 C 扩展了 A 和 B。如果有人打电话给 C. getSomething 会发生什么?无法确定要调用哪个方法。

接口基本上只是指定实现类需要包含哪些方法。实现多个接口的类只是意味着类必须实现来自所有这些接口的方法。这不会导致上述任何问题。

据说,对象状态是相对于其中的字段来引用的,如果继承了太多的类,就会变得模糊不清。这是链接

Http://docs.oracle.com/javase/tutorial/java/iandi/multipleinheritance.html

考虑一个场景,其中 Test1、 Test2和 Test3是三个类。Test3类继承 Test2和 Test1类。如果 Test1和 Test2类具有相同的方法,并且您从子类对象调用它,那么调用 Test1或 Test2类的方法将存在模糊性,但是对于接口没有模糊性,因为在接口中没有实现。

由于这个话题并不紧密,我将发布这个答案,我希望这能帮助人们理解为什么 java 不允许多重继承。

考虑以下类别:

public class Abc{


public void doSomething(){


}


}

在这种情况下,类 Abc 没有扩展任何东西对吗?没有这么快,这个类隐式扩展类对象,基类,允许一切工作在 java。一切都是物体。

如果您尝试使用上面的类,您将看到您的 IDE 允许您使用诸如: equals(Object o)toString()等方法,但是您没有声明这些方法,它们来自基类 Object

你可以试试:

public class Abc extends String{


public void doSomething(){


}


}

这很好,因为您的类将不会隐式扩展 Object,而是将扩展 String,因为这是您说的。考虑以下更改:

public class Abc{


public void doSomething(){


}


@Override
public String toString(){
return "hello";
}


}

现在,如果调用 toString () ,您的类将始终返回“ hello”。

现在想象一下下面这个类:

public class Flyer{


public void makeFly(){


}


}


public class Bird extends Abc, Flyer{


public void doAnotherThing(){


}


}

同样,类 Flyer隐式扩展对象,它有方法 toString(),任何类都将有这个方法,因为他们都间接扩展 Object,所以,如果你从 Bird调用 toString(),哪个 toString() java 将不得不使用?从 Abc还是 Flyer?任何试图扩展两个或更多类的类都会发生这种情况,为了避免这种“方法冲突”,他们构建了 接口的想法,基本上你可以把它们想象成一个 不间接扩展 Object 的抽象类。因为它们是 toString()0,所以它们必须由一个类来实现,这是一个 toString()1(你不能单独实例化一个接口,它们必须由一个类来实现) ,所以一切都将继续很好地工作。

为了使类与接口不同,关键字 工具仅保留给接口。

你可以在同一个类中实现任何你喜欢的接口,因为它们在默认情况下不扩展任何东西(但是你可以创建一个扩展另一个接口的接口,但是同样,“父”接口不会扩展 Object) ,所以接口只是一个接口,它们不会受到“ 方法签名冲突方法签名冲突”的影响,如果它们这样做了,编译器会向你发出警告,你只需要改变方法签名来修复它(sign = method name + params + return type)。

public interface Flyer{


public void makeFly(); // <- method without implementation


}


public class Bird extends Abc implements Flyer{


public void doAnotherThing(){


}


@Override
public void makeFly(){ // <- implementation of Flyer interface


}


// Flyer does not have toString() method or any method from class Object,
// no method signature collision will happen here


}

您可以在有关 多重继承的 Oracle 文档页面中找到此查询的准确答案

  1. 状态多重继承: 从多个类继承字段的能力

    Java 编程语言不允许扩展多个类的一个原因是为了避免状态多重继承的问题,即从多个类继承字段的能力

    如果允许使用多重继承,并且通过实例化该类创建对象时,该对象将从该类的所有超类继承字段。这会引起两个问题。

    1. 如果来自不同超类的方法或构造函数实例化同一个字段会怎样?
    2. 哪个方法或构造函数优先?
  2. 实现多重继承: 从多个类继承方法定义的能力

    这种方法的问题: 名字自相矛盾ts 和 模棱两可。如果子类和超类包含相同的方法名(和签名) ,编译器无法确定调用哪个版本。

    但是 Java 支持这种类型的多重继承,自从 Java 8发布以来就引入了 默认方法。Java 编译器提供了一些规则来确定特定类使用的默认方法。

    有关解决钻石问题的详情,请参阅以下职位:

    Java8中抽象类和接口之间的区别是什么?

  3. 类型多重继承: 一个类实现多个接口的能力。

    由于 interface 不包含可变字段,因此您不必担心状态多重继承引起的问题。

Java 只通过接口支持多重继承。一个类可以实现任意数量的接口,但只能扩展一个类。

多重继承不被支持,因为它会导致致命的钻石问题。然而,这个问题是可以解决的,但它会导致复杂的系统,因此 Java 创始人放弃了这种多重继承。

1995年2月,詹姆斯•高斯林(James Gosling)发表了一篇名为《 Java: 概述》(Java: a Overview)的白皮书(连结-第2页) ,阐述了为什么 Java 不支持多重继承。

高斯林表示:

“ JAVA 省略了许多很少使用、理解不足、令人困惑的特性 在我们的经验中,C + + 带来的痛苦多于收益 主要由运算符重载组成(虽然 方法重载) ,多重继承和广泛的自动 胁迫”

Java 不支持多重继承、多路径和混合继承,原因如下: 问题。

多重继承场景: 我们来看一下 A 类,b 类,c 类,a 类有字母表() ,方法,b 类也有字母表() ,方法。现在 C 类扩展了 A,B,我们正在为子类创建对象,也就是 C 类,所以 C ob = new C () ; ,然后如果你想调用这些方法 ob.alphabet () ; ,哪个类方法采用?是 A 类方法还是 B 类方法?所以在 JVM 层次上出现了歧义问题。因此,Java 不支持多重继承。

多重继承

参考链接: < a href = “ https://plus.google.com/u/0/community/102217496457095083679”rel = “ nofollow noReferrer”> https://plus.google.com/u/0/communities/102217496457095083679

* 这是个简单的答案,因为我是 Java 初学者 *

考虑有三个类 XYZ

所以我们像 X extends Y, Z一样继承 YZ都有一个具有相同返回类型和参数的方法 alphabet()Y中的方法 alphabet()显示第一个字母表说,Z中的方法字母表对 显示最后的字母表说。 因此,当 X调用 alphabet()时,就会出现歧义。它说的是显示 第一还是 最后字母表? ? ? 所以 java 不支持多重继承。 在使用接口的情况下,将 YZ视为接口。因此,两者都将包含方法 alphabet()的声明,但不包含定义。它不会告诉是否显示第一个字母或最后一个字母或任何东西,只是会声明一个方法 alphabet()。因此,没有理由提出这种模糊性。我们可以在类 X中定义任何我们想要的方法。

所以一句话,在接口定义实现之后就完成了,所以没有混淆。

例如两个类 A,B 有相同的方法 m1()。

 class C extends A, B // for explaining purpose.

现在,类 C 将搜索 m1的定义。首先,它将在类中搜索,如果它没有找到,然后它将检查到父类。A 和 B 都有定义,所以这里出现了歧义,应该选择哪个定义。 所以 JAVA 不支持多重继承。

这个问题的答案在于 Java 编译器的内部工作(构造函数链接)。 如果我们看到 Java 编译器的内部工作:

public class Bank {
public void printBankBalance(){
System.out.println("10k");
}
}
class SBI extends Bank{
public void printBankBalance(){
System.out.println("20k");
}
}

在编译这个之后,看起来像:

public class Bank {
public Bank(){
super();
}
public void printBankBalance(){
System.out.println("10k");
}
}
class SBI extends Bank {
SBI(){
super();
}
public void printBankBalance(){
System.out.println("20k");
}
}

当我们扩展类并创建它的对象时,一个构造函数链将一直运行到 Object类。

以上代码可以正常运行。但是如果我们有另一个类名为 Car,它扩展了 Bank,还有一个 混血儿(多重继承)类名为 SBICar:

class Car extends Bank {
Car() {
super();
}
public void run(){
System.out.println("99Km/h");
}
}
class SBICar extends Bank, Car {
SBICar() {
super(); //NOTE: compile time ambiguity.
}
public void run() {
System.out.println("99Km/h");
}
public void printBankBalance(){
System.out.println("20k");
}
}

在这种情况下(SBICar)将无法创建构造函数链(编译时间模糊性)。

对于接口,这是允许的,因为我们不能创建它的对象。

关于 defaultstatic方法的新概念,请参考 界面默认

希望这能解决你的疑问。 谢谢。

Java 不支持多重继承,原因有二:

  1. 在 java 中,每个类都是 Object类的子类。当它从多个超类继承时,子类将模糊性转换为 获取 Object 类的属性。
  2. 在 java 中,每个类都有一个构造函数,如果我们显式地或根本不写它。第一个语句调用 super()来调用 如果类有多个超类,则 会搞混。

因此,当一个类从多个超类扩展时,我们会得到编译时错误。

以我们都知道的简单方式,我们可以继承(扩展)一个类,但我们可以实现如此多的接口。.这是因为在接口中,我们没有给出一个实现,只是说功能。假设 java 可以扩展如此多的类,并且这些类具有相同的方法。.在这一点上,如果我们尝试调用子类中的超类方法,那么应该运行什么方法呢?,编译器得到混淆 尝试多重扩展 但是在接口中那些方法没有主体,我们应该在子类中实现它们。 尝试使用多种工具 所以别担心。

这是一个保持低复杂性的决定。 使用混合继承,实现起来会更加复杂,而且不管怎样,通过多重继承可以实现的东西也可以通过其他方式实现。

用多重继承来解释问题的图像。 enter image description here 派生类的继承成员是什么? 它在派生类中仍然是私有的或公共可用的? 因为在 Java 中没有遇到这种类型的问题,他们删除了多重继承。这张图片是面向对象程序设计问题的一个简单例子。

多重继承由于含糊不清而不被类别所支持。 (这一点在上面的答案中用 super 关键字解释得很清楚)

接口方面,

  1. 在 Java7之前,接口不能定义方法的实现。因此,如果类从具有相同方法签名的多个接口实现,那么该方法的实现将由该类提供。

  2. 从 java 8开始,接口也可以有方法的实现。因此,如果类实现了两个或多个具有相同方法签名的接口,那么它也必须实现该类中的方法。

从 Java9开始,接口可以包含静态方法、私有方法、私有静态方法。

修改接口 的特性(超过 Java 版本7,8,9)