为什么 Java 或 C# 中不允许多重继承?
我知道Java和C#中不允许多重继承。 很多书只是说,不允许多重继承。 但可以通过接口来实现。 没有讨论为什么不允许这样做。 有人能准确地告诉我为什么不允许吗?
I know that multiple inheritance is not allowed in Java and C#. Many books just say, multiple inheritance is not allowed. But it can be implemented by using interfaces. Nothing is discussed about why it is not allowed. Can anybody tell me precisely why it is not allowed?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(17)
简短的答案是:因为语言设计者决定不这样做。
基本上,.NET 和 Java 设计者似乎都不允许多重继承,因为他们认为添加 MI 给语言增加了太多复杂性,而提供的好处太少。
为了获得更有趣和更深入的阅读,网上有一些文章对一些语言设计者进行了采访。 例如,对于 .NET,Chris Brumme(曾在 MS 从事 CLR 工作)解释了他们决定不这样做的原因:
您可以在此处阅读全文。
对于 Java,您可以阅读这篇文章:
The short answer is: because the language designers decided not to.
Basically, it seemed that both the .NET and Java designers did not allow multiple inheritance because they reasoned that adding MI added too much complexity to the languages while providing too little benefit.
For a more fun and in-depth read, there are some articles available on the web with interviews of some of the language designers. For example, for .NET, Chris Brumme (who worked at MS on the CLR) has explained the reasons why they decided not to:
You can read the full article here.
For Java, you can read this article:
实现的多重继承是不允许的。
问题是,如果您有一个 Cowboy 和一个 Artist 类(两者都具有 draw() 方法的实现),然后您尝试创建一个新的 CowboyArtist 类型,则编译器/运行时无法弄清楚该怎么做。 当你调用draw()方法时会发生什么? 有人死在街上,还是你有一幅可爱的水彩画?
我相信这被称为双钻石继承问题。
Multiple inheritance of implementation is what is not allowed.
The problem is that the compiler/runtime cannot figure out what to do if you have a Cowboy and an Artist class, both with implementations for the draw() method, and then you try to create a new CowboyArtist type. What happens when you call the draw() method? Is someone lying dead in the street, or do you have a lovely watercolor?
I believe it's called the double diamond inheritance problem.
原因:
Java 因其简单性而非常流行且易于编码。
因此,对于程序员来说,Java 开发人员感到难以理解和复杂的东西,他们会尽力避免。 其中一种属性是多重继承。
多重继承问题:钻石问题。
示例:
这就是钻石问题中存在的模糊性。
解决这个问题并非不可能,但它会给程序员在阅读时带来更多的混乱和复杂性。
它导致的问题比它试图解决的问题还要多。
注意:但是无论如何,您总是可以通过使用接口间接实现多重继承。
Reason:
Java is very popular and easy to code, because of its simplicity.
So what ever java developers feel difficult and complicated to understand for programmers, they tried to avoid it. One such kind of property is multiple inheritance.
Problem with multiple inheritance: Diamond problem.
Example:
This is the ambiguity existing in diamond problem.
It is not impossible to solve this problem, but it creates more confusion and complexities to the programmer while reading it.
It causes more problem than it tries to solve.
Note: But any way you can always implement multiple inheritance indirectly by using interfaces.
因为Java与C++的设计理念有很大不同。 (我不打算在这里讨论 C#。)
在设计 C++ 时,Stroustrup 希望包含有用的功能,无论它们如何被滥用。 多重继承、运算符重载、模板和各种其他功能可能会搞砸,但也有可能用它们做一些非常好的事情。
Java 的设计理念是强调语言构造的安全性。 结果是,有些事情做起来要困难得多,但您可以更加确信您正在查看的代码意味着您认为它的作用。
此外,Java 在很大程度上是对最著名的 OO 语言 C++ 和 Smalltalk 的反应。 还有许多其他 OO 语言(Common Lisp 实际上是第一个标准化的语言),它们具有可以更好地处理 MI 的不同 OO 系统。
更不用说完全可以在 Java 中使用接口、组合和委托来进行 MI。 它比 C++ 更明确,因此使用起来更笨拙,但会给你带来乍一看更容易理解的东西。
这里没有正确的答案。 有不同的答案,对于特定情况,哪一个更好取决于应用和个人偏好。
Because Java has a greatly different design philosophy from C++. (I'm not going to discuss C# here.)
In designing C++, Stroustrup wanted to include useful features, regardless of how they could be misused. It's possible to screw up big-time with multiple inheritance, operator overloading, templates, and various other features, but it's also possible to do some very good things with them.
The Java design philosophy is to emphasize safety in language constructs. The result is that there are things that are a lot more awkward to do, but you can be a lot more confident that the code you're looking at means what you think it does.
Further, Java was to a large extent a reaction from C++ and Smalltalk, the best known OO languages. There are plenty of other OO languages (Common Lisp was actually the first one to be standardized), with different OO systems that handle MI better.
Not to mention that it's entirely possible to do MI in Java, using interfaces, composition, and delegation. It's more explicit than in C++, and therefore is clumsier to use but will get you something you're more likely to understand at first glance.
There is no right answer here. There are different answers, and which one is better for a given situation depends on applications and individual preference.
人们远离 MI 的主要原因(尽管绝不是唯一)是所谓的“钻石问题”,导致实施中的模糊性。 这篇维基百科文章讨论并解释得比我更好。 MI 还可能导致更复杂的代码,许多 OO 设计者声称您不需要 MI,如果您确实使用它,您的模型可能是错误的。 我不确定我是否同意最后一点,但保持简单总是一个好的计划。
The main (although by no means the only) reason people steer away from MI is the so called "diamond problem" leading to ambiguity in your implementation. This wikipedia article discusses it and explains better than I could. MI can also lead to more complex code, and a lot of OO designers claim that you do't need MI, and if you do use it your model is probably wrong. I'm not sure I agree with this last point, but keeping things simple is always a good plan.
在 C++ 中,如果使用不当,多重继承会是一个令人头疼的问题。 为了避免这些流行的设计问题,在现代语言(java、C#)中强制使用多个接口“继承”。
In C++ multiple inheritance was a major headache when used improperly. To avoid those popular design issues multiple interfaces "inheritance" was forced instead in modern languages (java, C#).
多重继承很难
因此,不将多重继承包含到 Java 语言中可以被认为是明智的选择。
Multiple Inheritance is
Therefore, it can be considered a wise choice to not include Multiple Inheritance into the Java language.
另一个原因是单继承使得转换变得微不足道,不发出汇编程序指令(除了在需要时检查类型的兼容性之外)。 如果您有多重继承,您需要弄清楚某个父类在子类中的哪个位置开始。 因此,性能当然是一项福利(尽管不是唯一的)。
Another reason is that single-inheritance makes casting trivial, emitting no assembler instructions (other than checking for the compatibility of the types where required). If you had multiple-inheritance, you'd need to figure out where in the child class a certain parent starts. So performance is certainly a perk (although not the only one).
回到过去(70 年代),当时计算机科学更加科学,大规模生产较少,程序员有时间思考良好的设计和良好的实现,因此产品(程序)具有高质量(例如 TCP/IP 设计)和实施)。
如今,当每个人都在编程,并且经理们在截止日期之前更改规范时,像 Steve Haigh 帖子中的维基百科链接中描述的那样的微妙问题很难跟踪; 因此,“多重继承”受到编译器设计的限制。 如果您喜欢,您仍然可以使用 C++ .... 并拥有您想要的所有自由:)
Back in the old days ('70s) when Computer Science was more Science and less mass production the programmers had time to think about good design and good implementation and as a result the products (programms) had high quality ( eg. TCP/IP design and implementation ).
Nowadays, when everybody is programming, and the managers are changing the specs before deadlines, subtle issues like the one descriped in the wikipedia link from Steve Haigh post are difficult to track; therefore, the "multiple inheritance" is limited by compiler design. If you like it, you can still use C++ .... and have all the freedom you want :)
我对“Java 中不允许多重继承”的说法持保留态度。
当一个“类型”继承多个“类型”时,就定义了多重继承。 接口也被归类为类型,因为它们具有行为。 所以Java确实有多重继承。 只是这样更安全。
I take the statement that "Multiple inheritance is not allowed in Java" with a pinch of salt.
Multiple Inheritance is defined when a "Type" inherits from more than one "Types". And interfaces are also classified as types as they have behavior. So Java does have multiple inheritance. Just that it is safer.
类的动态加载使得多重继承的实现变得困难。
在java中,实际上他们通过使用单继承和接口来避免多重继承的复杂性。
在如下情况下,多重继承的复杂性非常高
多重继承的钻石问题。
我们有两个类 B 和 C 继承自 A。假设 B 和 C 重写继承的方法并且它们提供自己的实现。 现在 D 从 B 和 C 继承,进行多重继承。 D应该继承那个重写的方法,jvm无法决定使用哪个重写的方法?
在c++中,虚函数是用来处理的,我们必须显式地做。
这可以通过使用接口来避免,没有方法体。 接口无法实例化,只能由类实现或由其他接口扩展。
Dynamic loading of classes makes the implementation of multiple inheritance difficult.
In java actually they avoided the complexity of multiple inheritance instead by using single inheritance and interface.
Complexity of multiple inheritance is very high in a situation like below explained
diamond problem of multiple inheritance.
We have two classes B and C inheriting from A. Assume that B and C are overriding an inherited method and they provide their own implementation. Now D inherits from both B and C doing multiple inheritance. D should inherit that overridden method, jvm can't able to decide which overridden method will be used?
In c++ virtual functions are used to handle and we have to do explicitly.
This can be avoided by using interfaces, there are no method bodies. Interfaces cannot be instantiated—they can only be implemented by classes or extended by other interfaces.
实际上,如果继承的类具有相同的功能,多重继承就会产生复杂性。 即编译器会感到困惑,必须选择哪一个(钻石问题)。 因此,在 Java 中,复杂性被消除,并提供了接口来获得像多重继承一样的功能。 我们可以使用接口
Actually multiple inheritance will arise a the complexity if the inherited classes have same function. ie the compiler will have a confusion which one has to chose (diamond problem). So in Java that complexity removed and gave interface to get the functionality like multiple inheritance gave. We can use interface
Java有一个概念,即多态性。 java中有两种类型的多态性。 有方法重载和方法重写。 其中,方法重写发生在超类和子类关系中。 如果我们创建一个子类的对象并调用超类的方法,并且如果子类扩展了多个类,那么应该调用哪个超类方法?
或者,当通过
super()
调用超类构造函数时,将调用哪个超类构造函数?对于当前的 java API 功能来说,这个决定是不可能的。 所以java中不允许多重继承。
Java has concept, i.e. polymorphism. There are 2 types of polymorphism in java. There are method overloading and method overriding. Among them, method overriding happens with super- and subclass relationship. If we are creating an object of a subclass and invoking the method of superclass, and if subclass extends more than one class, which super class method should be called?
Or , while calling superclass constructor by
super()
, which super class constructor will get called?This decisions are impossible by current java API features. so multiple inheritance is not allowed in java.
Java中直接不允许多重继承,但通过接口允许多重继承。
原因:
多重继承:引入更多复杂性和歧义。
接口:接口是 Java 中完全抽象的类,它为您提供了一种统一的方法,可以根据其公开可用的接口正确描述程序的结构或内部工作方式,从而获得更大的灵活性和灵活性。可重用的代码以及对如何创建其他类以及如何与其他类交互的更多控制。
更准确地说,它们是 Java 中的一种特殊构造,具有允许您执行一种多重继承的附加特性,即可以向上转换为多个类的类。
让我们举个简单的例子。
假设有两个超类 A 和 B,它们的方法名称相同,但功能不同。 通过以下带有 (extends) 关键字的代码,多重继承是不可能的。
但是通过接口,使用(implements)关键字多重继承是可能的。
Multiple Inheritance is not allowed in Java directly , but through interfaces it is allowed.
Reason :
Multiple Inheritance : Introduces more complexity and ambiguity.
Interfaces : Interfaces are completely abstract classes in Java that provide you with a uniform way to properly delineate the structure or inner workings of your program from its publicly available interface, with the consequence being a greater amount of flexibility and reusable code as well as more control over how you create and interact with other classes.
More precisely, they are a special construct in Java with the additional characteristic that allow you to perform a kind of multiple inheritance i.e. classes that can be upcast to more than one class.
Lets take simple example.
Suppose there are 2 superclasses classes A and B with same method names but different functionalities. Through following code with (extends) keyword multiple inheritance is not possible.
But through interfaces, with (implements) keyword multiple inheritance is possible.
在 C++ 中,一个类可以(直接或间接)继承多个类,这称为
多重继承。
然而,C# 和 Java 将类限制为每个类继承的单一继承
来自单亲班级。
多重继承是创建结合两个不同类的各个方面的类的有用方法
层次结构,在单个类中使用不同的类框架时经常发生的情况
应用。
例如,如果两个框架定义了自己的异常基类,您可以
使用多重继承来创建可与任一框架一起使用的异常类。
多重继承的问题是它可能导致歧义。 经典的例子是当
一个类继承自另外两个类,每个类都继承自同一个类:
在此示例中,
flag
数据成员由class A
定义。 但是D类
是B类
的后代和
class C
,它们都派生自A
,因此本质上flag
的两个副本可用,因为两个A
的实例位于D
的类层次结构中。 您想设置哪一项? 编译器会抱怨D
中对flag
的引用不明确。 一种修复方法是显式消除引用的歧义:另一种修复方法是将 B 和 C 声明为虚拟基类,这意味着只有 A 的一个副本可以
存在于层次结构中,消除了任何歧义。
多重继承还存在其他复杂性,例如基类的顺序
在构造派生对象时初始化,或者成员可能被无意隐藏的方式
来自派生类。 为了避免这些复杂性,某些语言将自己限制为更简单的单继承模型。
虽然这确实大大简化了继承,但也限制了它的用处
因为只有具有共同祖先的类才能共享行为。 接口可以缓解这种情况
通过允许不同层次结构中的类公开公共接口来稍微限制
如果它们不是通过共享代码实现的。
In C++ a class can inherit (directly or indirectly) from more than one class, which is referred to as
multiple inheritance.
C# and Java, however, limit classes to single inheritance each class inherits
from a single parent class.
Multiple inheritance is a useful way to create classes that combine aspects of two disparate class
hierarchies, something that often happens when using different class frameworks within a single
application.
If two frameworks define their own base classes for exceptions, for example, you can
use multiple inheritance to create exception classes that can be used with either framework.
The problem with multiple inheritance is that it can lead to ambiguity. The classic example is when
a class inherits from two other classes, each of which inherits from the same class:
In this example, the
flag
data member is defined byclass A
. Butclass D
descends fromclass B
and
class C
, which both derive fromA
, so in essence two copies offlag
are available because twoinstances of
A
are inD
’s class hierarchy. Which one do you want to set? The compiler will complainthat the reference to
flag
inD
is ambiguous. One fix is to explicitly disambiguate the reference:Another fix is to declare B and C as
virtual base classes
, which means that only one copy of A canexist in the hierarchy, eliminating any ambiguity.
Other complexities exist with multiple inheritance, such as the order in which the base classes are
initialized when a derived object is constructed, or the way members can be inadvertently hidden
from derived classes. To avoid these complexities, some languages restrict themselves to the simpler single inheritance model.
Although this does simplify inheritance considerably, it also limits its usefulness
because only classes with a common ancestor can share behaviors. Interfaces mitigate this
restriction somewhat by allowing classes in different hierarchies to expose common interfaces even
if they’re not implemented by sharing code.
您可以从此文档链接找到答案
如果允许多重继承并且当您通过以下方式创建对象时实例化该类时,该对象将从该类的所有超类继承字段。 这会导致两个问题。
如果来自不同超类的方法或构造函数实例化同一个字段怎么办?
哪个方法或构造函数将优先?
即使现在允许状态的多重继承,您仍然可以实现
类型的多重继承:一个类实现多个接口的能力。
实现的多重继承(通过接口中的默认方法):能够从多个类继承方法定义,
请参阅此相关的 SE 问题以获取更多信息:
接口的多重继承歧义
You can find answer from this documentation link
If multiple inheritance is allowed and when you create an object by instantiating that class, that object will inherit fields from all of the class's super classes. It will cause two issues.
What if methods or constructors from different super classes instantiate the same field?
Which method or constructor will take precedence?
Even though multiple inheritance of state is now allowed, still you can implement
Multiple inheritance of type: Ability of a class to implement more than one interface.
Multiple inheritance of implementation (through default methods in interfaces) : Ability to inherit method definitions from multiple classes
Refer to this related SE question for additional info:
Multiple Inheritance Ambiguity with Interface
想象一下这个例子:
我有一个类
Shape1
它有
CalcualteArea
方法:还有另一个类
Shape2
也有相同的方法现在我有一个子类 Circle,它源自 Shape1 和 Shape2;
现在,当我为 Circle 创建对象并调用该方法时,系统不知道要调用哪个计算面积方法。 两者都有相同的签名。 所以编译器会感到困惑。 这就是不允许多重继承的原因。
但可以有多个接口,因为接口没有方法定义。 即使两个接口都有相同的方法,它们都没有任何实现,并且总是会执行子类中的方法。
Imagine this Example:
I have a class
Shape1
It has
CalcualteArea
method:There is another class
Shape2
that one also has same methodNow I have a child class Circle, it derives from both Shape1 and Shape2;
Now when I create object for Circle, and call the method, system does not know which calculate area method to be called. Both has same signatures. So compiler will get confuse. That's why multiple inheritances are not allowed.
But there can be multiple interfaces because interfaces do not have method definition. Even both the interfaces have same method, both of them do not have any implementation and always method in the child class will be executed.