繁体   English   中英

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

[英]How do Java Interfaces simulate multiple inheritance?

我正在阅读“Java 教程”(第二次)。 我刚刚(再次)浏览了接口部分,但仍然不明白 Java 接口如何模拟多重继承。 有没有比书上更清楚的解释?

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

卡车有一个 driveTo() 方法,而厨房有一个 Cook() 方法。

现在假设泡利决定从一辆送货卡车的后面卖比萨饼。 他想要一个他可以用 driveTo() 和 cook() 的东西。

在 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);

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

(更新:随着默认方法接口的出现,现在也可以提供一些可以被继承的行为)

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

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

下面介绍一种在java中通过接口实现多重继承的方法。

要达到什么目的?
class A extends 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();
}

鉴于下面的两个接口......

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");
  }
}

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

接口不模拟多重继承。 Java 创建者认为多重继承是错误的,所以 Java 中没有这种东西。

如果您想将两个类的功能合二为一 - 使用对象组合。 IE

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

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

这里接口可能会派上用场 - 如果Component1实现接口Interface1并且Component2实现Interface2 ,您可以定义

class Main implements Interface1, Interface2

这样您就可以在上下文允许的情况下互换使用对象。

你知道吗,从一个 JavaScript 开发者的角度试图理解这些东西到底发生了什么,我想指出一些事情,如果我是,请有人告诉我我在这里遗漏了什么偏离目标。

接口真的很简单。 愚蠢的,疯狂的简单。 它们和人们最初想象的一样愚蠢,疯狂地简单,这就是为什么在这个确切的主题上有这么多重复的问题,因为使用它们的一个原因已经被人们试图制造比它们更多的人弄得不清楚。在我接触过的每个 Java 服务器端代码库中都被广泛滥用。

那么,为什么要使用它们呢? 大多数时候你不会。 您当然不想像许多人认为的那样一直使用它们。 但在我说你什么时候会这样做之前,让我们先谈谈它们不是什么。

接口不是:

  • 以任何方式解决 Java 缺乏的任何类型的继承机制。 它们与继承无关,它们从来没有做过,也绝不会模拟任何类似继承的东西。
  • 一定是对你写的东西有帮助的东西,就像它可以帮助另一个人写一些与你的东西交互的东西一样。

它们确实和您乍一看时认为的一样简单。 人们总是愚蠢地滥用,所以很难理解重点是什么。 这只是验证/测试。 一旦你编写了一些符合接口并且可以工作的东西,删除“实现”代码不会破坏任何东西。

但是如果你正确使用接口,你不会想要删除它,因为有了它,下一个开发人员就有了一个工具来为另一组数据库或 Web 服务编写访问层,他们希望你的应用程序的其余部分继续使用是因为他们知道他们的课程会失败,直到他们获得 100% 完全符合预期的界面。 所有接口所做的都是验证您的类并确定您实际上已经按照您的承诺实现了一个接口。 而已。

它们也是便携式的。 通过公开您的接口定义,您可以为想要使用您未公开代码的人提供一组方法,以便他们的对象正确使用它。 他们不必实现接口。 他们可以把它们记在一张记事本上,然后仔细检查。 但是有了这个接口,你就更有保证了,除非它有一个合适的接口版本,否则什么都不会尝试工作。

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

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

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

这不是多重继承的模拟。 在 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,它看起来像一个多继承,但这不是因为你没有继承任何东西,你只是重写了接口提供的公共方法。

你需要准确:

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(); }
}

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

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

如果它们自己实现接口,您实际上可以从多个具体类“继承”。 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(); } }

我想指出一些在背后咬我的东西,来自 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) { ... }
};

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

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接口增长。

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

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

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

通常查看您认为可能需要多重继承的组合。

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

他们没有。

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

你通过实现一个接口继承了什么? 巴克斯! 所以在我看来,不要在同一句话中使用接口和继承这两个词。 正如 Michael Borgwardt 所说,接口不是一个定义,而是一个方面。

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

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

...
...

java中不支持多重继承。

这个使用接口支持多重继承的故事是我们开发人员编造的。 接口比具体类更灵活,我们可以选择使用单个类实现多个接口。 根据协议,我们遵循两个蓝图来创建一个类。

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

我不认为他们这样做。

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

我相信这里某个地方有一个关于接口和多重继承的作用的问题,但我现在找不到了......

在 Java 中确实没有模拟多重继承。

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

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

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

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

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

如果您实现了一个接口,那么您将错过每个接口中所有方法的实现的可能性为零(例外:Java 8 中引入的接口方法的默认实现)因此,您现在完全了解事物发生的情况你已经嵌入到你的新课程中。

Java 不允许多重继承的原因实际上是,多重继承使代码有些复杂。 有时,由于具有相同的签名,父类的两个方法可能会发生冲突。 但是,如果您被迫手动实现所有方法,您将完全了解正在发生的事情,正如我上面提到的。 它使您的代码更容易理解。

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

两个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());
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM