Java多重继承

Java多重继承,java,oop,multiple-inheritance,diamond-problem,multiple-interface-implem,Java,Oop,Multiple Inheritance,Diamond Problem,Multiple Interface Implem,为了充分理解如何解决Java的多重继承问题,我有一个经典问题需要澄清 假设我有类Animal这有子类Bird和Horse,我需要创建一个类Pegasus,它从Bird和Horse扩展而来,因为Pegasus既是鸟又是马 我认为这是典型的钻石问题。据我所知,解决这个问题的经典方法是使动物、鸟和马类接口,并从它们实现飞马 我想知道是否还有其他方法可以解决这个问题,我仍然可以为鸟和马创建对象。如果有一种方法也能创造动物,那将是很好的,但这不是必需的。你可以为动物类(生物学意义上的类)创建接口,例如为马

为了充分理解如何解决Java的多重继承问题,我有一个经典问题需要澄清

假设我有类
Animal
这有子类
Bird
Horse
,我需要创建一个类
Pegasus
,它从
Bird
Horse
扩展而来,因为
Pegasus
既是鸟又是马

我认为这是典型的钻石问题。据我所知,解决这个问题的经典方法是使
动物
类接口,并从它们实现
飞马


我想知道是否还有其他方法可以解决这个问题,我仍然可以为鸟和马创建对象。如果有一种方法也能创造动物,那将是很好的,但这不是必需的。

你可以为动物类(生物学意义上的类)创建接口,例如为马创建
公共接口马类
,为鸟创建
公共接口鸟类
(我不是生物学家,所以术语可能是错误的)

然后您仍然可以创建一个

public class Bird implements Avialae {
}

而且

public class Pegasus implements Avialae, Equidae {}

从评论中添加: 为了减少重复代码,您可以创建一个抽象类,其中包含要实现的动物的大部分公共代码

public abstract class AbstractHorse implements Equidae {}

public class Horse extends AbstractHorse {}

public class Pegasus extends AbstractHorse implements Avialae {}

更新 我想再补充一个细节。这是OP已经知道的


然而,我想强调的是,我建议绕过接口的“多重继承”问题,我不建议使用已经表示一个具体类型(如Bird)而更多表示一种行为的接口(其他接口指duck类型,这也很好,但我的意思是:birds的生物类Avialae)。我也不建议使用以大写字母“I”开头的接口名称,例如
IBird
,这并不能说明为什么需要接口。这就是问题的不同之处:使用接口构造继承层次结构,在有用时使用抽象类,在需要时实现具体类,并在适当时使用委托。

从技术上讲,一次只能扩展一个类并实现多个接口,但是,当我着手研究软件工程时,我宁愿提出一个特定于问题的解决方案,而不是通常可以回答的。顺便说一句,这是一个很好的OO实践,不扩展具体类/只扩展抽象类以防止不必要的继承行为-没有“动物”这样的东西,也不使用动物对象,只使用具体的动物。

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

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

public class Main {
    private Component1 component1 = new Component1();    
    private Component2 component2 = new Component2();
}
如果要公开某些方法,请定义它们并让它们将调用委托给相应的控制器

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

class Main implements Interface1, Interface2
因此,您可以在上下文允许的情况下互换使用对象


因此,在我看来,你不能陷入钻石问题。

嗯,你的类可以是其他1个类的子类,但是,你仍然可以根据自己的意愿实现任意多的接口

帕伽索斯实际上是一匹马(这是马的特例),它能飞(这是这匹特殊马的“技能”)。从另一方面来说,你可以说,飞马是一种能走路的鸟,它有四条腿——这一切都取决于你如何更容易地编写代码

就像你的情况一样,你可以说:

abstract class Animal {
   private Integer hp = 0; 
   public void eat() { 
      hp++; 
   }
}
interface AirCompatible { 
   public void fly(); 
}
class Bird extends Animal implements AirCompatible { 
   @Override
   public void fly() {  
       //Do something useful
   }
} 
class Horse extends Animal {
   @Override
   public void eat() { 
      hp+=2; 
   }

}
class Pegasus extends Horse implements AirCompatible {
   //now every time when your Pegasus eats, will receive +2 hp  
   @Override
   public void fly() {  
       //Do something useful
   }
}

您可以拥有一个接口层次结构,然后从所选接口扩展类:

public interface IAnimal {
}

public interface IBird implements IAnimal {
}

public  interface IHorse implements IAnimal {
}

public interface IPegasus implements IBird,IHorse{
}
然后根据需要通过扩展特定接口来定义类:

public class Bird implements IBird {
}

public class Horse implements IHorse{
}

public class Pegasus implements IPegasus {
}
我有一个愚蠢的想法:

public class Pegasus {
    private Horse horseFeatures; 
    private Bird birdFeatures; 

   public Pegasus(Horse horse, Bird bird) {
     this.horseFeatures = horse;
     this.birdFeatures = bird;
   }

  public void jump() {
    horseFeatures.jump();
  }

  public void fly() {
    birdFeatures.fly();
  }
}

我可以提出一个新的概念吗

