为什么使用带有共同祖先的菱形案例来解释Java多重继承问题,而不是两个不相关的父类?
这个问题对Java人来说可能听起来很奇怪,但如果你能解释一下,那就太好了 在这些日子里,我正在澄清Java的一些非常基本的概念。 所以我来谈谈Java的继承和接口主题 在阅读本文时,我发现Java不支持多重继承,也理解了这一点,我无法理解的是,为什么要讨论everywhere菱形图形问题(至少有4个类来创建菱形)来解释这种行为,我们不能仅使用3个类来理解这个问题吗 比如说,我有A类和B类,这两个类不同(它们不是普通类的子类),但它们有一个通用方法,它们看起来像:-为什么使用带有共同祖先的菱形案例来解释Java多重继承问题,而不是两个不相关的父类?,java,multiple-inheritance,diamond-problem,Java,Multiple Inheritance,Diamond Problem,这个问题对Java人来说可能听起来很奇怪,但如果你能解释一下,那就太好了 在这些日子里,我正在澄清Java的一些非常基本的概念。 所以我来谈谈Java的继承和接口主题 在阅读本文时,我发现Java不支持多重继承,也理解了这一点,我无法理解的是,为什么要讨论everywhere菱形图形问题(至少有4个类来创建菱形)来解释这种行为,我们不能仅使用3个类来理解这个问题吗 比如说,我有A类和B类,这两个类不同(它们不是普通类的子类),但它们有一个通用方法,它们看起来像:- class A { v
class A {
void add(int a, int b) {
}
}
class B {
void add(int a, int b) {
}
}
好,现在假设Java是否支持多重继承,是否有一个类是A和B的子类,如下所示:-
class C extends A,B{ //If this was possible
@Override
void add(int a, int b) {
// TODO Auto-generated method stub
super.add(a, b); //Which version of this, from A or B ?
}
}
然后编译器将无法找到从A或B调用哪个方法,这就是Java不支持多重继承的原因。那么这个概念有什么问题吗
当我读到这个话题时,我能够理解钻石问题,但我无法理解为什么人们不举三个类的例子(如果这是一个有效的例子,因为我们只使用了三个类来演示这个问题,所以将它与钻石问题进行比较很容易理解。)
让我知道这个例子是否不适合解释这个问题,或者这个例子也可以用来理解这个问题
编辑:
我在这里投了一票,表明这个问题不清楚。
主要问题是:-
我可以理解为什么“Java不支持多重继承”只有3个类,如上所述,或者我必须有4个类(菱形结构)才能理解这个问题。您提到的菱形问题是不支持多重继承的一个原因(也是一个很好的原因)。还有其他原因,你可以
许多原因归结为复杂性(正确操作相当复杂)、使用它的合法需求相对较少,以及它所造成的调度方面的各种其他问题(除了菱形问题)。菱形继承的问题并不多。如您所见,Java实际上一直支持多重继承,但只支持类型为的多重继承 只有三个类,通过引入像
super.a
或super.B
这样的简单构造,问题相对容易解决。虽然您只关注被重写的方法,但实际上,您是否有一个共同的祖先或仅仅是基本的三个类并不重要
然而,如果A
和B
有一个共同的祖先,即他们都继承的状态,那么你就有严重的麻烦了。您是否存储此共同祖先状态的两个独立副本?这更像是组合而不是继承。或者您是否只存储一个由A
和B
共享的状态,从而在它们操作继承的共享状态时导致奇怪的交互
class A {
protected int foo;
}
class B extends A {
public B() {
this.foo = 42;
}
}
class C extends A {
public C() {
this.foo = 0xf00;
}
}
class D extends B,C {
public D() {
System.out.println( "Foo is: "+foo ); //Now what?
}
}
请注意,如果类a
不存在,并且B
和C
都声明了自己的foo
字段,那么上面的问题就不会那么大了。仍然会有名称冲突的问题,但这可以通过一些名称空间构造来解决(B.this.foo
和C.this.foo
可能,就像我们处理内部类一样?)。另一方面,真正的菱形问题不仅仅是命名冲突,而是当D
(B
和C
)的两个不相关的超类共享从a
继承的相同状态时,如何维护类不变量的问题。这就是为什么需要所有四个类来演示问题的全部程度
多重继承中的共享行为不会表现出同样的问题。如此之多以至于最近引入的新技术正是这样做的。这意味着现在也允许实现的多重继承。关于调用哪个实现的解析仍然存在一些复杂问题,但由于接口是无状态的,因此避免了最大的错误。Java不支持多重继承,因为该语言的设计者以这种方式设计Java。像C++这样的其他语言支持多继承,这不是一个技术问题,而只是一个设计标准。 多重继承的问题是,并不总是清楚调用哪个类的哪个方法,以及访问哪个实例变量。不同的人对此有不同的解释,Java设计师当时认为最好完全跳过多重继承 C++通过以下方式解决菱形类问题: 虚拟继承是一种用于面向对象的技术 编程,其中继承层次结构中的特定基类 声明与任何其他成员共享其成员数据实例 在进一步的派生类中包含相同的基。例如 如果类别A通常(非虚拟)源自类别X(假设 以包含数据成员),类B也是如此,类C继承 从A类和B类中,它将包含两组数据 与类X关联的成员(可独立访问,通常使用 合适的消歧限定符)。但如果A级实际上是 而不是从类X派生,那么类C的对象将包含 只有一组来自类X的数据成员。这是最著名的语言 实现这个特性的是C++。
与java相反,C++中,可以通过用类名称预先调用调用来消除哪个实例方法调用:
class X {
public: virtual void f() {
}
};
class Y : public X {
public: virtual void f() {
}
};
class Z : public Y {
public: virtual void f() {
X::f();
}
};
这只是语言中多重继承必须解决的一个困难。既然有郎
+-----+
| A |
|=====|
|foo()|
+-----+
^
|
+---+---+
| |
+-----+ +-----+
| B | | C |
|=====| |=====|
|foo()| |foo()|
+-----+ +-----+
^ ^
| |
+---+---+
|
+-----+
| D |
|=====|
+-----+