为什么使用带有共同祖先的菱形案例来解释Java多重继承问题,而不是两个不相关的父类?

为什么使用带有共同祖先的菱形案例来解释Java多重继承问题,而不是两个不相关的父类?,java,multiple-inheritance,diamond-problem,Java,Multiple Inheritance,Diamond Problem,这个问题对Java人来说可能听起来很奇怪,但如果你能解释一下,那就太好了 在这些日子里,我正在澄清Java的一些非常基本的概念。 所以我来谈谈Java的继承和接口主题 在阅读本文时,我发现Java不支持多重继承,也理解了这一点,我无法理解的是,为什么要讨论everywhere菱形图形问题(至少有4个类来创建菱形)来解释这种行为,我们不能仅使用3个类来理解这个问题吗 比如说,我有A类和B类,这两个类不同(它们不是普通类的子类),但它们有一个通用方法,它们看起来像:- class A { v

这个问题对Java人来说可能听起来很奇怪,但如果你能解释一下,那就太好了

在这些日子里,我正在澄清Java的一些非常基本的概念。 所以我来谈谈Java的继承和接口主题

在阅读本文时,我发现Java不支持多重继承,也理解了这一点,我无法理解的是,为什么要讨论everywhere菱形图形问题(至少有4个类来创建菱形)来解释这种行为,我们不能仅使用3个类来理解这个问题吗

比如说,我有A类和B类,这两个类不同(它们不是普通类的子类),但它们有一个通用方法,它们看起来像:-

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  |
    |=====|
    +-----+