【问题标题】:What can polymorphism do that inheritance can't? [duplicate]多态性能做什么继承不能? [复制]
【发布时间】:2017-02-06 05:45:49
【问题描述】:

假设我们有一个类 Animal 扩展到其他三个类:DogCatBird

这个动物类有一个talk()move() 函数。 talk 函数输出“Animal talk”,move 函数输出“Animal Moving”。

对于狗来说,这是“狗移动”和“狗吃”。对于CatBird 类,这种差异与“猫移动”等类似。

现在,由于多态性,如果我这样做了

Animal charlietheBird = new Bird()

然后调用

charlietheBird.talk()

它会输出

鸟语花香

因为输出是在运行时确定的,因为编译器知道 charlie 是 Bird 类的 Animal 类型。

但是!!

我可以做到

Bird charlietheBird = new Bird();

然后调用charlietheBird.poop(); 将给出相同的输出,因为 方法会被覆盖。

【问题讨论】:

  • 多态是一个概念。继承(连同虚函数)是实现该概念的技术手段。所以标题中的问题有点无关紧要。
  • 你基本上是对的。当您的程序中有 234 只猫、一只狗和 5000 只鸟时,如果您有时可能希望其中一只说话或移动而不关心您正在处理的动物的确切类型,那么将某些鸟声明为 Animal 的优势就来了。
  • @silenceislife 我相信你的问题大致可以转化为如果我们有继承,为什么我们需要多态。有关 Polymorphism 可以做什么的详细说明,请参阅我的回答。
  • @barakmanos 继承不是和多态一样也是一个概念吗?或者更确切地说,在技术上是否实现了多态性?多态性和继承都需要以特定方式构造代码,对吗?

标签: java oop inheritance design-patterns polymorphism


【解决方案1】:

多态性可以做哪些继承不能做的事情?

多态性的真正优势可以在运行时而不是编译时看到。多态性允许您将一种实现替换为另一种实现,而无需更改使用它的代码。让我们以Animal 层次结构为例。假设您有一个 Vet 知道如何对任何动物进行健康检查(是的,他是个超级兽医)。

class Vet {
   private Animal animal; 
   public Vet(Animal animal) {
      this.animal = animal;
   }

   public void perfromCheckup() {
      animal.talk();
      animal.poop();
   }
} 

你现在可以说:

Vet vetWithBird = new Vet(new Bird());
Vet vetWithDog =  new Vet(new Dog());
vetWithBird.performCheckup();
vetWithDog.performCheckup();

请注意如何告诉VetBirdDog 或任何其他动物进行检查,而无需更改Vet 类。在运行时,Dog 在进行检查时会吠叫,Bird 在进行检查时会发推文。想象一下,如果Vet 有一个Bird 引用而不是Animal

class Vet {
   private Bird bird; 
   public Vet(Bird bird) {
      this.bird = bird;
   }

   public void perfromCheckup() {
      bird.talk();
      bird.poop();
   }
} 

可怜的Vet 现在只能与Bird 合作。告诉您的VetDog 合作,他会立即拒绝。

Vet vetWithBird = new Vet(new Bird()); //Works fine. Vet likes birds.
Vet vet = new Vet(new Dog())// compilation error. Sorry I don't like dogs.

总之,多态性 允许您替换使用超类引用的子类实例。 继承允许您从父类继承代码并可能在子类中重新定义该行为,以便您的代码可以在运行时通过多态性

利用它

【讨论】:

    【解决方案2】:

    继承支持多态,但多态不依赖于继承。

    您举例说明了如何通过继承实现多态性。

    但你可以换个角度看:

    移动的概念有一个接口

    interface Movable{
      void move();
    }
    

    动物可以实现这个接口:

    class Dog implements Movable {
      @Override
      public void move(){
        // move the animal
      }
    }
    

    但有些真菌也可以移动:

    class SlimeMold implements Movable {
      @Override
      public void move(){
        // move the animal
      }
    }
    

    在这两者之间几乎找不到可以通过继承来表达的“是”关系,但是当两者都实现相同的接口时,我们仍然可以对它们应用多态:

    Collection<Movable> movables = new HashSet<>();
    movables.add(new Dog());
    movables.add(new SlimeMold());
    for(Movable movable : movables)
       movable.move();
    

    【讨论】:

    • 一个Dog 是一个Movable 对象。
    • @CKing maye 我最好将该界面称为Mobile
    • 这不是我要说的重点。你的Dog 仍然是Mobile,你仍然可以说DogMobile 动物。运行时多态性(在您的回答中)总是依赖于某种继承。我不同意以下行:多态不依赖于继承
    【解决方案3】:

    继承是指 Java 编程的一项功能,它允许您创建从其他类派生的类。基于另一个类的类继承另一个类。被继承的类是父类、基类或超类。

    多态性是指编程语言根据对象的数据类型或类以不同方式处理对象的能力。更具体地说,它是为派生类重新定义方法的能力。

    You can find more information in Objects and Java by Bill Venners Chapter 7: Polymorphism and Interfaces

    【讨论】:

    • 我不相信 OP 要求两者之间的区别。问题是多态性可以做哪些继承不能做的事情?。这大致转化为向我展示一个我需要多态性而继承不够用的用例
    • 此外,这个答案的措辞与this 完全相同。现在我很好奇这是否是某些出版物/书籍中的既定术语?
    • 这是一个有区别的通用定义。我添加了更多信息+一个很好的参考!你的回答足够好,有一个完整的总结:-)
    猜你喜欢
    • 2017-07-13
    • 2015-01-19
    • 2011-03-25
    • 2010-10-20
    • 2010-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多