Java接口如何模拟多重继承?

时间:2010-08-24 13:01:41

标签: java interface multiple-inheritance

我正在阅读“The Java Tutorial”(第二次)。我刚刚完成了关于接口的部分(再次),但仍然不了解Java接口如何模拟多重继承。是否有比书中更清楚的解释?

22 个答案:

答案 0 :(得分:149)

假设您的域中有两种东西:卡车和厨房

Trucks有一个driveTo()方法,Kitchens有一个cook()方法。

现在假设保利决定从送货卡车后面出售比萨饼。他想要一个他可以驾驶To()和烹饪()的东西。

在C ++中,他会使用多重继承来执行此操作。

在被认为过于危险的Java中,您可以继承主类,但是您可以从接口“继承”行为,这些行为适用于所有意图和目的,抽象类没有字段或方法实现。

因此在Java中,我们倾向于使用委托来实现多重继承:

Pauli将一辆卡车子类化,并在一个名为kitchen的成员变量中为卡车添加了一个厨房。他通过调用kitchen.cook()来实现Kitchen接口。

class PizzaTruck extends Truck implements Kitchen {
   Kitchen kitchen;

   public void cook(Food foodItem) {
      kitchen.cook(foodItem);
   }
}

他是一个快乐的人,因为他现在可以做一些事情;

pizzaTruck.driveTo(beach);
pizzaTruck.cook(pizzaWithExtraAnchovies);

好吧,这个愚蠢的故事是为了表明它不是多重继承的模拟,它是真正的多重继承,条件是你只能继承契约,只能从称为接口的空抽象基类继承。

(更新:随着default methods interfaces的到来,现在还可以提供一些可以继承的行为)

答案 1 :(得分:18)

您可能会感到困惑,因为您在本地查看多个继承,就一个类继承多个父项的实现详细信息而言。这在Java中是不可能的(并且经常导致在可能的语言中滥用)。

接口允许类型的多重继承,例如其他类可以使用class Waterfowl extends Bird implements Swimmer,就好像它是Bird 一样,就好像它是Swimmer一样。这是多重继承的深层含义:允许一个对象同时表现为属于几个不相关的不同类。

答案 2 :(得分:16)

这是一种通过java中的接口实现多重继承的方法。

取得什么成果?
A类扩展B,C //这在java中是不可能的,但可以间接实现。

class B{
   public void getValueB(){}
}

class C{
   public void getValueC(){}
}


interface cInterface{
   public getValueC();
}

class cChild extends C implemets cInterface{
    public getValueC(){

      // implementation goes here, call the super class's getValueC();

    }
}


// Below code is **like** class A extends B, C 
class A extends B implements cInterface{
   cInterface child =  new cChild();
   child.getValueC();
}

答案 3 :(得分:10)

给出以下两个接口......

interface I1 {
  abstract void test(int i);
}
interface I2 {
  abstract void test(String s);
}

我们可以使用下面的代码实现这两个......

public class MultInterfaces implements I1, I2 {
  public void test(int i) {
    System.out.println("In MultInterfaces.I1.test");
  }
  public void test(String s) {
    System.out.println("In MultInterfaces.I2.test");
  }
  public static void main(String[] a) {
    MultInterfaces t = new MultInterfaces();
    t.test(42);
    t.test("Hello");
  }
}

我们不能扩展两个对象,但我们可以实现两个接口。

答案 4 :(得分:10)

接口不模拟多重继承。 Java创建者认为多重继承是错误的,因此在Java中没有这样的东西。

如果要将两个类的功能合并为一个 - 使用对象组合。即。

public class Main {
    private Component1 component1 = new Component1();    
    private Component2 component2 = new Component2();
}

如果您想公开某些方法,请定义它们并让它们将调用委托给相应的控制器。

这里的接口可能很方便 - 如果Component1实现接口Interface1Component2实现Interface2,则可以定义

class Main implements Interface1, Interface2

这样你就可以在上下文允许的情况下交替使用对象。

答案 5 :(得分:6)

你知道吗,从JavaScript开发人员的角度来看,试图了解这些东西到底发生了什么,我想指出一些事情,有人请告诉我,我在这里缺少的是我离开了标记。