最有可能的是,你会让飞马扩展鸟和马的界面,但鸭子类型实际上表明你应该继承行为。正如评论中所说,飞马座不是鸟,但它能飞。所以你的飞马座应该继承一个
可飞的
-接口,比如说一个
可飞的
-接口


这一概念被应用于实际工作中。给出的示例实际上向您展示了鸭子是如何继承
flybehavior
quackbehavior
的,但仍然可能有鸭子,例如
RubberDuck
,它们不能飞。他们还可以让
鸭子
扩展一个
类,但是他们会放弃一些灵活性,因为每只
鸭子
都能飞,即使是可怜的
橡胶狗

我想这在很大程度上取决于你的需要,以及你的动物类在你的代码中的使用方式

如果您希望能够在Pegasus类中使用Horse和Bird实现的方法和功能,那么您可以将Pegasus实现为鸟和马的一种组合:

public class Animals {

    public interface Animal{
        public int getNumberOfLegs();
        public boolean canFly();
        public boolean canBeRidden();
    }

    public interface Bird extends Animal{
        public void doSomeBirdThing();
    }
    public interface Horse extends Animal{
        public void doSomeHorseThing();
    }
    public interface Pegasus extends Bird,Horse{

    }

    public abstract class AnimalImpl implements Animal{
        private final int numberOfLegs;

        public AnimalImpl(int numberOfLegs) {
            super();
            this.numberOfLegs = numberOfLegs;
        }

        @Override
        public int getNumberOfLegs() {
            return numberOfLegs;
        }
    }

    public class BirdImpl extends AnimalImpl implements Bird{

        public BirdImpl() {
            super(2);
        }

        @Override
        public boolean canFly() {
            return true;
        }

        @Override
        public boolean canBeRidden() {
            return false;
        }

        @Override
        public void doSomeBirdThing() {
            System.out.println("doing some bird thing...");
        }

    }

    public class HorseImpl extends AnimalImpl implements Horse{

        public HorseImpl() {
            super(4);
        }

        @Override
        public boolean canFly() {
            return false;
        }

        @Override
        public boolean canBeRidden() {
            return true;
        }

        @Override
        public void doSomeHorseThing() {
            System.out.println("doing some horse thing...");
        }

    }

    public class PegasusImpl implements Pegasus{

        private final Horse horse = new HorseImpl();
        private final Bird bird = new BirdImpl();


        @Override
        public void doSomeBirdThing() {
            bird.doSomeBirdThing();
        }

        @Override
        public int getNumberOfLegs() {
            return horse.getNumberOfLegs();
        }

        @Override
        public void doSomeHorseThing() {
            horse.doSomeHorseThing();
        }


        @Override
        public boolean canFly() {
            return true;
        }

        @Override
        public boolean canBeRidden() {
            return true;
        }
    }
}
另一种可能是使用一种方法而不是遗传来定义你的动物。当然,这意味着您将不会有单独的Java动物类,而是只由它们的组件定义

实体组件系统方法的一些伪代码可能如下所示:

public void createHorse(Entity entity){
    entity.setComponent(NUMER_OF_LEGS, 4);
    entity.setComponent(CAN_FLY, false);
    entity.setComponent(CAN_BE_RIDDEN, true);
    entity.setComponent(SOME_HORSE_FUNCTIONALITY, new HorseFunction());
}

public void createBird(Entity entity){
    entity.setComponent(NUMER_OF_LEGS, 2);
    entity.setComponent(CAN_FLY, true);
    entity.setComponent(CAN_BE_RIDDEN, false);
    entity.setComponent(SOME_BIRD_FUNCTIONALITY, new BirdFunction());
}

public void createPegasus(Entity entity){
    createHorse(entity);
    createBird(entity);
    entity.setComponent(CAN_BE_RIDDEN, true);
}
 interface IFlier {
     Flier getFlier();
 }
 class Bird extends Animal implements IFlier {
      Flier flier = new Flier();
      public Flier getFlier() { return flier; }
 }

将对象组合在一起有两种基本方法:

  • 第一个是继承。正如您已经确定的那样,继承的局限性意味着您不能在这里做您需要的事情
  • 第二种是组合。由于继承失败,您需要使用组合
这样做的方式是,你有一个动物对象。然后在该对象中添加更多对象
 class Bird extends Animal implements IFlier {
      Flier flier = new Flier();
      public Flier getFlier() { return flier; }
 }
[abstract] class <clsname> implements <intf 1>,<intf 2>.........<intf n>
{
    variable declaration;
    method definition or declaration;
};
interface <intf 0 name> extends <intf 1>,<intf 2>.........<intf n>
{     
    variable declaration cum initialization;
    method declaration;
};
[abstract] class <derived class name> extends <base class name> implements <intf 1>,<intf 2>.........<intf n>
{
  variable declaration;
  method definition or declaration;
};
class A {  
    void msg() {
        System.out.println("From A");
    }  
}

class B {  
    void msg() {
        System.out.println("From B");
    }  
}

class C extends A,B { // suppose if this was possible
    public static void main(String[] args) {  
        C obj = new C();  
        obj.msg(); // which msg() method would be invoked?  
    }
}