【问题标题】:How do I implement multiple inheritence in Java如何在 Java 中实现多重继承
【发布时间】:2010-10-12 17:04:58
【问题描述】:

我正在使用 Java 中的某个 API 库。它有一个基类 A,以及扩展 A 的 B 和 C。B 和 C 提供相似但不同的功能,所有三个类都在库中。

public abstract class A
{
    virtual foo();
}

public class B extends A {}
public class C extends A {}

如何在我的班级中获取ABC 的元素?如果我使用接口来实现类,会有很多重复的代码,并且内部类不允许我覆盖现有的方法,从而保留ABC的调用接口。

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

编辑: 感谢乔治的编辑,现在更清楚了,忘了提到一个关键要求:我的类必须有 A 作为基础,以便它们可以由平台 API 管理。

【问题讨论】:

  • 那么问题是什么?
  • @Hemang,查看这个问题的原始未编辑版本。
  • 既然你已经google了,你可能知道java等很多语言都去掉了多重继承。如果您可以更具体,为什么在您的情况下必须拥有它,可以提出更好的替代方案
  • Groovy,虽然在技术上是另一种语言,但可以用作 Java 的扩展,因为大多数 Java 代码也可以在 Groovy 中使用。 Groovy 能够让您在现有 Java 类中注入/拦截方法。只是想我会把它扔出去,以防你没想到。

标签: java multiple-inheritance


【解决方案1】:

回顾一下,你有:

class A
{
    public void foo() {}
}

class B extends A
{
    public specificAMethod() {}
}

class C extends A
{
    public specificCMethod() {}
}

上述类位于您无法访问或修改的库中。 您想在第三类 D 中获得 B 和 C 的行为,好像可以这样写:

class D extends B, C
{
}

对吗?

使用 B 和 C 而不是继承呢?你真的需要继承吗?你想调用私有 B 和 C 方法吗?

class D
{

private B b;
private C c;
}

【讨论】:

  • 更喜欢组合而不是继承!
  • 我同意你的观点——投票给你@vulkanio——因为这就是你所说的(我只是总结了)。希望它没有告诉你你做错了什么。
  • 这又是委托。我希望我的类最终以 A 为基础的原因是我可以将它传递给平台 API,因为这些都是平台管理的对象。
  • @Saideira 通常你必须传递给 API 的东西被指定为接口,如果不是有人真的不明白如何编写 API,但如果你不能使用接口,那么扩展您需要使用的类并将第二个类组合到您的对象中。
  • @Bill 我只是在问,因为在那本书中那句话一遍又一遍地重复,我不是在抱怨你的评论,我对此表示赞同 :)
【解决方案2】:

如果您采用“优先组合优于继承”的一般方法,您可能会发现其中一个或两个类实际上不应该是“继承”的。在这两种情况下,类是否具有严格的“is-a”关系?如果您可以大声说“有”并且听起来并不愚蠢,那么您可能需要作曲。

例如,如果您正在实施一副纸牌,黑桃 3 是 -a 3 并且它是 -a 黑桃,但您也可以将其视为它有 -a 3 并且它有 -a 花色(铲)。既然您可以这样想,您可能应该更喜欢 has-a 解释和使用组合。

尽量远离继承树的深度超过几个对象——如果您曾经想要使用多重继承,请尝试解决它。这是 Java 迫使您通过不提供功能来设计代码更具可读性的情况之一(但诚然,当您真正想要它时,它不存在并且可能会受到伤害!某种程度的 mixin 将是不错)。

【讨论】:

    【解决方案3】:

    听起来您想扩展 A - 将其称为 D - 覆盖其 foo(),然后拥有扩展 D 并添加自己的功能的新子类 E 和 F。

    您可能会考虑提取通用接口并重用它们。具有重构功能的良好 IDE 将使其变得容易。

    【讨论】:

      【解决方案4】:

      在 Java 中不能进行多类继承,但是您可以对接口使用多继承。使用Delegation pattern,您可以将其他几个类的行为合二为一。

      【讨论】:

      • 是的,我可以使用委托,但必须编写很多胶水代码,因为类有很多方法
      • 大多数情况下 IDE 可以为您生成它,或者您可以使用动态代理。参见,例如java.sys-con.com/node/37748
      • @Saideria 你的课程太大了吗?如果您的界面转发了那么多东西,我想知道您是否做错了什么。例如,您可能有 setter 和 getter——通常尝试消除它们并将调用它们的代码放入您的类中。你的班级可以做不止一件简单的事情吗?也许它应该被分解成多个类......这是没有正确答案的东西,但是每次你看任何代码时都试着重复做这种事情。从长远来看,这是完全值得的。
      【解决方案5】:

      在 COM 中应用了完全不同的方法:所有对象都继承自 IUnknown,它有一个方法可以翻译成 Java:

      Object queryInterface(Class<?> clazz)
      

      这个方法最简单的实现可以是:

      if(clazz.isAssignableFrom(this.getClass()))
          return this;
      else
          return null;
      

      单继承行不通的地方,添加就够了:

      else if(class == SomeClass.class) {
          return something;
      } else ...
      

      这样,即使是最复杂的多重继承情况也可以得到解决,并且您可以完全控制返回的内容和时间,因此您可以避免来自 C++ 等语言的“经典”多重继承的许多问题,例如 fork-join 问题。

      【讨论】:

        【解决方案6】:

        从 Java 1.8 开始,您可以使用带有默认方法的接口。它非常方便,我经常使用它。 Covariant return types 也受支持。有一些限制(见下文),但您不必自己实现继承并让编译器为您工作。

        public interface A {
            default A foo() {
                return this;
            }
        }
        
        public interface B extends A {
            @Override
            default B foo() {
                return this;
            }
        }
        
        public interface C extends A {
            @Override
            default C foo() {
                return this;
            }
        }
        
        public interface D extends B, C {
            @Override
            // if the return type does not implement B and C
            // the comiler will throw an error here
            default D foo() { 
                return this;
            }
        }
        

        请注意这一点,但请注意您不能调用 super.foo 或定义字段或私有成员(直到 Java 9),因为它仍然是接口。如果你能接受这些限制,这将为你开启一个新的面向对象编程水平。

        【讨论】:

          猜你喜欢
          • 2017-06-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-03-06
          • 2011-11-21
          • 2015-02-12
          • 2020-08-09
          相关资源
          最近更新 更多