接口非常简单。愚蠢,非常简单。他们像人们最初想的那样愚蠢,非常简单,这就是为什么关于这个确切的主题存在如此多的重复问题,因为使用它们的一个原因已经被人们试图制造出比他们更多的人所不清楚了在我曾经接触过的每个Java服务器端代码库中都被广泛滥用。

那么,你为什么要使用它们呢?大多数时候你不会。你肯定不会像许多人想的那样一直使用它们。但在我到达之前,让我们谈谈他们不是什么。

接口不是:

  • 以任何方式解决Java缺乏的任何类型的继承机制。它们与继承无关,它们从未做过,也绝不模拟任何类似继承的东西。
  • 必然可以帮助你写下你写的东西,就像它帮助其他人写一些你想要与你的东西接口的东西一样。

他们真的很简单,你认为他们乍看之下。人们总是愚蠢地滥用,所以很难理解这一点。这只是验证/测试。一旦你写了一些符合接口的东西并且有效,删除那些“实现”代码就不会破坏任何东西。

但是如果你正确使用接口,你就不想删除它,因为在那里有它可以为下一个开发人员提供一个工具来为另一组数据库或Web服务编写一个访问层,他们希望你的其余数据库应用程序继续使用,因为他们知道他们的类将失败,直到他们获得100%完整的预期接口到位。所有接口都是验证您的类,并确定您实际上已实现了您承诺的接口。没什么。

它们也是便携式的。通过公开您的接口定义,您可以为想要使用未暴露代码的人提供一组符合的方法,以便他们的对象能够正确使用它。他们不必实现接口。他们可以把它们放在一张记事本纸上并仔细检查。但是通过界面,您可以获得更多保证,除非有相应版本的接口,否则不会尝试工作。

那么,任何界面都不可能被多次实现?完全没用。多重继承?停止伸手去抓那条彩虹。 Java首先避免使用它们,并且无论如何,合成/聚合对象在很多方面都更加灵活。这并不是说接口无法帮助您以多重继承允许的方式进行建模,但它实际上不是以任何形式或形式继承的,并且不应该被视为这样。它只是保证你的代码在你实现了你建立的所有方法之后才能工作。

答案 6 :(得分:5)

这很简单。您可以在一个类型中实现多个接口。例如,您可以拥有List的实现,它也是Deque的实例(而Java确实...... LinkedList)。

您无法从多个父级继承实现(即扩展多个类)。 声明(方法签名)没问题。

答案 7 :(得分:3)

这不是多重继承的模拟。在java中,你不能从两个类继承,但是如果你实现了两个接口“看起来你是从两个不同的类继承的”,因为你可以将你的类用作你的两个接口中的任何一个。

例如

interface MyFirstInteface{
    void method1();
}
interface MySecondInteface{
    void method2();
}
class MyClass implements MyFirstInteface, MySecondInteface{
    public void method1(){
        //Method 1
    }
    public void method2(){
        //Method 2
    }

    public static void main(String... args){
        MyFirstInterface mfi = new MyClass();
        MySecondInterface msi = new MyClass();
    }
}

这可以工作,你可以使用mfi和msi,它看起来像是一个多继承,但它不是因为你没有继承任何东西,你只需要重写接口提供的公共方法。

答案 8 :(得分:3)

你需要准确:

Java允许多重继承接口,但只实现单一继承。

你在Java中做了多个接口继承,如下所示:

public interface Foo
{
    String getX(); 
}

public interface Bar
{
    String getY();
}

public class MultipleInterfaces implements Foo, Bar
{
    private Foo foo;
    private Bar bar;

    public MultipleInterfaces(Foo foo, Bar bar)
    {
        this.foo = foo;
        this.bar = bar;
    }

    public String getX() { return this.foo.getX(); }
    public String getY() { return this.bar.getY(); }
}

答案 9 :(得分:3)

顺便说一下,Java没有实现完全多重继承的原因是因为它会产生歧义。假设你可以说“A extends B,C”,然后B和C都有一个函数“void f(int)”。 A继承了哪个实现?使用Java的方法,您可以实现任意数量的接口,但接口只声明签名。因此,如果两个接口包含具有相同签名的函数,那么您的类必须实现具有该签名的函数。如果你继承的接口具有不同签名的函数,那么这些函数彼此无关,所以不存在冲突问题。

我不是说这是唯一的方法。 C ++通过建立实现获胜的优先级规则来实现真正的多重继承。但Java的作者决定消除歧义。无论是因为哲学上认为这是为了更清洁的代码,还是因为他们不想做所有额外的工作,我不知道。

答案 10 :(得分:2)

他们没有。

我认为混淆来自于人们相信实现接口构成某种形式的继承。它没有;实施可以简单地为空白,行为不会强迫行为或通过任何合同保证。一个典型的例子是Clonable接口,虽然暗示了很多很棒的功能,但它定义的很少,基本上没用,而且有潜在的危险。

通过实现接口继承了什么? Bubkes!所以在我看来,停止在同一个句子中使用单词interface和inheritance。正如Michael Borgwardt所说,界面不是定义,而是一个方面。

答案 11 :(得分:2)

我想指出一些让我陷入困境的东西,来自C ++,你可以很容易地继承许多实现。

有一个"宽"使用多种方法的界面意味着您必须在具体的类中实现许多方法,并且您无法在各个实现中轻松共享这些方法。

例如:

interface Herbivore {
    void munch(Vegetable v);
};

interface Carnivore {
    void devour(Prey p);
}

interface AllEater : public Herbivore, Carnivore { };

class Fox implements AllEater {
   ... 
};

class Bear implements AllEater {
   ...
};

在此示例中,Fox和Bear无法共享其接口方法munchdevour的公共基础实现。

如果基本实现看起来像这样,我们可能希望将它们用于FoxBear

class ForestHerbivore implements Herbivore
    void munch(Vegetable v) { ... }
};

class ForestCarnivore implements Carnivore
    void devour(Prey p) { ... }
};

但我们不能继承这两者。基本实现需要是类中的成员变量,定义的方法可以转发给它。即:

class Fox implements AllEater {
    private ForestHerbivore m_herbivore;
    private ForestCarnivore m_carnivore;

    void munch(Vegetable v) { m_herbivore.munch(v); }
    void devour(Prey p) { m_carnivore.devour(p); }
}

如果接口增长(即超过5-10种方法......),这会变得难以处理。

更好的方法是将接口定义为接口的聚合:

interface AllEater {
    Herbivore asHerbivore();
    Carnivore asCarnivore();
}

这意味着FoxBear只需要实现这两个方法,接口和基类可以独立于与实现类相关的聚合AllEater接口增长。 / p>

如果它适用于您的应用,则以这种方式减少耦合。

答案 12 :(得分:2)

如果实现接口本身,您实际上可以从多个具体类“继承”。 innerclasses帮助您实现这一目标:

interface IBird {
    public void layEgg();
}

interface IMammal {
    public void giveMilk();
}

class Bird implements IBird{
    public void layEgg() {
        System.out.println("Laying eggs...");
    }
}

class Mammal implements IMammal {
    public void giveMilk() {
        System.out.println("Giving milk...");
    }
}

class Platypus implements IMammal, IBird {

    private class LayingEggAnimal extends Bird {}
    private class GivingMilkAnimal extends Mammal {}

    private LayingEggAnimal layingEggAnimal = new LayingEggAnimal();

    private GivingMilkAnimal givingMilkAnimal = new GivingMilkAnimal();

    @Override
    public void layEgg() {
        layingEggAnimal.layEgg();
    }

    @Override
    public void giveMilk() {
        givingMilkAnimal.giveMilk();
    }

}

interface IBird { public void layEgg(); } interface IMammal { public void giveMilk(); } class Bird implements IBird{ public void layEgg() { System.out.println("Laying eggs..."); } } class Mammal implements IMammal { public void giveMilk() { System.out.println("Giving milk..."); } } class Platypus implements IMammal, IBird { private class LayingEggAnimal extends Bird {} private class GivingMilkAnimal extends Mammal {} private LayingEggAnimal layingEggAnimal = new LayingEggAnimal(); private GivingMilkAnimal givingMilkAnimal = new GivingMilkAnimal(); @Override public void layEgg() { layingEggAnimal.layEgg(); } @Override public void giveMilk() { givingMilkAnimal.giveMilk(); } }

答案 13 :(得分:2)

说接口'模拟'多重继承是不公平的。

当然,您的类型可以实现多个接口,并以多态方式执行多种不同类型。但是,您显然不会在此安排下继承行为或实现。

一般来看你认为可能需要多重继承的构图。

OR实现多重继承的潜在解决方案就像Mixin接口 - http://csis.pace.edu/~bergin/patterns/multipleinheritance.html。小心使用!

答案 14 :(得分:1)

如果在对象模型中有意义,您当然可以从一个类继承并实现一个或多个接口。

答案 15 :(得分:1)

Java中没有真正的多重继承模拟。

人们有时会说你可以使用Interfaces来模拟多重继承,因为你可以为每个类实现多个接口,然后在你的类中使用组合(而不是继承)来实现你尝试的多个类的行为继承从开始。

答案 16 :(得分:1)

在某些情况下,多继承变得非常方便,并且在不编写更多代码的情况下很难用接口替换。例如,有些Android应用程序使用从Activity派生的类和同一应用程序中FragmentActivity的其他应用程序。如果您想要在公共类中共享特定功能,则必须使用Java重复代码,而不是让Activity和FragmentsActivity的子类派生自同一个SharedFeature类。 Java中泛型的不良实现也无济于事,因为编写以下内容是非法的:

public class SharedFeature<T> extends <T extends Activity>

...
...

答案 17 :(得分:1)

java中不支持多重继承。

这个使用接口支持多重继承的故事是我们开发人员编写的。接口比具体类提供灵活性,我们可以选择使用单个类实现多个接口。通过协议,我们正在坚持创建一个类的两个蓝图。

这是试图接近多重继承。我们所做的是实现多个接口,这里我们不扩展(继承)任何东西。实现类是要添加属性和行为的类。它没有从父类中获得实现。我只想说,java中没有对多重继承的支持。

答案 18 :(得分:1)

我不认为他们这样做。

继承特别是实现之间面向实现的关系。接口根本不提供任何实现信息,而是定义类型。要进行继承,您需要专门从父类继承一些行为或属性。

我相信这里有一个问题,特别是关于接口和多重继承的作用,但我现在找不到它......

答案 19 :(得分:1)

不,Java不支持多重继承。 既不使用类也不使用接口。有关详细信息,请参阅此链接 https://devsuyed.wordpress.com/2016/07/21/does-java-support-multiple-inheritance

答案 20 :(得分:1)

我还必须说Java不支持多重继承。

您必须区分Java中extendsimplements关键字之间的含义。如果我们使用extends,我们实际上是在该关键字之后继承该类。但是,为了使一切变得简单,我们不能多次使用extends。但是您可以根据需要实现任意数量的接口。

如果你实现了一个接口,那么你就不会错过每个接口中所有方法的实现(例外:Java 8中引入的接口方法的默认实现)所以,你现在已经充分意识到你刚刚上课的东西发生了什么。

为什么Java实际上不允许多重继承,多重继承会使代码变得有些复杂。有时,由于具有相同的签名,两种父类方法可能会发生冲突。但如果您被迫手动实施所有方法,您将完全了解正在进行的操作,如上所述。它使您的代码更易于理解。

如果您需要有关Java接口的更多信息,请查看本文http://www.geek-programmer.com/introduction-to-java-interfaces/

答案 21 :(得分:1)

两个Java类之间不能直接进行多重继承。在这种情况下,java建议使用接口来声明接口内的方法,并使用Child类实现方法。

interface ParentOne{
   public String parentOneFunction();
}

interface ParentTwo{
    public String parentTwoFunction();
}

class Child implements ParentOne,ParentTwo{

   @Override
    public String parentOneFunction() {
        return "Parent One Finction";
    }

    @Override
    public String parentTwoFunction() {
        return "Parent Two Function";
    }

    public String childFunction(){
       return  "Child Function";
    }
}
public class MultipleInheritanceClass {
    public static void main(String[] args) {
        Child ch = new Child();
        System.out.println(ch.parentOneFunction());
        System.out.println(ch.parentTwoFunction());
        System.out.println(ch.childFunction());
    }
}